Python開發爬蟲之動態網頁抓取篇:爬取博客評論數據——經過Selenium模擬瀏覽器抓取

區別於上篇動態網頁抓取,這裏介紹另外一種方法,即便用瀏覽器渲染引擎。直接用瀏覽器在顯示網頁時解析 HTML、應用 CSS 樣式並執行 JavaScript 的語句。

這個方法在爬蟲過程當中會打開一個瀏覽器加載該網頁,自動操做瀏覽器瀏覽各個網頁,順便把數據抓下來。用一句簡單而通俗的話說,就是使用瀏覽器渲染方法將爬取動態網頁變成爬取靜態網頁。css

咱們能夠用 Python 的 Selenium 庫模擬瀏覽器完成抓取。Selenium 是一個用於Web 應用程序測試的工具。Selenium 測試直接運行在瀏覽器中,瀏覽器自動按照腳本代碼作出單擊、輸入、打開、驗證等操做,就像真正的用戶在操做同樣。html

經過Selenium模擬瀏覽器抓取。最經常使用 的是 Firefox,所以下面的講解也以 Firefox 爲例,在運行以前須要安裝 Firefox 瀏 覽器。python

以爬取《Python 網絡爬蟲:從入門到實踐》一書做者的我的博客評論爲例。網址:http://www.santostang.com/2017/03/02/hello-world/

在運行下列代碼時,必定要留意本身網絡是否暢通,若是網絡很差形成瀏覽器不能正常打開網頁及其評論數據,就可能形成爬取失敗。web

1)找到評論的HTML代碼標籤。使用Chrome打開該文章頁面,右鍵點擊頁面,打開「檢查」選項。定位到評論數據。此處定位到的評論數據便是瀏覽器渲染後的數據位置,如圖:api

 

 

2)嘗試獲取一條評論數據。在原來打開頁面的代碼數據上,咱們可使用如下代碼,獲取第一條評論數據。在下面代碼中,driver.find_element_by_css_selector是用CSS選擇器查找元素,找到class爲’reply-content’的div元素;find_element_by_tag_name則是經過元素的tag去尋找,意思是找到comment中的p元素。最後,再輸出p元素中的text文本。瀏覽器

相關代碼1:服務器

from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary

caps=webdriver.DesiredCapabilities().FIREFOX
caps["marionette"]=True
binary=FirefoxBinary(r'E:\軟件安裝目錄\裝機必備軟件\Mozilla Firefox\firefox.exe') #把上述地址改爲你電腦中Firefox程序的地址
driver=webdriver.Firefox(firefox_binary=binary,capabilities=caps)
driver.get("http://www.santostang.com/2017/03/02/hello-world/")
#page=driver.find_element_by_xpath(".//html")
driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere']"))
comment=driver.find_element_by_css_selector('div.reply-content-wrapper') #此處參數字段也能夠是'div.reply-content',具體字段視具體網頁div包含關係而定
content=comment.find_element_by_tag_name('p')
print(content.text)
#driver.page_source

輸出:網絡

在JS 裏面也找不到https://api.gentie.163.com/products/ 哪位大神幫忙解答下。謝謝。

 代碼解析:app

1)caps=webdriver.DesiredCapabilities().FIREFOX框架

由此可知,將上文代碼中的caps["marionette"]=True註釋掉,代碼依舊能夠正常運行。

 

2)binary=FirefoxBinary(r'E:\軟件安裝目錄\裝機必備軟件\Mozilla Firefox\firefox.exe')

 3)driver=webdriver.Firefox(firefox_binary=binary,capabilities=caps)

 構建webdriver類。

還能夠構建別的類型的webdriver類。

 

 

4)driver.get("http://www.santostang.com/2017/03/02/hello-world/")

 

5)driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere']"))

 6)comment=driver.find_element_by_css_selector('div.reply-content-wrapper')

7)content=comment.find_element_by_tag_name('p')

更多代碼含義和使用規則請參見官網API和Navigating:http://selenium-python.readthedocs.io/index.html

 8)關於driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere']"))中的框架定位及title內容。

可在代碼中加入driver.page_source,而且註釋掉driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere']"))。可在輸出內容中找到(若輸出雜亂,很差找出相關內容,可將其複製黏貼到文本文件中,使用Notepad++打開,該軟件有先後標籤對應顯示功能):

(此處只截取了相關內容的末尾部分)

若使用了driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere']")),而再使用driver.page_source進行相關輸出,則發現沒有上面的iframe標籤,證實咱們已經將該框架解析完畢,能夠進行相關定位獲取元素了。

 

上面咱們只是獲取了一條評論,若是要獲取全部評論,使用循環獲取全部評論。

相關代碼2:

from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary

caps=webdriver.DesiredCapabilities().FIREFOX
caps["marionette"]=True
binary=FirefoxBinary(r'E:\軟件安裝目錄\裝機必備軟件\Mozilla Firefox\firefox.exe')
driver=webdriver.Firefox(firefox_binary=binary,capabilities=caps)
driver.get("http://www.santostang.com/2017/03/02/hello-world/")
#page=driver.find_element_by_xpath(".//html")
driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere']"))

comments=driver.find_elements_by_css_selector('div.reply-content')
for eachcomment in comments:
    content=eachcomment.find_element_by_tag_name('p')
    print(content.text)
#driver.page_source

輸出:

在JS 裏面也找不到https://api.gentie.163.com/products/ 哪位大神幫忙解答下。謝謝。
@先生姓張 原來要按照這裏的操做才行。。。
在JS 裏面也找不到https://api.gentie.163.com/products/ 哪位大神幫忙解答下。謝謝。
@先生姓張 這是網易雲上面的一個鏈接地址,那個服務器都關閉了
在JS 裏面也找不到https://api.gentie.163.com/products/ 哪位大神幫忙解答下。謝謝。
測試
爲何我用代碼打開的文章只有兩條評論,原本是有46條的,有大神知道怎麼回事嗎?
菜鳥一隻,求學習羣
lalala1
我來試一試
我來試一試
應該點JS,而後看裏面的Preview或者Response,裏面響應的是Ajax的內容,而後若是去爬網站的評論的話,點開js那個請求後點Headers -->在General裏面拷貝 RequestURL 就能夠了

注意代碼2中將代碼1中的comment=driver.find_element_by_css_selector('div.reply-content-wrapper') 改爲了comments=driver.find_elements_by_css_selector('div.reply-content')

elements加了s

 

以上獲取的所有評論數據均屬於正常進入該網頁,等該網頁渲染完獲取的所有評論,並未進行點擊「查看更多」來加載目前還未渲染的評論。

下面介紹一種可以爬取到全部評論,包括點擊完「查看更多」加載的目前還未渲染的評論。

相關代碼:

from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
import time

caps=webdriver.DesiredCapabilities().FIREFOX
caps["marionette"]=True
binary=FirefoxBinary(r'E:\軟件安裝目錄\裝機必備軟件\Mozilla Firefox\firefox.exe')
driver=webdriver.Firefox(firefox_binary=binary,capabilities=caps)
driver.get("http://www.santostang.com/2017/03/02/hello-world/")
driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere']"))

time.sleep(60)
for i in range(0,10):
    try:
        load_more=driver.find_element_by_css_selector('div.more-wrapper')
        load_more.click()
    except:
        pass
    time.sleep(5)
comments=driver.find_elements_by_css_selector('div.reply-content')
    
for eachcomment in comments:
    content=eachcomment.find_element_by_tag_name('p')
    print(content.text)

代碼解析:

1)time.sleep(60)

延時60秒執行如下代碼。

2)load_more=driver.find_element_by_css_selector('div.more-wrapper')中的參數字符串

打開目標網頁,等目標網頁總體渲染完以後,右鍵評論區的「查看更多」。

3)load_more.click()

模擬點擊「查看更多」按鈕,進行完整顯示全部評論。

4)之因此在代碼中兩次使用延時函數,是由於不一樣網絡情況和不一樣機器環境下可能在打開網頁以及點擊「查看更多」按鈕後不能立刻顯示評論,因此代碼須要等一等,等到頁面徹底渲染後,再進行評論區數據的收集工做。

所以各延時函數的延時時間長短可視具體狀況靈活設置。

 輸出結果:

在JS 裏面也找不到https://api.gentie.163.com/products/ 哪位大神幫忙解答下。謝謝。
@先生姓張 原來要按照這裏的操做才行。。。
在JS 裏面也找不到https://api.gentie.163.com/products/ 哪位大神幫忙解答下。謝謝。
@先生姓張 這是網易雲上面的一個鏈接地址,那個服務器都關閉了
在JS 裏面也找不到https://api.gentie.163.com/products/ 哪位大神幫忙解答下。謝謝。
測試
爲何我用代碼打開的文章只有兩條評論,原本是有46條的,有大神知道怎麼回事嗎?
菜鳥一隻,求學習羣
lalala1
我來試一試
我來試一試
應該點JS,而後看裏面的Preview或者Response,裏面響應的是Ajax的內容,而後若是去爬網站的評論的話,點開js那個請求後點Headers -->在General裏面拷貝 RequestURL 就能夠了
如今死在了4.2節上,頁面評論是有的,可是XHR裏沒有東西啊,這是什麼狀況?有解決的大神嗎?
@骨犬 JS
爲什麼靜態網頁抓取不了?

奇怪了,我按照書上的方法來操做,XHR也是空的啊
@易君召 個人也是空的
你解決問題了嗎
@思い亦深 看JS不是XHR
XHR沒有顯示任何東西啊。奇怪。
找到緣由了
caps["marionette"] = True
做者能夠解釋一下這句話是幹什麼的嗎
@A cat named GitHub 改爲 caps["marionette"] = False 能夠運行。 目前還沒吃透代碼,先用着試試
我用的是 pycham IDE,按照做者的寫法寫的,怎麼不行
@A cat named GitHub 找到緣由了
caps["marionette"] = True
做者能夠解釋一下這句話是幹什麼的嗎
對火狐版本有要求嗎
@花晨 個人也是提示火狐版本不匹配,你解決了嗎
@A cat named GitHub 重裝了geckodriver
改爲caps["marionette"] = "Windows"
總之就行了
4.3.1 打開Hello World,代碼用的做者的,火狐地址我也設置了,爲啥運行沒反應
from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary

caps = webdriver.DesiredCapabilities().FIREFOX
caps["marionette"] = False
binary = FirefoxBinary(r'C:\Program Files\Mozilla Firefox\firefox.exe')
#把上述地址改爲你電腦中Firefox程序的地址
driver = webdriver.Firefox(firefox_binary=binary, capabilities=caps)
driver.get("http://www.santostang.com/2017/03/02/hello-world/")
我是番茄
爲何刷新沒有XHR數據,評論明明加載出來了
爲何刷新沒有XHR數據,評論明明加載出來了
@萌萌噠的小嘰嘰丶 書裏錯誤不少,留個qq吧
爲何刷新沒有XHR數據,評論明明加載出來了
第21條測試評論
第20條測試評論
第19條測試評論
第18條測試評論
第17條測試評論
第16條測試評論
第15條測試評論
第14條測試評論
第13條測試評論
第12條測試評論
第11條測試評論
第10條測試評論
第9條測試評論
第8條測試評論
第7條測試評論
第6條測試評論
第5條測試評論
第4條測試評論
第3條測試評論
第二條測試評論
第一條測試評論

 

 

參考書目:唐鬆,來自《Python 網絡爬蟲:從入門到實踐》

 參考書目做者關於本部分的介紹:http://www.santostang.com/2017/09/25/4-3-%E9%80%9A%E8%BF%87-selenium-%E6%A8%A1%E6%8B%9F%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8A%93%E5%8F%96/

相關文章
相關標籤/搜索