閱讀534 返回首頁    go 阿裏雲 go 技術社區[雲棲]


騰訊動漫爬蟲與動態隨機加載反爬破解技術實戰

​​本文作者韋瑋原創,轉載請注明出處。

項目需求與問題引入

有時,我們想爬取騰訊動漫中的漫畫,比如,我們不妨打開騰訊動漫中某一個動漫的網址https://ac.qq.com/Comic/comicInfo/id/539443,如下圖所示:

然後,我們點擊“開始閱讀”,出現如下所示界麵:

可以看到,在此有一副漫畫,我們可以按常規方式嚐試進行處理,我們查看該網頁對應的源代碼,可以發現在源代碼中並不能找到這副漫畫的圖片地址,並且,當我們鼠標往下滑動的時候,才會觸發加載後續的漫畫,所以,我們可以初步斷定,這種數據是通過異步加載動態觸發出來的。

按照一貫的解決思路,我們接下來嚐試使用抓包分析進行解決這個問題,所以我們打開Fiddler。

打開Fiddler之後,我們再次打開動漫頁拖動觸發出相應的漫畫,與此同時,Fiddler中會依次出現新觸發的資源信息,如下所示:

我們依次分析這些網址,並把漫畫相關的網址整理複製出來,放到word中,如下所示:

通過對比觀察,我們可以看到漫畫資源的網址規律。

對應的規律如下:

https://ac.qq.com/store_file_download?buid=動漫ID&uin=uin值&dir_path=/&name=日期_隨機數_漫畫圖片ID.jpg

我們可以看到,其地址中有一段是隨機數,這一段網址我們很難通過以往的網址構造的方法構造出來,所以,即使分析出了網址規律也無濟於事,因為這個網址的規律中有一部分是隨機數,即無規律的字段。

所以,顯然,這種網址動態觸發+資源隨機存儲的反爬策略我們采用以往的反爬攻關技巧很難解決,這一點大家可以先按常規的方法嚐試寫一遍便會有深刻感觸。

問題的解決辦法總是有的,隻要我們思考,接下來,我們就為大家講解這一種反爬策略應該如何攻克解決,今天我們的主要需求與目的是使用Python自動爬取騰訊動漫裏麵的各個漫畫,實現自動加載觸發漫畫並得到隨機地址的功能,以此為例為大家講解網址動態觸發+資源隨機存儲的反爬策略的攻克方式。

問題難點與解決思路

由上麵的介紹,我們可以知道,目前問題的難點在於:

1、漫畫圖片動態觸發,異步加載,無法通過漫畫的主網址獲得這些各漫畫圖片的網址,而沒有漫畫圖片的網址,我們無法爬取這些漫畫圖片。

2、漫畫圖片網址中含有隨機參數,即使我們通過抓包分析分析出各漫畫網址的規律,也無法主動構造出這些漫畫圖片的地址。

這些問題其實我們可以解決,先為大家介紹一下解決思路,解決思路如下:

1、通過PhantomJS(無界麵瀏覽器)自動觸發出漫畫圖片。

2、通過JS代碼實現頁麵滑動,以自動觸發出剩下的多張漫畫圖片。

3、觸發出漫畫圖片之後,將漫畫地址通過正則表達式提取出來。

4、交給Urllib或者Scrapy普通爬蟲,對相關資源進行自動爬取,在這裏我們使用Urllib模塊編寫相關爬蟲。

在這裏稍微解釋一下,PhantomJS雖然可以觸發相關的數據,因為其本質就是瀏覽器,但是其效率是比較慢的,所以,一般情況下,我們會將主要爬蟲處理部分交給Urllib或者Scrapy等常規爬蟲,這樣效率高,而如果常規爬蟲不能處理的部分,我們可以將這一部分交給PhantomJS等處理,處理完成後交由常規爬蟲處理,也就是不同的技術負責不同的部分,整合起來寫,這樣可以讓爬蟲的效率更高,並且不影響爬蟲的功能。

使用PhantomJS實現動態觸發動漫圖片地址的獲取

接下來,我們就來編寫實現相關的項目。

首先,我們導入相關模塊:

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

然後,我們需要基於PhantomJS創建一個瀏覽器,並且設置一下用戶代理,否則可能出現界麵不兼容的情況,如下所示:

dcap = dict(DesiredCapabilities.PHANTOMJS)  
dcap["phantomjs.page.settings.userAgent"] = ("Mozilla/4.0 (compatible; MSIE 5.5; windows NT)"  )  
browser = webdriver.PhantomJS(desired_capabilities=dcap)

然後,我們通過PhantomJS打開相關動漫網頁,將相關動漫圖片地址觸發出來,如下所示:

#打開動漫的第一頁

browser.get("https://ac.qq.com/ComicView/index/id/539443/cid/1")

#將打開的界麵截圖保存,方便觀察

a=browser.get_screenshot_as_file("D:/Python35/test.jpg")

#獲取當前頁麵所有源碼(此時包含觸發出來的異步加載的資源)

data=browser.page_source

#將相關網頁源碼寫入本地文件中,方便分析

fh=open("D:/Python35/dongman.html","w",encoding="utf-8")

fh.write(data)

fh.close()

隨後,我們運行相關代碼,運行完成後,會發現對應的截圖D:/Python35/test.jpg如下所示:

​可以看到,前麵幾幅漫畫圖片成功加載,可是後麵的漫畫圖片卻沒有加載出來,為什麼呢?

顯然後麵的漫畫圖片我們需要觸發才能加載,所以我們可以使用JS代碼實現自動拖動觸發後麵的漫畫的功能。

在沒有觸發後續的漫畫圖片之前,我們不妨看一下此時的網頁源代碼,我們在源代碼中搜索“ac.tc.qq.com/store_file_download”,即搜索滿足漫畫圖片資源的網址格式的地址,看看源碼中有沒有,如下所示:

​可以看到,此時隻有4各匹配的網址,說明此時確實沒有加載出相關的剩下的動漫圖片資源網址。

接下來,我們可以通過window.scrollTo(位置1,位置2)實現自動滑動頁麵,觸發後續的網址,我們可以在上麵的:

browser.get("https://ac.qq.com/ComicView/index/id/539443/cid/1")

代碼下麵插入如下補充代碼:

for i in range(10):

    js='window.scrollTo('+str(i*1280)+','+str((i+1)*1280)+')'

    browser.execute_script(js)

    time.sleep(1)

通過該循環,我們可以依次進行自動滑動,模擬滑動後自然會觸發後續的圖片資源。

隨後,我們再次執行代碼,執行完代碼後,截圖中你可以看到剩下的動漫圖片資源已經加載出來了,並且源碼中,匹配的網址也變多了,源碼中網址的匹配情況現在如下所示:

​可以看到,此時符合規律的網址已經變成了25個,所以,現在,當前頁麵中的所有圖片資源已經加載出來了。

顯然,我們通過PhantomJS已經實現了異步資源觸發與隨機網址獲取的功能了。接下來我們將需要提取出相關動漫圖片的網址,並交由Urllib模塊進行後續爬取。

結束了PhantomJS的使用之後,我們需要關閉一下瀏覽器,所以,我們在代碼後添加如下一行代碼:

browser.quit()

編寫完整爬蟲項目

隨後,我們繼續編寫該爬蟲項目。

我們可以通過正則表達式'<img src="(http:..ac.tc.qq.com.store_file_download.buid=.*?name=.*?).jpg"'將所有動漫資源圖片網址提取出來,提取出來之後,通過urllib對這些圖片進行爬取,爬到本地。

具體代碼實現如下:

import re
import urllib
#構造正則表達式提取動漫圖片資源網址

pat='<img src="(http:..ac.tc.qq.com.store_file_download.buid=.*?name=.*?).jpg"'

#獲取所有動漫圖片資源網址

allid=re.compile(pat).findall(data)

for i in range(0,len(allid)):

    #得到當前網址

    thisurl=allid[i]

    #去除網址中的多餘元素amp;

    thisurl2=thisurl.replace("amp;","")+".jpg"

    #輸出當前爬取的網址

    print(thisurl2)

    #設置將動漫存儲到本地的本地目錄

    localpath="D:/Python35/dongman/"+str(i)+".jpg"

    #通過urllib對動漫圖片資源進行爬取

    urllib.request.urlretrieve(thisurl2,filename=localpath)

隨後,我們運行該代碼,便可以在本地目錄D:/Python35/dongman/下看到如下信息:

​可以看到,相關動漫圖片資源已經爬到本地了。

為了方便大家調試,我們提供完整代碼,完整代碼如下所示:

from selenium import webdriver

import time

from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

import re

import urllib.request

dcap = dict(DesiredCapabilities.PHANTOMJS)  

dcap["phantomjs.page.settings.userAgent"] = ("Mozilla/4.0 (compatible; MSIE 5.5; windows NT)"  )  

browser = webdriver.PhantomJS(desired_capabilities=dcap)

#打開動漫的第一頁

browser.get("https://ac.qq.com/ComicView/index/id/539443/cid/1")

for i in range(10):

    js='window.scrollTo('+str(i*1280)+','+str((i+1)*1280)+')'

    browser.execute_script(js)

    time.sleep(1)

#將打開的界麵截圖保存,方便觀察

a=browser.get_screenshot_as_file("D:/Python35/test.jpg")

#獲取當前頁麵所有源碼(此時包含觸發出來的異步加載的資源)

data=browser.page_source

#將相關網頁源碼寫入本地文件中,方便分析

fh=open("D:/Python35/dongman.html","w",encoding="utf-8")

fh.write(data)

fh.close()

browser.quit()

#構造正則表達式提取動漫圖片資源網址

pat='<img src="(http:..ac.tc.qq.com.store_file_download.buid=.*?name=.*?).jpg"'

#獲取所有動漫圖片資源網址

allid=re.compile(pat).findall(data)

for i in range(0,len(allid)):

    #得到當前網址

    thisurl=allid[i]

    #去除網址中的多餘元素amp;

    thisurl2=thisurl.replace("amp;","")+".jpg"

    #輸出當前爬取的網址

    print(thisurl2)

    #設置將動漫存儲到本地的本地目錄

    localpath="D:/Python35/dongman/"+str(i)+".jpg"

    #通過urllib對動漫圖片資源進行爬取

    urllib.request.urlretrieve(thisurl2,filename=localpath)

可以看到,當我們直到了解決方法之後,項目實現起來並不難,在這裏,大家需要通過這一個例子,掌握這一類問題的解決思路,即掌握網址動態觸發+資源隨機存儲的反爬策略的攻克解決方案。希望大家可以多多練習,希望這篇文章能夠讓遇到這一類問題的同學獲得解決的思路與啟發。

本文作者韋瑋原創,轉載請注明出處。

作者新書推薦

最後更新:2017-07-28 23:35:21

  上一篇:go  交房時建築麵積與約定不一致該怎麼辦?
  下一篇:go  常用的分布式事務解決方案介紹