1. 程式人生 > >爬蟲爬蟲Pyspider+Selenium+Chrome

爬蟲爬蟲Pyspider+Selenium+Chrome

前言:

最近受林老闆之託需要爬取一些資料。想要簡單實現,看到Pyspider好像不錯,好的,就決定是你拉。

分析:

這次需要爬取的任務大致情況如下:

  1. 需要爬取某網站試題以及答案

  2. 試題以及答案最終會在同一個頁面上呈現

  3. 每次顯示有限的題數,例如20道題目,做完提交後可以看答案

  4. 需要進行答案填寫和提交,下次進入才會有新的題目出來

  5. 該網站最終連結是js非同步請求生成的

我需要的爬取流程也很簡單:

  1. 手工通過賬號密碼登入該網站,獲取登入後的cookies資訊

  2. 指令碼通過cookies登入該網站

  3. 一路跳轉到試題介面

  4. 填寫試題,提交,檢視題目和答案

  5. 解析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通常加密過,有一定難度,而且這樣工作量太大了。

臨時解決方法:

但老闆那邊催著要,先爬到要緊,想到了使用按鍵精靈獲取最終頁面的連結。

錄製滑鼠和鍵盤事件:

  1. 點選進入首頁,從首頁點選進入試題

  2. 進行提交,進入試題和答案頁

  3. 複製頁面連結

  4. 貼上到Pyspider程式碼中

  5. 點選除錯的run按鈕

不斷重複這個指令碼,資料就爬下來了。

這個方法雖然簡單,但是主要缺點也是很明顯:

  1. 按鍵指令碼難以重複使用,因為指令碼的滑鼠操作座標是根據螢幕的,它根本不知道網頁

  2. 不能後臺進行,這臺電腦就不能做其他事情了

  3. 效率慢

完善:

百度搜到參考文章:Pyspider使用Selenium+Chrome實現爬取js動態頁面  https://www.jianshu.com/p/8d955deac99b ,也很簡單,該大神的程式碼已經貼上,執行就可以了。

我這次需要的步驟也很明瞭了:

  1. 搭建Flask+Selenium+Chrome的後臺服務

  2. 通過該後臺服務處理頁面模擬點選事件,返回最終頁面

  3. 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})

遇到的比較印象深刻的問題:

  1. selenium 進行設定cookie時出現 unable set cookie

解決方法:

需要先載入一個頁面才能進行add_cookies操作;

  1. pyspider 多層的crawl時,有些頁面不爬取

解決方法:

回撥方法的age=0。因為如果回撥方法有一定時間的話,在時間內不會重複處理相同的url請求。