使⽤浏览器模拟器获取动态⽹站数据
虽然python中的urllib模块中有相应的函数来处理这类动态页⾯,但过于⿇烦,这⾥我们选⽤⼀个简便的⽅法,使⽤浏览器模拟器。
在⽹上下载⽆界⾯浏览器PhantomJS,利⽤pip下载模块selenium(这⾥推荐版本2.53.6,⽽不是最新版本,最新版本的selenium不⽀持PhantomJS),建⽴main.py,编写涉及和使⽤到的类与⽅法,代码如下:
1from selenium import webdriver
2from selenium.webdriver.support.select import Select
3from myLog import MyLog
4import time
python在线模拟器5import xlwt
6
7class Item(object):
8 shengfen = None #省份
9 xiangmubianhao = None #项⽬编号
10 xiangmumingcheng = None #项⽬名称
11 xiangmuneihan = None #项⽬内涵
12 chuwaineirong = None #除外内容
13 danwei = None #单位
14 jiage = None #价格
15 shuoming = None #说明
16 wenhao = None #⽂号
17 zhixingriqi = None #执⾏⽇期
18
19class Get_medicalprice(object):
20def__init__(self):
21 self.hospitalPriceurl = 'jgw/front/cn/hospitalPrice'
22 self.log = MyLog()
23 self.filename = u'医疗服务价格.xls'.encode('GBK')
24 self.namelist = ame('')
25 self.hospitallist = hospitalprice(self.hospitalPriceurl,self.namelist)
26 self.savefiletoxls(self.filename,self.hospitallist)
27
28def getname(self,filename):
29 namelist = []
30 with open(filename,'r') as fp:
31 s = fp.read()
32for name in s.split():
33 namelist.append(name)
34 self.log.info('open namelist success , the length of list is %d' % len(namelist))
35return namelist
36
37def gethospitalprice(self,url,namelist):
37def gethospitalprice(self,url,namelist):
38 list_hospitalprice = []
39return list_hospitalprice
40
41def savefiletoxls(self,filename,hospitallist):
42 self.log.info('save data to excel')
43 book = xlwt.Workbook(encoding = 'utf8',style_compression=0)
44 sheet = book.add_sheet(u'医疗服务项⽬收费')
45 sheet.write(0,0,u'省份'.encode('utf8'))
46 sheet.write(0,1,u'项⽬编号'.encode('utf8'))
47 sheet.write(0,2,u'项⽬名称'.encode('utf8'))
48 sheet.write(0,3,u'项⽬内涵'.encode('utf8'))
49 sheet.write(0,4,u'除外内容'.encode('utf8'))
50 sheet.write(0,5,u'单位'.encode('utf8'))
51 sheet.write(0,6,u'价格'.encode('utf8'))
52 sheet.write(0,7,u'说明'.encode('utf8'))
53 sheet.write(0,8,u'⽂号'.encode('utf8'))
54 sheet.write(0,9,u'执⾏⽇期'.encode('utf8'))
55for i in range(1,len(hospitallist)+1):
56 item = hospitallist[i-1]
57 sheet.write(i,0,item.shengfen)
58 sheet.write(i,1,item.xiangmubianhao)
59 sheet.write(i,2,item.xiangmumingcheng)
60 sheet.write(i,3,item.xiangmuneihan)
61 sheet.write(i,4,item.chuwaineirong)
62 sheet.write(i,5,item.danwei)
63 sheet.write(i,6,item.jiage)
64 sheet.write(i,7,item.shuoming)
65 sheet.write(i,8,item.wenhao)
66 sheet.write(i,9,item.zhixingriqi)
67 book.save(filename)
68 self.log.info('save excel success')
69
70
71if__name__ == '__main__':
72 Get_medicalprice()
其中,类Item定义了我们需要从⽹页获取到的所有信息;类Get_medicalprice为爬⾍主程序;⽅法__init__定义了整个爬⾍的⼯作流程;⽅法getname从“”中获取需要查的医疗服务项⽬名称,返回名称列表;⽅法gethospitalprice 为爬⾍的关键,负责根据getname返回的名称列表在页⾯中查对应的信息并保存;⽅法savefiletoxls负责将gethospitalprice获取到的所有信息保存到电⼦表中。
我们现在开始来补充⽅法gethospitalprice中的代码。
使⽤selenium模拟调⽤浏览器PhantomJS,⾸先⽤“#”注释掉__init__中
的“self.savefiletoxls(self.filename,self.hospitallist)”,出于测试⽬的,这⾥只让浏览器截图查看模拟效果⽽不进⼀步抓取数据。在gethospitalprice中增加代码如下:
1def gethospitalprice(self,url,namelist):
2 browser = webdriver.PhantomJS()
3 list_hospitalprice = []
4 (url)
5#browser.implicitly_wait(10)
6for name in namelist:
7 textelement = browser.find_element_by_id('projectname')
8 textelement.clear() #清除text中已输⼊的项⽬
9try:
10 textelement.send_keys(name.decode('GBK')) #text中填⼊项⽬名称
11except:
12 ('get data %s error ' % name)
13continue
14else:
15 self.log.info('get data %s \n' % name.decode('GBK'))
16 selectelement = browser.find_element_by_id('provName')
17 Select(selectelement).select_by_value(u'河南省') #使⽤select控件选择河南省
18 submitelement = browser.find_element_by_class_name('l-btn-left')
19 submitelement.click() #点击查询按钮
20 time.sleep(10)
21 _screenshot_as_file('%s.png' % name) #进⾏查询后让浏览器截图,以查看程序是否运⾏正常
在这⾥,模块selenium本⾝⾃带的implicitly_wait效果⽐time⾥的sleep要好,所以平时尽量优先使⽤implicitly_wait,⽽这⾥依旧使⽤time.sleep是为防⽌被服务器拦截⽽强制让程序降速。根据页⾯源代码,到相应控件的id,如这⾥
的“projectname”、“provName”,利⽤find_element_by_id来定位。其中⽤于选择省份的控件是个select,需要⽤到selenium.webdriver.support.select中的Select。通过send_keys来向“provName”的⽂本框控件中发送项⽬名称时,特别需要注意的是汉字编码,因为是在windows下创建的,编码⽤的是"GBK'',所以这⾥需要先⽤
decode("GBK")把项⽬名称进⾏反编码。
但有个问题是“查”按钮不好定位,没有明显的id和class。右键点击“查”按钮,选择“审查元素”,这⾥可以看到该控件的class为“l-btn-left”(虽然那个“清空”按钮的class也是“l-btn-left”,但并没太⼤的影响,“查”⽐“清空”位置靠前,find_element_by_class_name返回的是检索到的第⼀个符合条件的控件),利⽤
find_element_by_class_name('l-btn-left')来定位。
在最后增加⼀条语句 _screenshot_as_file('%s.png' % name) 来让浏览器⾃动截图并保存成“项⽬名
称.png”的图⽚,以便⽅便查看确定程序是否在正常运⾏。
点击run运⾏程序,在⽬录下随便打开⼀张png图⽚,如下图:
爬⾍程序已经成功选择了设定的“省份”,填⼊了读取到的项⽬名称,并成功点击了“查”按钮,⽽且成功地获取到了我们需要的信息。
好了,下⾯我们就开始和以前⼀样抓取页⾯上的信息。
查看页⾯源代码,可以看到存放数据的位置在标签tbody下,但tbody不唯⼀,⽽上层的标签table,class值
为“xxbTable”,通过搜索后发现是唯⼀的。所以这⾥我们先定位class值为“xxbTable”的标签table,随后再依次定位tbody,tr,td。
1 resultelement = browser.find_element_by_class_name('xxbTable')
2#
3 elements=resultelement.find_elements_by_xpath('./tbody[2]/tr/td')
4 item = Item()
5if len(elements)==0:
6 self.log.info('%s has no data' % name.decode('GBK'))
7else:
8 self.log.info('save data %s to list' % name.decode('GBK'))
9 item.shengfen = elements[1].text
10 item.xiangmubianhao = elements[2].text
11 item.xiangmumingcheng = elements[3].text
12 item.xiangmuneihan = elements[4].text
13 item.chuwaineirong = elements[5].text
14 item.danwei = elements[6].text
15 item.jiage = elements[7].text
16 item.shuoming = elements[8].text
17 item.wenhao = elements[9].text
18 item.zhixingriqi = elements[10].text
19 list_hospitalprice.append(item)
tbody不是唯⼀的,所以在确定需求的是哪⼀部分的时候,可以先⽤定位到tbody处,使⽤for循环打印下此处的⽂本,代码如下:
1 resultelement = browser.find_element_by_class_name('xxbTable')
2#
3 elements=resultelement.find_elements_by_xpath('./tbody')
4for i in elements:
运⾏结果如下:
tbody[0]为空,tbody[1]是列名,tbody[2]才是我们需要的数据。
最终运⾏后,⽣成的结果被⽅法savefiletoxls保存到电⼦表'医疗服务价格.xls'中
以下为“main.py”⽂件的完整代码:
1from selenium import webdriver
2from selenium.webdriver.support.select import Select
3from myLog import MyLog
4import time
5import xlwt
6
7class Item(object):
8 shengfen = None
9 xiangmubianhao = None
10 xiangmumingcheng = None
11 xiangmuneihan = None
12 chuwaineirong = None
13 danwei = None
14 jiage = None
15 shuoming = None
16 wenhao = None
17 zhixingriqi = None
18
19class Get_medicalprice(object):
20def__init__(self):
21 self.hospitalPriceurl = 'jgw/front/cn/hospitalPrice'
22 self.log = MyLog()
23 self.filename = u'医疗服务价格.xls'.encode('GBK')
24 self.namelist = ame('')
25 self.hospitallist = hospitalprice(self.hospitalPriceurl,self.namelist)
26 self.savefiletoxls(self.filename,self.hospitallist)
27
28def getname(self,filename):
29 namelist = []
30 with open(filename,'r') as fp:
31 s = fp.read()
32for name in s.split():
33 namelist.append(name)
34 self.log.info('open namelist success , the length of list is %d' % len(namelist))
35return namelist
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论