那些年,我爬過的北科(六)——反反爬蟲之js渲染

叄公子KCN發表於2019-03-01

反爬蟲和反反爬蟲?

從本章開始,我們將要進入反反爬蟲篇的內容。

感覺如果是第一聽到這個名字的讀者肯定是懵逼的狀態。現在我們先來介紹一下什麼是爬蟲、反爬蟲、反反爬蟲。

爬蟲其實就是我們前面所學的程式碼,直接使用requests.get("http://xxx.com")就能拿到網站的原始碼。

但是很多時候,我們獲取的都是有價值的資料,而網站開發者就不想讓我們拿到他們的資料,就有了很多反爬蟲的策略,不讓我們那麼容易的爬取到資料。反爬蟲的策略其實其實主要就是三個方面:

  • ①JS加密:HTML是用js程式碼生成的,不讓我們拿到html。
  • ②禁IP:我們寫爬蟲的時候,一般用一個ip爬取,如果訪問頻率過高,網站開發者可以不讓我們這個ip訪問網站。
  • ③驗證碼:獲取資料之前要先輸入驗證碼。

當然,除了這三個,還有些別的東西,比如說User-Agent識別這樣的就屬於比較基本的了,我們這裡就不展開了。

而反反爬蟲,其實就是針對上面的三個方面給出解決方案:

  • ①針對JS加密:我們可以使用無頭瀏覽器渲染js,再解析渲染後的html程式碼。
  • ②針對禁IP:我們可以使用代理ip等方式,用不同的ip訪問網站。
  • ③針對驗證碼:我們可以對驗證碼進行識別,也可以使用雲打碼這種人工驗證碼平臺。

關於爬蟲、反爬蟲、反反爬蟲的故事,知乎上的這個回答描繪的非常形象。

如何應對網站反爬蟲策略?如何高效地爬大量資料? - 申玉寶的回答 - 知乎 www.zhihu.com/question/28…

本章內容

通過上面的介紹,讀者應該對反反爬蟲有了一個基本的認識了。本章將要對反爬蟲的第一個方案:JS加密,進行反反爬蟲。

嘗試爬取 baidu.com

在介紹反反爬蟲方法之前,我們先拿百度測試一下。這裡假設我們想爬一爬百度搜尋美女的搜尋結果,也就是這個連結:www.baidu.com/s?wd=%E7%BE…(注:這裡URL進行了url編碼)

我們先用之前超級好用的requests庫試一下。

那些年,我爬過的北科(六)——反反爬蟲之js渲染

稍微懂點兒html的就知道,這裡沒看到所謂的美女圖,反而還讓我們跳轉回www.baidu.com/

什麼是無頭瀏覽器?

上面我們用requests.get什麼都沒看到,但我們用瀏覽器訪問www.baidu.com/s?wd=%E7%BE…的時候,的的確確看到了搜尋結果的。

那些年,我爬過的北科(六)——反反爬蟲之js渲染

用requests不行,明顯是百度的後臺識別出來我們是低劣的爬蟲程式,鄙視我們,什麼都不給我們。

既然用瀏覽器可以,我們是不是可以通過Api呼叫我們的瀏覽器然後爬取搜尋結果呢?

確實是可以,而且還有種瀏覽器叫:Headless Browser,也就是無頭瀏覽器,沒有介面的瀏覽器。如果有介面的話,我們可能還要用顯示卡去渲染圖形頁面,非常耗費欄位,這簡直是專門為爬蟲開發者設計的。

Phantomjs

我們這裡主要介紹的一款無頭瀏覽器名叫:PhantomJS。雖然它現在已經不更新了,但不妨礙我們繼續使用它。

下載PhantomJS

我們首先下載安裝PhantomJS,下載連結為:phantomjs.org/download.ht…

下載後解壓可以看到在bin目錄下面有一個phantomjs的可執行檔案。(如果是windows的話就是phantomjs.exe

那些年,我爬過的北科(六)——反反爬蟲之js渲染

安裝selenium

接下來我們需要安裝selenium,直接使用pip命令即可。

pip install selenium
複製程式碼

selenium是一個用於Web應用程式測試的工具。它相容各種瀏覽器,包括:PhantomJS、Chrome、FireFox等。

phantomjs預設的話要用JavaScript寫程式碼。安裝了selenium,我們就可以使用python進行操作了。

使用PhantomJS爬取百度

以上安裝好了之後,我們再嘗試使用phantomjs爬取一下百度。程式碼如下:

from selenium import webdriver

exe_path = "/usr/bin/phantomjs"
driver = webdriver.PhantomJS(executable_path=exe_path)

driver.get("https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3")

driver.save_screenshot("screenshot.png")  # 截個圖
print(driver.page_source)  # 列印原始碼

driver.quit()
複製程式碼

這裡需要根據自己phantomjs的下載路徑配置exe_path。然後首先建立一個driver物件,呼叫get訪問頁面,就會自動渲染內部的js,顯示出結果。

注意:在不使用了之後,要呼叫driver.quit()退出,要不然後臺會有很多phantomjs程式。

這裡我們呼叫selenium的截圖方法看下結果。

那些年,我爬過的北科(六)——反反爬蟲之js渲染

可以看到我們連網頁的截圖都弄出來了。selenium除了截圖之外,還支援很多使用js才能完成的操作,比如說:模擬點選、滾動等等。如果讀者感興趣可以自己去研究。

修改PhantomJS的UA

PhantomJS預設的User-Agent使用的是:PhantomJS。如果我們帶著這個會很容易被網站檢測出來,我們可以在建立driver的時候加入配置修改PhantomJS的UA,讓它偽裝成Chrome瀏覽器。程式碼實現如下:

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

dcap = dict(DesiredCapabilities.PHANTOMJS)
dcap['phantomjs.page.settings.userAgent'] = ('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36')
exe_path = "/usr/bin/phantomjs"
driver = webdriver.PhantomJS(executable_path=exe_path, desired_capabilities=dcap)
複製程式碼

Chrome的無頭模式

PhantomJS訪客檢測

當然,有的時候,你會發現有些網站你用了PhantomJS還是爬不了,筆者就遇到過這樣的場景。這是因為PhantomJS建立在Qt框架。而Qt實現HTTP棧的方式使它和其他現代瀏覽器不一樣。

在Chrome中,發出Http請求的head如下:

GET / HTTP/1.1
Host: localhost:1337
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ru;q=0.6
複製程式碼

然而在PhantomJS,相同的HTTP請求是這樣的:

GET / HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.8 Safari/534.34
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: Keep-Alive
Accept-Encoding: gzip
Accept-Language: en-US,*
Host: localhost:1337
複製程式碼

你會注意到PhantomJS頭是不同於Chrome(事實證明,其他所有現代瀏覽器)有一些微妙的不同:

  • 主機(host) 出現最後一行
  • 連線頭(Connection)是大小寫混合
  • 唯一的 接受編碼 值是gzip

在伺服器上檢查這些HTTP頭的變化,它應該可以識別PhantomJS瀏覽器。

Selenium+Chrome

如果讀者真的碰到這種情況的話,就可以考慮用別的無頭瀏覽器了,比如說Chrome的無頭模式

Chrome的無頭模式和selenium也可以結合在一起使用。這裡首先需要下載chromedriver,然後通過selenium的API使用即可。以下為簡單的示例,如果讀者對這個感興趣,可以查閱自行百度查詢教程。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument('--headless')
driver = webdriver.Chrome(chrome_options=chrome_options, executable_path='/usr/bin/chromedriver')
複製程式碼

另一個工具:Splash

這裡還有一款工具叫Splash,它是一個JavaScript渲染服務,基於Twisted和QT5,提供了Http的API。

相比PhantomJS和Chrome的無頭模式,Splash的效能會好很多,而且可以支援併發渲染,不過需要跑Docker。

兩個比較火的Python爬蟲框架:Scrapy以及PySpider就是使用Splash作為JS渲染引擎。

這裡筆者只是簡單進行介紹,如果讀者對這個感興趣,可以查閱自行百度查詢教程。

Reference

相關文章