寫爬蟲絕對不要太客氣也不可以心軟

尤其是要爬像是 Facebook 這種蓄意想要鎖住資訊,把 Internet 變成一個巨大內網的邪惡公司的時候。

之前在 Github 看到 rss-bridge 這個專案,用爬蟲去爬網頁然後產生 RSS/Atom feed ,原本是想要把它用在 Facebook 上面,這樣就可以訂閱粉專的每一篇貼文、照時間排序、不用被 Facebook 的 filter bubble 審查資訊,也不會因為你訂閱什麼就汙染你的 stream 。

架起來試了一下發現效果還不錯,訂閱了一堆粉專就去睡了。

結果隔天早上醒來發現所有 feed 都失效,因為 Facebook 要求 Captcha 驗證。原本的 rss-bridge 會把驗證圖片 proxy 顯示給瀏覽 feed 的使用者,使用者可以解完之後送出,rss-bridge 會再送給 Facebook ,但這功能實測的時候發現無論如何送出都會失敗,把這 bug 解掉之後又發現 captcha 只會當次有效,也就是要發另一個 request 的時候又會被跳 captcha 。

自己開瀏覽器測試了一下發現,瀏覽器的 captcha 只要解一次,未來的 request 就都會過,想說大概是因為 rss-bridge 的爬蟲不支援 cookie 的問題,所以就花了好幾天時間把 rss-bridge 的爬蟲換成 PHP curl (原本是用 file_get_contents() ),因為 PHP curl 有 cookie jar 的功能,管理 cookie 比較方便。

結果新的 code 終於會動,但儘管送了 cookie 還是每次被跳 captcha ,挖到底層去測試了很多東西,檢查 request header 和 response header ,確定不是我實作有問題之後,我發現問題不在 cookie。

問題在於 rss-bridge 的爬蟲預設都會多送一個 GET 參數 _fb_noscript=1 ,有這個參數的時候顯示出來的 captcha 會不一樣!

_fb_noscript=1 的時候顯示的 captcha 會直接是一個 <img src="..."> ,而且這個 captcha 也只有單次有效!下次再請求,就算有 cookie, 也會再被要求解另一個 captcha 。

沒有那個參數的時候的 captcha 圖片會使用 AJAX 載入,然後解開之後設定的 cookie 也會多次有效。

我拿舊的實作改成 curl 的時候沒有特別改這個東西,結果到現在才發現這件事。

所以,這次學到的教訓是,寫爬蟲的時候,不要仁慈,直接開 PhantomJS/CasperJS 吧……

P.S. 我改過的 rss-bridge 在這兒: https://github.com/pellaeon/rss-bridge/tree/enhance

更新:不想用 Javascript 的話 Python 的 Scrapy + Splash (Splash 是 headless browser)看起來還不錯(沒用過)。還有 django-dynamic-scraper 可以直接把爬到的東西結構化成 Django model object ,每一個 field 直接關聯一個 selector ,scrape 的時候讀進去,太神啦。

2017/2/24 更新2:後來又繼續試著解決這個問題。研究了一下 django-dynamic-scraper , 幾乎找不到如何處理 captcha 的說明和範例,雖然說應該是可以解但是感覺又要研究 scrapy 很久,所以還是決定回去幫 rss-bridge 加上 proxy 的功能。改出來的東西在 https://github.com/pellaeon/rss-bridge/tree/enhance2 。然後還花了一些心力研究要怎麼取得免費的 proxy 清單,最後發現 HideMyAss.com 的不錯,寫了個小小的 Javascript 去撈 proxy 清單

One thought on “寫爬蟲絕對不要太客氣也不可以心軟

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s