騰訊動漫Python爬蟲與動態隨機載入反爬破解技術實戰
專案需求與問題引入
有時,我們想爬取騰訊動漫中的漫畫,比如,我們不妨打開騰訊動漫中某一個動漫的網址http://ac.qq.com/Comic/comicInfo/id/539443,如下圖所示:
然後,我們點擊“開始閱讀”,出現如下所示介面:
可以看到,在此有一副漫畫,我們可以按常規方式嘗試進行處理,我們查看該網頁對應的原始程式碼,
按照一貫的解決思路,我們接下來嘗試使用抓包分析進行解決這個問題,所以我們打開Fiddler。
打開Fiddler之後,我們再次打開動漫頁拖動觸發出相應的漫畫,與此同時,Fiddler中會依次出現新觸發的資源資訊,
我們依次分析這些網址,並把漫畫相關的網址整理複製出來,放到word中,如下所示:
通過對比觀察,我們可以看到漫畫資源的網址規律。
對應的規律如下:
http://ac.qq.com/store_file_download?buid=動漫ID&uin=uin值&dir_path=/&name=日期_亂數_漫畫圖片ID.jpg
我們可以看到,其位址中有一段是亂數,這一段網址我們很難通過以往的網址構造的方法構造出來,
所以,顯然,這種網址動態觸發+資源隨機存儲的反爬策略我們採用以往的反爬攻關技巧很難解決,這一點大家可以先按常規的方法嘗試寫一遍便會有深刻感觸。
問題的解決辦法總是有的,只要我們思考,接下來,
問題難點與解決思路
由上面的介紹,我們可以知道,目前問題的難點在於:
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("http://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("http://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()
編寫完整爬蟲項目
隨後,我們繼續編寫該爬蟲項目。
我們可以通過規則運算式'
具體代碼實現如下:
import re
import urllib
#構造規則運算式提取動漫圖片資源網址
pat='
#獲取所有動漫圖片資源網址
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("http://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='
#獲取所有動漫圖片資源網址
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)
可以看到,當我們直到了解決方法之後,項目實現起來並不難,在這裡,大家需要通過這一個例子,掌握這一類問題的解決思路,即掌握網址動態觸發+資源隨機存儲的反爬策略的攻克解決方案。希望大家可以多多練習,希望這篇文章能夠讓遇到這一類問題的同學獲得解決的思路與啟發。
作者新書推薦
tstoutiao,邀請您加入頭條資料愛好者交流群,資料愛好者們都在這兒。
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("http://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("http://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()
編寫完整爬蟲項目
隨後,我們繼續編寫該爬蟲項目。
我們可以通過規則運算式'
具體代碼實現如下:
import re
import urllib
#構造規則運算式提取動漫圖片資源網址
pat='
#獲取所有動漫圖片資源網址
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("http://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='
#獲取所有動漫圖片資源網址
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)
可以看到,當我們直到了解決方法之後,項目實現起來並不難,在這裡,大家需要通過這一個例子,掌握這一類問題的解決思路,即掌握網址動態觸發+資源隨機存儲的反爬策略的攻克解決方案。希望大家可以多多練習,希望這篇文章能夠讓遇到這一類問題的同學獲得解決的思路與啟發。
作者新書推薦
tstoutiao,邀請您加入頭條資料愛好者交流群,資料愛好者們都在這兒。