在4S店实习,市场部经理让我写一个小程序自动爬取汽车之家网站上自家品牌的促销文章,因为区域经理需要各店上报在网站上每一家经销商文章的露出频率,于是就自己尝试写一个爬虫,正好当入门了。
(1)配置环境
电脑上已经安装了Anaconda3 4.2.0,集成了python3.5.2,以及pandas、numpy等数据处理与科学计算模块。
在命令行中用 pip install 安装bs4
如
pip install bs4
(2)思路
http://www.autohome.com.cn/chengdu/cheshi/
对象是上面这个网站,打开后可以看到有不同品牌的促销文章,进入其中一个链接,http://www.autohome.com.cn/dealer/201706/118192201.html
翻到最底下,可以看到“商家名称”一栏后有对应的商家名称“四川知行荣业汽车销售服务有限公司”,要找的就是它。
每一个促销信息的网页结构都是一致的。这就有规律可寻。
在Firefox浏览器中,对应区域——右键——查看元素,定位到某个标题的位置
在下方的查看器中,根据结构找到这个促销信息区域的结构。
能够看到是
采用了BeautifulSoup库,是一个可以从HTML或XML文件中提取数据的Python库。具体文档介绍:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
在导入对应的库后,首先发送网页请求并解析
html = urllib.request.urlopen("http://www.autohome.com.cn/chengdu/cheshi/") #发送打开网页请求
soup = BeautifulSoup(html, "lxml") #解析网页
先上这部分代码:
for i in soup.body.find_all("div",attrs={"class":"news_area"}): #定位到优惠促销区域
k=0 #k用于统计促销信息数量
df = pd.DataFrame(np.empty((len(i.find_all('a')),2))) #df用于存储所有信息
for j in i.find_all('a'):
result = j.get_text()
result = "".join(result) #将列表转化为字符串
df.ix[k,0] = result #第k行第一列为标题
df.ix[k,1] = j['href'] #第k行第二列为对应网址
k += 1
df.columns = ['标题','链接'] #结果表格列名
df.to_csv('D:\\所有优惠信息.csv',index = False) #输出总结果
采用soup.find_all 函数(用法见文档说明)
soup.body.find_all("div",attrs={"class":"news_area"})
如果在body标签内有多条'div'标签,用上述的函数只会输出第一条,但是如果写一个循环,就可以全部找出来,所以在这里要写一个循环。
对找出来的子结构再进行分析,发现'a' 标签代表一条促销信息,如
众泰SR9目前价格稳定 售价10.88万元起,
购讴歌MDX目前暂无优惠,
高尔夫目前售价12.89万起,”
对于优惠信息,创建一个pandas 库中的 DataFrame 来存储每一条记录,第一列为标题,第二列为对应的链接。由于DataFrame需要事先确定行数,实现计算好条目数。
(len(i.find_all('a'))
同上,.find_all()函数需写一个循环遍历所有结果。
用.get_text()来获得纯文本作为标题,注意需要将获得的文本转化为字符串。参考上面的信息,网址在'href'标签里,直接用 j['href'] 提取。至此,标题、网址都已得到。
在循环中引入k计数,逐行向下记录。
在df 表格记录完成后,重命名列名,然后保存到csv格式表格中,方便查看。
接下来就是在df表格中寻找需要品牌的关键字,以“荣威”为例。
基本思路就是在df的第一列中逐行向下检索,看有没有'荣威'字符,如果有,打开对应行第二列的网址,在进行解析,定位到经销商处,提取出经销商名称。
直接上代码。
data = pd.DataFrame(np.empty((1,3))) #data用于存储荣威经销商
for x in range(len(df)):
if '荣威' in df.ix[x,0]: #查找优惠标题中是否有荣威
URL = urllib.request.urlopen(df.ix[x,1]) #打开有荣威字段的网页
SOUP = BeautifulSoup(URL, "lxml") #解析网页
for i in SOUP.find_all("div",attrs={"class":"seller-add"}): #定位到经销商信息
for j in i.find_all('a'):
tempdata = pd.DataFrame(np.empty((1,3))) #tempdata变量存储每条荣威优惠信息
tempdata.ix[0,0] = df.ix[x,0] #第一列为标题
tempdata.ix[0,1] = df.ix[x,1] #第二列为网址
tempdata.ix[0,2] = j.get_text() #第三列为经销商
data = data.append(tempdata) #将tempdata的记录合并到data中去
data.index = range(len(data)) #统计data共有几行
data = data.drop(0) #去掉空白的第一行
data.columns = ['标题','网址','经销商'] #改变列名
data.to_csv('D:\\荣威经销商优惠.csv',index = False) #输出最后结果
最后输出两个csv文件,分别是当前所有经销商的信息,以及只含关键品牌的信息。
完整代码如下:
# -*- coding: utf-8 -*-
'''
Created on Wed Jun 7 20:07:12 2017
@author: gusiev
平台:anaconda 64位版 python 3.5
作用:打开汽车之家特定网页,提取网页中也定的优惠信息文章。
在优惠信息文章中找到‘荣威’关键字的文章,在对应的文章内找到
经销商的名称。可用于统计经销商的促销文章在网站的推送频次。
'''
import urllib
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
import os
os.chdir('D:\\') #变更工作目录
html = urllib.request.urlopen("http://www.autohome.com.cn/chengdu/cheshi/") #发送打开网页请求
soup = BeautifulSoup(html, "lxml") #解析网页
for i in soup.body.find_all("div",attrs={"class":"news_area"}): #定位到优惠促销区域
k=0 #k用于统计促销信息数量
df = pd.DataFrame(np.empty((len(i.find_all('a')),2))) #df用于存储所有信息
for j in i.find_all('a'):
result = j.get_text().split(',') #优惠信息分隔
result2 = "".join(result) #将列表转化为字符串
df.ix[k,0] = result2 #第k行第一列为标题
df.ix[k,1] = j['href'] #第k行第二列为对应网址
k += 1
df.columns = ['标题','链接'] #结果表格列名
df.to_csv('D:\\所有优惠信息.csv',index = False) #输出总结果
data = pd.DataFrame(np.empty((1,3))) #data用于存储荣威经销商
for x in range(len(df)):
if '荣威' in df.ix[x,0]: #查找优惠标题中是否有荣威
URL = urllib.request.urlopen(df.ix[x,1]) #打开有荣威字段的网页
SOUP = BeautifulSoup(URL, "lxml") #解析网页
for i in SOUP.find_all("div",attrs={"class":"seller-add"}): #定位到经销商信息
for j in i.find_all('a'):
tempdata = pd.DataFrame(np.empty((1,3))) #tempdata变量存储每条荣威优惠信息
tempdata.ix[0,0] = df.ix[x,0] #第一列为标题
tempdata.ix[0,1] = df.ix[x,1] #第二列为网址
tempdata.ix[0,2] = j.get_text() #第三列为经销商
data = data.append(tempdata) #将tempdata的记录合并到data中去
data.index = range(len(data)) #统计data共有几行
data = data.drop(0) #去掉空白的第一行
data.columns = ['标题','网址','经销商'] #改变列名
data.to_csv('D:\\荣威经销商优惠.csv',index = False) #输出最后结果
在第一部分的基础上有稍微增加了一个对关键字经销商信息的网页进行截屏的功能,采用selenium 库完成,可调用Firefox浏览器自动打开对应促销网页并截图保存到本地。
import urllib
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
import os
from selenium import webdriver
import time
os.chdir('D:\\code\\roewe\\') #变更工作目录
def capture(url, save_fn="capture.png"):
browser = webdriver.Firefox() # Get local session of firefox
browser.maximize_window()
browser.get(url) # Load page
browser.save_screenshot(save_fn)
browser.close()
html = urllib.request.urlopen("http://www.autohome.com.cn/chengdu/cheshi/") #发送打开网页请求
soup = BeautifulSoup(html, "lxml") #解析网页
for i in soup.body.find_all("div",attrs={"class":"news_area"}): #定位到优惠促销区域
k=0 #k用于统计促销信息数量
df = pd.DataFrame(np.zeros((len(i.find_all('a')),2))) #df用于存储所有信息
for j in i.find_all('a'):
result = j.get_text().split(',')
result2 = "".join(result) #将列表转化为字符串
df.ix[k,0] = result2 #标题
df.ix[k,1] = j['href'] #对应网址
k += 1
df.columns = ['标题','链接'] #结果表格列名
df.to_csv('所有优惠信息.csv',index = False)
data = pd.DataFrame(np.empty((1,3))) #data用于存储荣威经销商
for x in range(len(df)):
if '荣威' in df.ix[x,0]:
URL = urllib.request.urlopen(df.ix[x,1])
capture(df.ix[x,1])
SOUP = BeautifulSoup(URL, "lxml")
for i in SOUP.find_all("div",attrs={"class":"seller-add"}): #定位到经销商信息
for j in i.find_all('a'):
tempdata = pd.DataFrame(np.empty((1,3)))
tempdata.ix[0,0] = df.ix[x,0]
tempdata.ix[0,1] = df.ix[x,1]
tempdata.ix[0,2] = j.get_text()
data = data.append(tempdata)
data.index = range(len(data))
data = data.drop(0)
data.columns = ['标题','网址','经销商']
data.to_csv('荣威经销商优惠.csv',index = False)
表格文件
截图
这是本人第一篇技术博客,由于也是初学者,所以代码难免有疏漏,望包涵,个人检测可运行。