Python爬蟲爬取動態頁面思路+實例(一)


簡介

有時候,我們天真無邪的使用urllib庫或Scrapy下載HTML網頁時會發現,我們要提取的網頁元素並不在我們下載到的HTML之中,盡管它們在瀏覽器里看起來唾手可得。

這說明我們想要的元素是在我們的某些操作下通過js事件動態生成的。舉個例子,我們在刷QQ空間或者微博評論的時候,一直往下刷,網頁越來越長,內容越來越多,就是這個讓人又愛又恨的動態加載。

爬取動態頁面目前來說有兩種方法

  1. 分析頁面請求(這篇介紹這個)
  2. selenium模擬瀏覽器行為(霸王硬上弓,以后再說)

言歸正傳,下面介紹一下通過分析頁面請求的方法爬取動態加載頁面的思路。中心思想就是找到那個發請求的javascript文件所發的請求。

舉兩個例子,京東評論和上證股票。

后注:本文的兩個例子都是get請求,可以顯示的在瀏覽器中查看效果,如果是post請求,需要我們在程序中構造數據,構造方法可以參考我從前的一篇博文Scrapy定向爬蟲教程(六)——分析表單並回帖

京東評論

這是一個比較簡單的例子。

首先我們隨便找一個熱賣的商品,評論比較多。

就這個吧威剛(ADATA) SU800 256G 3D NAND SATA3固態硬盤

點進去看看這個頁面現在的狀況

圖一

滾動條給的第一印象感覺這頁仿佛沒多少內容。

鍵盤F12打開開發者工具,選擇Network選項卡,選擇JS(3月12日補:除JS選項卡還有可能在XHR選項卡中,當然也可以通過其它抓包工具),如下圖

圖二

然后,我們來拖動右側的滾動條,這時就會發現,開發者工具里出現了新的js請求(還挺多的),不過草草翻譯一下,很容易就能看出來哪個是取評論的,如下圖

圖三

好,復制出js請求的目標url

圖四

在瀏覽器中打開,發現我們想要的數據就在這里,如下圖

圖五

這整個頁面是一個json格式的數據,對於京東來說,當用戶下拉頁面時,觸發一個js事件,向服務器發送上面的請求取數據,然后通過一定的js邏輯把取到的這些json數據填充到HTML頁面當中。對於我們Spider來說,我們要做的就是把這些json數據整理提取。

在實際應用中,當然我們不可能去每個頁面里找出來這個js發起的請求目標地址,所以我們需要分析這個請求地址的規律,一般情況下規律是比較好找的,因為規律太復雜服務方維護也難。那我們就來看一下京東這個請求:

https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv337&productId=3311073&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0
  • 1

挺長的一個GET請求,不過參數命名都很規范,產品ID,評論頁碼什么的,因為我這里只是舉個例子,我就不一個一個去研究了~

思路有了,就按照正常的爬蟲去寫就好了,發請求,得到響應,解析數據,后續處理等等……

上證股票

這是前段時間一位道友問我的一個問題,感覺還是挺有嚼頭的,比上例要難。

目標網址:上海證券交易所

目的是把每一頁的股票信息都得到,看似很簡單,但是通過查看源代碼發現,每一頁的鏈接在源代碼里是看不到的。如下圖

圖六

ok,又是js動態加載,在源代碼里不顯示,不過一定躲不過我們的開發者工具,按照上面京東的思路,切到Network、js選項卡,點擊頁碼,獲得請求地址,一切行雲流水,如下圖

圖七

然而,當我們復制出這個url,在瀏覽器中打開的時候,瀏覽器呈現的信息卻是:

圖八

403錯誤!奇哉怪也!

究其原因,403狀態碼什么意思呢?意思就是說,本服務器知道你發來這一串url想找啥呢,但是老子就不給你!

怎么辦,有辦法~

想想看,為什么我們在那個頁面上點擊第二頁第三頁的時候能夠正常的獲取到數據?為什么我們直接請求不行?都是同一個瀏覽器呀。

問題就在於,瀏覽器通過上一個頁面發起的請求和單獨發的請求,頭信息(request header)是不同的,比方說cookie、refer這些字段,服務器就通過這些就把我們的請求過濾掉了。

瀏覽器如此,我們的爬蟲也是如此,最后我解決這個問題的方法是給爬蟲設定詳細的請求頭(從我們能請求到的原始頁獲得),包括cookie,refer等,終於成功的得到了返回的json數據。

這份代碼是用python3的urllib寫的,我只幫他寫了取一頁的數據,邏輯他自己去寫了。如下,看官不妨試試將頭信息去掉~

import urllib.request

Cookie = "PHPStat_First_Time_10000011=1480428327337; PHPStat_Cookie_Global_User_Id=_ck16112922052713449617789740328; PHPStat_Return_Time_10000011=1480428327337; PHPStat_Main_Website_10000011=_ck16112922052713449617789740328%7C10000011%7C%7C%7C; VISITED_COMPANY_CODE=%5B%22600064%22%5D; VISITED_STOCK_CODE=%5B%22600064%22%5D; seecookie=%5B600064%5D%3A%u5357%u4EAC%u9AD8%u79D1; _trs_uv=ke6m_532_iw3ksw7h; VISITED_MENU=%5B%228451%22%2C%229055%22%2C%229062%22%2C%229729%22%2C%228528%22%5D" url = "http://query.sse.com.cn/security/stock/getStockListData2.do?&jsonCallBack=jsonpCallback41883&isPagination=true&stockCode=&csrcCode=&areaName=&stockType=1&pageHelp.cacheSize=1&pageHelp.beginPage=3&pageHelp.pageSize=25&pageHelp.pageNo=3&pageHelp.endPage=31&_=1480431103024" headers = { 'User-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36', 'Cookie': Cookie, 'Connection': 'keep-alive', 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, sdch', 'Accept-Language': 'zh-CN,zh;q=0.8', 'Host': 'query.sse.com.cn', 'Referer': 'http://www.sse.com.cn/assortment/stock/list/share/' } req = urllib.request.Request(url,None,headers) response = urllib.request.urlopen(req) the_page = response.read() print(the_page.decode("utf8"))

結語

還是那句話,通過分析頁面請求的方法爬取動態加載頁面的思路。中心思想就是找到那個發請求的javascript文件所發的請求。然后利用我們既有的爬蟲知識去構造請求就可以了。

臨近考試,寫作較為匆忙。如果本文有敘述不清或者不正確的地方,還請批評指正。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM