爬蟲爬蟲Pyspider+Selenium+Chrome
前言:
最近受林老闆之託需要爬取一些資料。想要簡單實現,看到Pyspider好像不錯,好的,就決定是你拉。
分析:
這次需要爬取的任務大致情況如下:
-
需要爬取某網站試題以及答案
-
試題以及答案最終會在同一個頁面上呈現
-
每次顯示有限的題數,例如20道題目,做完提交後可以看答案
-
需要進行答案填寫和提交,下次進入才會有新的題目出來
-
該網站最終連結是js非同步請求生成的
我需要的爬取流程也很簡單:
-
手工通過賬號密碼登入該網站,獲取登入後的cookies資訊
-
指令碼通過cookies登入該網站
-
一路跳轉到試題介面
-
填寫試題,提交,檢視題目和答案
-
解析html,將試題和答案儲存到本地
搞起:
雖然流程是按部就班的來,但是為了興趣和成效,我先從最後一步走起(當然cookies登入必不可少):
百度了Pyspider的用法和PyQuery的用法,這裡提供兩個連結參考:
很快就最終結果給弄出來了。輸入試題和答案頁面的連結,就會生成結果檔案,一切順利,果然信心滿滿(^_^)。
遇到問題:
然後是自動進行爬取的跳轉操作:
Pyspider已經支援了PhantomJS,所以要渲染帶js的頁面,或者實現點選操作都可以。
Pyspider的模擬點選是通過crawl的引數js_script實現的,例如:
self.crawl('http://www.example.org/', callback=self.callback,fetch_type='js', js_script=''' function() { document.querySelectorAll('.btn-inner')[1].click(); } ''')
Pyspider的一般做法是獲取點選跳轉的URL,然後再進行crawl。
但是面對一些通過js跳轉的網頁,除非你能解析出點選後的js如何返回連結,由於js通常加密過,有一定難度,而且這樣工作量太大了。
臨時解決方法:
但老闆那邊催著要,先爬到要緊,想到了使用按鍵精靈獲取最終頁面的連結。
錄製滑鼠和鍵盤事件:
-
點選進入首頁,從首頁點選進入試題
-
進行提交,進入試題和答案頁
-
複製頁面連結
-
貼上到Pyspider程式碼中
-
點選除錯的run按鈕
不斷重複這個指令碼,資料就爬下來了。
這個方法雖然簡單,但是主要缺點也是很明顯:
-
按鍵指令碼難以重複使用,因為指令碼的滑鼠操作座標是根據螢幕的,它根本不知道網頁
-
不能後臺進行,這臺電腦就不能做其他事情了
-
效率慢
完善:
百度搜到參考文章:Pyspider使用Selenium+Chrome實現爬取js動態頁面 https://www.jianshu.com/p/8d955deac99b ,也很簡單,該大神的程式碼已經貼上,執行就可以了。
我這次需要的步驟也很明瞭了:
-
搭建Flask+Selenium+Chrome的後臺服務
-
通過該後臺服務處理頁面模擬點選事件,返回最終頁面
-
Pyspider訪問該後臺服務,獲取最終頁面,解析html獲取資料
我在文章開頭想好的流程1-4都可以在這個後臺完成了。
通過Selenium操作瀏覽器進行頁面跳轉、填寫答案、提交等操作都非常穩健,可以填寫答案,程式碼完成後直接在Pyspider控制檯讓爬取任務running就可以了,比起按鍵精靈確實爽多了。
需要注意的是如果這個操作過長,Pyspider可能超時,對於過長的操作可能需要分次操作較好,就是Pyspider中多寫幾層crawl,後臺多處理幾次handle_post。
這裡貼出我使用的跳轉瀏覽器操作程式碼作參考,這段程式碼放在後臺selenium_fetcher的handle_post中即可:
# 訪問網頁
browser.get('https://xxxx')
browser.find_element_by_css_selector("[class='btn btn-primary select-csk']").click()
sleep(1)
browser.find_element_by_css_selector(".sprite.sprite-expand.i-20").click()
sleep(1)
# 進入試題頁面
for a in browser.find_elements_by_css_selector("[class='btn btn-round create-exercise']"):
if '13842' == a.get_attribute("data-keypoint-id"):
print(a.get_attribute("data-keypoint-id"))
a.click()
break
sleep(1)
# 交卷
browser.find_element_by_css_selector(".commit-exercise.last").click()
sleep(1)
try:
browser.find_element_by_css_selector(".btn.btn-paper.btn-paper-xlarge.submit").click()
except Exception as e:
print (e)
sleep(1)
# 進入答案頁面
browser.find_element_by_partial_link_text('檢視解析').click()
sleep(1)
設定cookies的程式碼,我的cookies直接在Pyspider中寫好了,所以需要獲取,然後再設定到selenium的瀏覽器中:
# 設定cookies
cookie_str = fetch['headers']['Cookies']
if fetch.get('headers') and cookie_str:
driver.delete_all_cookies()
for item in cookie_str.split('; '):
key = item.split('=')[0]
value = item.split('=')[1]
print(key+":"+value+'\n')
driver.add_cookie({'name': key, 'value': value})
遇到的比較印象深刻的問題:
-
selenium 進行設定cookie時出現 unable set cookie
解決方法:
需要先載入一個頁面才能進行add_cookies操作;
-
pyspider 多層的crawl時,有些頁面不爬取
解決方法:
回撥方法的age=0。因為如果回撥方法有一定時間的話,在時間內不會重複處理相同的url請求。