在一家能從業務里源源不斷產生數據的公司工作是一件很幸福的事情,但很多人如我就沒有這樣幸運。沒有數據又想蹭住人工智慧的風口,一種方法是潛心學術研究演算法,但用來做實驗的數據往往都是學術界或者一些好心的工業界提供的低配版數據,練就的屠龍刀倚天劍離實戰還有很多距離;另一種方法就是費盡心機尋找真實數據。在聊( ...
在一家能從業務里源源不斷產生數據的公司工作是一件很幸福的事情,但很多人如我就沒有這樣幸運。沒有數據又想蹭住人工智慧的風口,一種方法是潛心學術研究演算法,但用來做實驗的數據往往都是學術界或者一些好心的工業界提供的低配版數據,練就的屠龍刀倚天劍離實戰還有很多距離;另一種方法就是費盡心機尋找真實數據。在聊(已經學不動的)各種神乎其技的演算法之餘,我也想簡單總結下那些年我們寫爬蟲的經驗。
甄選網站
寫爬蟲之前先要從需求出發尋找合適的目標網站和數據源。
首先,能有API調用或者能從別的渠道買到的數據就儘量別再自己寫爬蟲了。除非目標網站的數據非常容易爬,否則寫爬蟲是一個非常繁瑣且需要長期鬥爭的體力活。從各個IT大廠的雲服務,到一些爬蟲起家的數據公司,甚至在某寶上面,都有大量的API或者數據的服務。首選API的服務因為一般數據提供商會按照API調用次數收費,配合API的query條件可以比較好滿足自己的特定需求,數據提供商一般也會保持數據更新;如果是直接買數據一開始報價中就要談好更新數據的後續報價。
幾個數據源的例子,比如百度數據開放平臺:
香港政府的資料一線通(更新很快,最新的冠狀病毒數據也已經傳在上面並且保持更新):
如果真的要自己寫爬蟲,那就要開始調研目標數據所在的網站。一般都會有多個網站提供目標數據,我們要挑看上去數據簡單排列整齊的(一個表格很多下一頁那種),排版看上去土土的(網頁代碼簡單好寫parser),沒有太多控制項,最好也不用賬戶登錄更不要沒事跳出一個驗證碼的那就是墜好的。越冷門的網站一般也越好,因為可能訪問量不高,網站管理者也不會設置太多的爬蟲限制。
業務方常常會提出比如去幾千個不同網站上去分別爬取信息的需求。這是不現實的,因為我們並不是谷歌或者百度這樣的搜索引擎,不同網站結構不一樣,意味著我們可能要分別寫幾千個爬蟲才能爬取所有的信息,更不要提之後的維護工作。最佳的情況是目標數據存在同一個網站內,網頁結構單一可以直接一次性爬取,後續維護工作也比較簡單。有時候我們也會爬兩到三個不同的網站然後做數據的cross validation,因為有的網站數據不見得是完整正確的,甚至一些網站檢測到爬蟲還會主動給你feed假數據…
爬蟲框架
市面上有多種不同的爬蟲框架可以選擇,不同的框架也可能基於java或者python等的不同語言。如scrapy這樣的爬蟲包已經將很多爬蟲功能如多線程並行爬取等打包實現。
當年自己寫爬蟲主要是python棧,簡單的流程就是使用selenium做框架,phantomJS做模擬瀏覽器拿到源代碼,然後用xpath或者beautifulSoup做網頁解析得到目標數據。解析前一般會用chrome的debug模式先直接在網頁中測試xpath的解析邏輯是否靠譜:
相應的爬蟲代碼教程很多,這裡不再啰嗦。
搏鬥經驗
寫完爬蟲代碼,把代碼跑起來,這才是一條爬蟲和目標網站搏鬥的剛剛開始…下麵是冰山一角的幾條經驗:
-
斷點續爬。這個很重要,因為你的網路很可能不穩定,中間爬蟲很可能會斷掉。如果每次斷掉都重頭開始爬數據可能永遠也爬不完,所以一定也寫好error handling也就是try exception的部分,connection error之類發生以後要及時等待重試而不是退出程式。
-
瀏覽器加header。這個也很重要,因為很多時候如果網站伺服器發現你明顯是一個headless的爬蟲瀏覽器會即刻拒絕掉你的網路請求。一個典型的header如下:
{'Accept': '*/*', 'Accept-Language': 'en-US,en;q=0.8', 'Cache-Control': 'max-age=0', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36', 'Connection': 'keep-alive', 'Referer': 'http://www.baidu.com/' }
-
模擬登錄、隨機等待時間等等,這些都是為了模擬真實用戶的行為,防止激活網站的反爬蟲機制封殺掉你。
-
如果不幸你的ip被網站封殺了,就需要使用ip代理繼續爬取數據。實際上ip代理是爬蟲中非常重要的一環。有了大量代理ip就可以放心做多線程爬取,一個ip封掉可以自動及時替換為另一個ip。網上有一些免費的ip代理服務,但是速度和穩定性都不夠;一般推薦付費的ip代理服務如kuaidaili,會提供API直接調取和動態更新代理池,穩定度也會好很多。
-
爬蟲維護。網站改版、網址改動、新數據上線等都可能造成原先的爬蟲不再適用,加上目標網站的IT也會不斷更新反爬蟲策略,所以爬蟲維護是一個持久戰。
另一個障礙是很多網站為了防止爬蟲還會設置有驗證碼。不過道高一尺魔高一丈,我曾經也和各種驗證碼搏鬥過一些時間,而且這個經驗很有意思,我下麵單獨聊聊。
幹掉驗證碼
比較古舊的網站驗證碼往往是如下的樣子:
這種驗證碼的破解方式其實就是訓練一個OCR的模型去模擬人識別這些扭曲變形或者不同背景的文字。然後訓練一個針對某一種驗證碼的OCR系統是需要大量訓練數據訓練一個圖像識別模型的。莫非我們還要去大量爬取驗證碼圖片先?實際中大部分情況的做法是,通過觀察驗證碼的樣式,寫一些簡單的規則自己生成類似的驗證碼。比如調整字體,隨機做圖片扭曲,加一些橫豎的裂紋線,或者加上不同背景花紋和顏色等等。規則寫好,就相當於有一套系統可以隨機生成無限多的訓練數據,這樣就可以當作用如捲積網路這樣的模型,最後面一層是26個英文字母的分類,訓練出一個驗證碼識別的模型。
我們當年的實際情況是遇到了中文驗證碼,而且是中文或者成語,有時候還是數學公式:
這就大大加大了模型驗證的難度,因為漢字個數要遠遠大於英文字母的個數。不過對於成語來講,我們又單獨爬取了一個成語庫。這樣對於識別出來的四字中文如果有一兩個識別錯了,我們會計算相似度從成語庫中找到最相近的正確成語,這樣就大大提高了識別的準確度。
當我們的深度學習驗證碼識別系統完美工作,爬取了數天數據之後,我們發現網站忽然改版了。新的驗證碼變成了這樣:
要找到拼圖,然後拖動滑塊到拼圖的附近才可以成功。
於是我們再次用圖像處理的方法找到拼圖,卻發現如果只是直接模擬把滑塊拖過去依然會驗證失敗。我們找到了這家驗證碼服務的提供商,然後發現他們的文檔里說他們也使用了人工智慧技術來通過拖動滑塊的滑鼠軌跡和速度以及拼圖契合度來判斷是真人還是機器人…如果勻速直線拖過去然後完美契合拼圖也會悲劇。
於是我又用了將近一個月的時間研究如何模擬出完美的滑鼠軌跡來騙過驗證碼。當年的成果現在還在 github裡面躺著 ,有興趣的讀者可以去挖一下墳。那時候已經崩潰到考慮用強化學習Reinforcement Learning來做破解了…
現今的驗證碼已經基本到了神乎其技的階段了。以Google為例,居然在用驗證碼幫助收集圖像識別的標註數據,也是真的醉了…
總結
業務有數據最幸福請珍惜。沒數據想要爬數據,先做調研看看技術難度,情況不妙就找數據提供商,不要怕花錢因為自己開發和維護爬蟲的開銷很可能更大。真要自己硬杠開發爬蟲的話,請對時間、資金和腦力的投入做好充分的心理準備,可能開發過程把你逼成一個深度強化學習的AI大神也不一定…
爬蟲是一門可以非常艱深的任務,某種程度上也其實是如谷歌和百度這樣的搜索引擎的根基,網上也有很多的爬蟲工程大神。這篇文章只是分享自己曾經寫爬蟲的的些許經驗,希望能拋磚引玉(或是嚇走一批想要學習爬蟲的人…)