Python 爬蟲如何獲取 JS 生成的 URL 和網頁內容?
想嘗試爬下北郵人的論壇,但是看到頁面的源代碼都是js,幾乎沒有我想要的信息。
今天偶然發現了PyV8這個東西,感覺就是你想要的。它直接搭建了一個js運行環境,這意味著你可以直接在python裡面執行頁面上的js代碼來獲取你需要的內容。參考:http://www.silverna.org/blog/?p=252
https://code.google.com/p/pyv8/
js代碼是需要js引擎運行的,Python只能通過HTTP請求獲取到HTML、CSS、JS原始代碼而已。不知道有沒有用Python編寫的JS引擎,估計需求不大。我一般用PhantomJS、CasperJS這些引擎來做瀏覽器抓取。直接在其中寫JS代碼來做DOM操控、分析,以文件方式輸出結果。讓Python去調用該程序,通過讀文件方式獲得內容。
針對某網站的,可以自己看網路請求找到返回實際內容的那些有針對性地發。如果是通用的,得用 headless browser 了,比如 PhantomJS。
雖然這是一個很久以前的問題,題主似乎也已經解決的這個問題。但是看到好多答案的辦法有點太重了,這裡分享一個效率更優、資源佔用更低的方法。由於題主並沒有指明需要什麼,這裡的示例取首頁所有帖子的鏈接和標題。
首先請一定記住,瀏覽器環境對內存和CPU的消耗都非常嚴重,模擬瀏覽器環境的爬蟲代碼要儘可能避免。請記住,對於一些前端渲染的網頁,雖然在HTML源碼中看不到我們需要的數據,但是更大的可能是它會通過另一個請求拿到純數據(很大可能以JSON格式存在),我們不但不需要模擬瀏覽器,反而可以省去解析HTML的消耗。
然後,打開北郵人論壇的首頁,發現它的首頁HTML源碼中確實沒有頁面所顯示文章的內容,那麼,很可能這是通過JS非同步載入到頁面的。通過瀏覽器開發工具(Chrome瀏覽器在OS X下通過command+option+i或Win/Linux下通過F12)分析在載入首頁的時候請求,容易發現,如下截圖中的請求:
在headers選項中,有這次請求的請求頭及請求參數,我們通過Python模擬這次請求,即可拿到相同的響應。再配合BeautifulSoup等庫解析HTML,即可得到相應的內容了。
對於如何模擬請求和如何解析HTML,請移步我的專欄,有詳細的介紹,這裡便不再贅述。
通過這樣的方式可以不用模擬瀏覽器環境來抓取數據,對內存和CPU消耗、抓取速度都有很大的提升。在編寫爬蟲的時候,請務必記得,如非必要,不要模擬瀏覽器環境。簡單總結下 一般來說 有兩種方式
一種 像大家說的 模擬瀏覽器環境 用一些庫來執行這些js 相關的庫大家都提到了
但是這些庫安裝起來好像都很麻煩 而且對內存和cpu的消耗比較大 基本上不推薦還有一種 就是手動分析 這種我覺得是比較好的 js的作用的確很多 但是爬蟲關注的是數據 js無非就是請求數據 或者請求回來以後再進行加工總之 它的數據肯定也有來源的 如果是網路請求來的 我們也請求這個數據就好了 如果是自己生成的 同樣代碼模擬下就好了只不過這種辦法可能比較消耗時間還有一點 可以試試用nodejs跑js代碼 當然前提是那個代碼不涉及瀏覽器的一些內容 比如扣扣空間的密碼加密代碼 它就是將輸入的代碼加密成密文 這樣我們可以把這段加密函數直接保存下來 爬蟲時每次調用下就好寫到這 越來越感嘆 這js大一統的時代感覺在逼近啊去年還真爬過這樣的數據,因為趕時間,我的方法就比較醜陋了。
PyQt有一個具體的庫來模擬瀏覽器請求和行為(好像是webkit,忘記了,查一下就好。使用時就幾行代碼就夠了),在一次運行程序中,第一次(只有第一次)的返回結果是js運行之後的代碼。於是寫了一個py腳本做一次訪問解析,然後再寫了windows腳本通過傳遞命令行參數循環這個py腳本,最後搞到數據。
方法dirty了些,不過數據拿到了就好~我是直接看js源碼,分析完,然後爬的。例如看頁面是用Ajax請求一個JSON文件,我就先爬那個頁面,獲取Ajax所需的參數,然後直接請求JSON頁,然後解碼,再處理數據併入庫。如果你直接運行頁面上所有js(就像瀏覽器做的那樣),然後獲取最終的HTML DOM樹,這樣的性能非常地糟糕,不建議使用這樣的方法。因為Python和js性能本身都很差,如果這樣做,會消耗大量CPU資源並且最終只能獲得極低的抓取效率。
又一個爬北郵人論壇的。。
文藝的方法,上瀏覽器引擎,比如 PhantomJS ,用它導出 html,再對html用 python 解析。千萬別直接 PhantomJS 解析,雖然我知道這很容易,為什麼?&那就不叫 python 爬蟲了啊& 因為統一使用 python 做解析更統一,這裡假設你還在爬取非 JS 頁面。
X-Requested-With:XMLHttpRequest
而漲經驗最快的方式是:學學怎麼寫網站,你知道網站是什麼發請求的,就知道怎麼爬了。
二B的方法,瀏覽器打開,右鍵另存為。。。這裡舉個栗子:
拉勾網的職位列表所以我們就可以模仿這一個步驟來構造一個數據包來模擬用戶的點擊動作。
post_data = {"first":"true","kd":"Android","pn":"1"}
然後使用python中庫中最簡單的requests庫來提交數據。 而這些數據 正是抓包里看到的數據。
import requests
return_data=requests.post("http://www.lagou.com/jobs/posi ... ot%3B,data=post_data)
print return_data.text
吶,列印出來的數據就是返回來的json數據
Firefox抓包分析 (拉勾網抓包分析)在知乎找到了學python爬蟲的方法,為了回饋,解答這道題。1、抓取地址:你要輸入一個搜索關鍵字,類似「http://-gouwu.sogou.com/shop?query=iphone/detail/『。你輸入了iphone,那麼他自動會生成一個頁面http://-gouwu.sogou.com/shop?query=iphonedisplay=gridsourceid=sr_tbtnw=01029901sut=589sst0=1454465834270那麼你就需要得到這個地址。2、製作一個關鍵字.py,這樣讓爬蟲能循環執行下去。不斷提取關鍵字.py里的搜索詞。
3、self.browser.get(response.url),self.browser.close()
4、普通爬蟲爬取手法。每次打開搜索頁面,爬取數據,保存即可。Google Phantom JS
按照題主的描述有仔細看了下北郵人的論壇 ,此網站的所有網頁內容請求的 url 應該都是可以通過抓包分析出來的。
比如說我們看下其中的一個優秀版主評選板塊:北郵人論壇-北郵人的溫馨家園 ,使用Chrome的F12或者其他任何你比較熟悉的工具抓包,其他板塊同理。
把response裡面的具體內容複製出來,查看分析,再使用正則之類的去匹配就可以了。
但是這種可以通過抓包一步到位分析出來的是比較簡單的,我也看到很多朋友的討論已經不僅僅是局限於北郵人論壇,比如說某些網站的某個請求中的參數可能是JavaScript計算出來等情況。
比方說我們最常接觸的網易雲音樂,很多人表示網易雲音樂的歌曲熱門評論很難抓取,因為請求評論的數據的中的請求參數是經過JavaScript計算加密過的。
而對於這一類的網站,我們通常會有三種情況,對於這幾種情況無疑都需要對網頁請求的整個流程有比較好的把握,以及能比較有耐心的一層一層分析請求參數等等的來源。
首先按我們看上面的網易雲音樂的請求評論數據的參數:params 和 encSecKey ,同時在Name欄目可以清楚地看到處理該參數的 js 文件為 core.js
所以為了弄清楚兩個參數的來源,我們把core.js文件下載到本地,使用Javascript在線解壓縮 - 在線工具 解壓縮,得到標準格式的JavaScript文件,搜索兩個參數。
我們會發現這兩個參數來源於window.asrsea的函數加密,window.asrsea需要四個參數,為了弄清楚這四個參數的來源,我們可以改變本地core.js代碼,並用fildder替換執行。
替換之後查看Chrome中的console輸出,查看四個參數的值信息,可以看出除了bl其他的幾個參數都是固定的字元串值。再看bl值,bl 值由字典構成,總共有五個key值。
- rid:rid值由一個固定字元串R_SO_4_和歌曲的id構成
- offset:表示當前是第幾頁的評論數據
- total:固定值true
- limit:每頁顯示多少個評論,默認20
- csrf_token:無關可以為空
我們知道了參數的來源,弄清楚函數的具體執行流程是什麼,一切就豁然開朗了。追蹤window.asrsea 函數,找到如下內容,現在我們就弄明白了所有的流程了。
既然弄清楚了所有的JS加密流程下面就有幾種方法去解決。
1、使用Python模擬
我正常採用的就是這種手段,先分析具體的JavaScript代碼,再嘗試用Python去模擬,不過這種選擇需要你對Python相對比較熟悉。
def aesEncrypt(text, secKey):
pad = 16 - len(text) % 16
text = text + pad * chr(pad)
encryptor = AES.new(secKey, 2, "0102030405060708")
ciphertext = encryptor.encrypt(text)
ciphertext = base64.b64encode(ciphertext)
return ciphertext
def rsaEncrypt(text, pubKey, modulus):
text = text[::-1]
rs = int(text.encode("hex"), 16)**int(pubKey, 16) % int(modulus, 16)
return format(rs, "x").zfill(256)
def createSecretKey(size):
return ("".join(map(lambda xx: (hex(ord(xx))[2:]), os.urandom(size))))[0:16]
2、Python執行JavaScript代碼
Python執行JavaScript代碼,如果對Python不是很熟悉,建議採用這種方法,這種方法的可用第三方庫比較多,研究了一些文檔之後發現:
- ScriptControl只能在windows上運行,需要win32com庫
- PyV8能在windows和*nix上運行,需要裝PyV8庫
- SpiderMonkey是mozilla的js引擎在python上的移植。
經評論區的朋友們提醒,自己也嘗試使用了一下另外一個第三方庫:Js2Py
此第三方庫不但可以執行JavaScript代碼,甚至可以把JavaScript代碼轉換成Python代碼,但是在此只推薦轉換簡單的JavaScript代碼,這是一個轉換的案例。
由於網易雲音樂的評論加密這一塊涉及的函數相對較多,這裡不推薦使用Python執行JavaScript代碼。
3、最粗暴的方法
最粗暴的方法是使用selenium+phantomjs無界面瀏覽器,這兩者的結合其實就是直接操作瀏覽器,可以獲取JavaScript渲染後的頁面數據。
這兩者結合使用的缺點:
- 由於是無界面瀏覽器,採用此方案效率極低,如果大批量抓取不推薦。
- 對於非同步請求並且數據在源碼中並不存在的,同時也就無法抓取到的數據。
對這兩個不了解可以查一下兩者的官方文檔,也可以讀讀這篇文章快都上手:python爬蟲的最佳實踐(五)--selenium+PhantomJS
感覺不錯也歡迎點贊支持。
很多人問我如何學習Python爬蟲,為此我整理編寫了一本Python爬蟲相關的電子書,主要包括Python入門、Python爬蟲入門到進階、Python爬蟲面試總結等等。可以在微信公眾號【一個程序員的日常】後台回復關鍵詞【1】獲取這本電子書。
使用 python 模擬瀏覽器行為,有一些庫可以使用。例如 selenium 和 webdriver,還有一個 ghost
一般要先用抓包工具分析出ajax請求的url。
如果想偷懶,可以直接抓取用webkit內核渲染後的網頁,但是比較耗資源。
https://github.com/heartfly/ajax_crawler
我寫的這個爬蟲實現了以上功能如果是在windows下,可以嘗試調用windows系統中的webbrowser控制項。另外ie本身也提供了介面。不過這兩種方式都要渲染頁面,性能上多少有點浪費,為了加快速度可以把ie的圖片下載顯示關閉掉,然後通過click等方法來模擬真實行為。
Google headless browser.
用selenium
細看題主的內容,發現題主還沒找到想爬內容所在的真實URL。這個問題,建議用一個叫「Fiddler」的工具!
casperjs 終極武器
兩種思路:
- 如果頁面實現的比較清晰,比如直接是用json請求數據的。那麼直接用Python請求json數據即可。如果js中的處理邏輯很少,可以用Python自己實現一遍來解析。
- 開一個瀏覽器來抓取,包括但不限於:網頁另存為、開一個PhantomJS、自己集成WebKit/V8。
推薦閱讀:
※如何看待 AWS Lambda ?
※有哪些方式可以實現跨域?
※为什么form表单提交没有跨域问题,但ajax提交有跨域问题?
※用於驗證的 Passport.js 與 JsonWebToken 是什麼關係?
※「遵循XXX開源協議」這句話規定了什麼,我要把某個js工具用在項目中,我具體要做哪些事情才算遵循協議?
TAG:JavaScript | Python | 爬蟲計算機網路 | URL | Python框架 |