利用python爬取網(wǎng)站數(shù)據(jù)非常便捷湿弦,效率非常高,但是常用的一般都是使用BeautifSoup汞扎、requests搭配組合抓取靜態(tài)頁面(即網(wǎng)頁上顯示的數(shù)據(jù)都可以在html源碼中找到,而不是網(wǎng)站通過js或者ajax異步加載的),這種類型的網(wǎng)站數(shù)據(jù)爬取起來較簡單掌腰。但是有些網(wǎng)站上的數(shù)據(jù)是通過執(zhí)行js代碼來更新的,這時傳統(tǒng)的方法就不是那么適用了张吉。這種情況下有如下幾種方法:
清空網(wǎng)頁上的network信息齿梁,更新頁面,觀察網(wǎng)頁發(fā)送的請求肮蛹,有些網(wǎng)站可以通過這種方法構(gòu)造參數(shù)勺择,從而簡化爬蟲孤个。但是適用范圍不夠廣泛各谚。
使用selenium模擬瀏覽器行為更新網(wǎng)頁獲取更新后的數(shù)據(jù)。本文接下來著重講述這種方法航厚。
一气忠、準(zhǔn)備工作
模擬瀏覽器需要用到兩個工具:
1.selenium,可直接通過pip install selenium進行安裝赋咽。
2.PhantomJS,這是一個無界面的冬耿,可腳本編程的WebKit瀏覽器引擎,百度進行搜索亦镶,在其官網(wǎng)下進行下載日月,下載后無需安裝,放到指定路徑下缤骨,在使用時只需指定文件所在路徑即可爱咬。
二、使用selenium模擬瀏覽器
本文爬取網(wǎng)站示例為:http://datacenter.mep.gov.cn:8099/ths-report/report!list.action?xmlname=1465594312346(最新測試發(fā)現(xiàn)網(wǎng)站已無法打開绊起,2021年5月25日)
學(xué)習(xí)示例時請不要爬取太多頁面精拟,走一遍流程了解怎么抓就行。
打開網(wǎng)站后,可以看到需要爬取的數(shù)據(jù)為一個規(guī)則的表格蜂绎,但是有很多頁栅表。
在這個網(wǎng)站中,點擊下一頁頁面的url不發(fā)生變化师枣,是通過執(zhí)行一段js代碼更新頁面的怪瓶。因此本文思想就是利用selenium模擬瀏覽器進行點擊,點擊“下一頁”后頁面數(shù)據(jù)進行更新践美,獲取更新后的頁面數(shù)據(jù)即可洗贰。下面是完整代碼:
# -*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup
import json
import time
from selenium import webdriver
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )
curpath=sys.path[0]
print curpath
def getData(url):
? ? # 使用下載好的phantomjs,網(wǎng)上也有人用firefox陨倡,chrome敛滋,但是我沒有成功,用這個也挺方便
driver =webdriver.PhantomJS(executable_path="C:/phantomjs.exe")
driver.set_page_load_timeout(30)
time.sleep(3)
html=driver.get(url[0])? # 使用get方法請求url兴革,因為是模擬瀏覽器绎晃,所以不需要headers信息
for page in range(3):
html=driver.page_source? # 獲取網(wǎng)頁的html數(shù)據(jù)
soup=BeautifulSoup(html,'lxml')? # 對html進行解析,如果提示lxml未安裝帖旨,直接pip install lxml即可
table=soup.find('table',class_="report-table")
name=[]
for th in table.find_all('tr')[0].find_all('th'):
name.append(th.get_text())? # 獲取表格的字段名稱作為字典的鍵
flag=0? # 標(biāo)記箕昭,當(dāng)爬取字段數(shù)據(jù)是為0,否則為1
for tr in table.find_all('tr'):
# 第一行為表格字段數(shù)據(jù)解阅,因此跳過第一行
if flag==1:
dic={}
i=0
for td in tr.find_all('td'):
dic[name[i]]=td.get_text()
i+=1
jsonDump(dic,url[1])#保存數(shù)據(jù)
flag=1
? # 利用find_element_by_link_text方法得到下一頁所在的位置并點擊落竹,點擊后頁面會自動更新,只需要重新獲取driver.page_source即可
driver.find_element_by_link_text(u"下一頁").click()
def jsonDump(_json,name):
"""store json data"""
with open(curpath+'/'+name+'.json','a') as outfile:
json.dump(_json,outfile,ensure_ascii=False)
with open(curpath+'/'+name+'.json','a') as outfile:
outfile.write(',\n')
if __name__ == '__main__':
url=['http://datacenter.mep.gov.cn:8099/ths-report/report!list.action?xmlname=1465594312346','yzc']? # yzc為文件名货抄,此處輸入中文會報錯述召,前面加u也不行,只好保存后手動改文件名……
getData(url)? # 調(diào)用函數(shù)
本文中獲取下一頁的位置是通過driver.find_element_by_link_text方法來實現(xiàn)的蟹地,這是因為在此網(wǎng)頁中积暖,這個標(biāo)簽沒有唯一可標(biāo)識的id,也沒有class怪与,如果通過xpath定位的話夺刑,第一頁和其他頁的xpath路徑又不完全相同,需要加個if進行判斷分别。因此直接通過link的text參數(shù)進行定位遍愿。click()函數(shù)模擬在瀏覽器中的點擊操作。
selenium的功能非常強大耘斩,用在爬蟲上能夠解決很多一般爬蟲解決不了的問題沼填,它可以模擬點擊、鼠標(biāo)移動括授,可以提交表單(應(yīng)用如:登陸郵箱賬號坞笙、登陸wifi等,網(wǎng)上有很多實例籍茧,本人暫時還沒有嘗試過)却邓,當(dāng)你遇到一些非常規(guī)的網(wǎng)站數(shù)據(jù)爬取起來非常棘手時院水,不妨嘗試一下selenium+phantomjs。