那些年我們一起寫過的Python爬蟲

来源:https://www.cnblogs.com/7758520lzy/archive/2020/03/05/12422271.html
-Advertisement-
Play Games

在一家能從業務里源源不斷產生數據的公司工作是一件很幸福的事情,但很多人如我就沒有這樣幸運。沒有數據又想蹭住人工智慧的風口,一種方法是潛心學術研究演算法,但用來做實驗的數據往往都是學術界或者一些好心的工業界提供的低配版數據,練就的屠龍刀倚天劍離實戰還有很多距離;另一種方法就是費盡心機尋找真實數據。在聊( ...


在一家能從業務里源源不斷產生數據的公司工作是一件很幸福的事情,但很多人如我就沒有這樣幸運。沒有數據又想蹭住人工智慧的風口,一種方法是潛心學術研究演算法,但用來做實驗的數據往往都是學術界或者一些好心的工業界提供的低配版數據,練就的屠龍刀倚天劍離實戰還有很多距離;另一種方法就是費盡心機尋找真實數據。在聊(已經學不動的)各種神乎其技的演算法之餘,我也想簡單總結下那些年我們寫爬蟲的經驗。

甄選網站

寫爬蟲之前先要從需求出發尋找合適的目標網站和數據源。

首先,能有API調用或者能從別的渠道買到的數據就儘量別再自己寫爬蟲了。除非目標網站的數據非常容易爬,否則寫爬蟲是一個非常繁瑣且需要長期鬥爭的體力活。從各個IT大廠的雲服務,到一些爬蟲起家的數據公司,甚至在某寶上面,都有大量的API或者數據的服務。首選API的服務因為一般數據提供商會按照API調用次數收費,配合API的query條件可以比較好滿足自己的特定需求,數據提供商一般也會保持數據更新;如果是直接買數據一開始報價中就要談好更新數據的後續報價。

幾個數據源的例子,比如百度數據開放平臺:

香港政府的資料一線通(更新很快,最新的冠狀病毒數據也已經傳在上面並且保持更新):

如果真的要自己寫爬蟲,那就要開始調研目標數據所在的網站。一般都會有多個網站提供目標數據,我們要挑看上去數據簡單排列整齊的(一個表格很多下一頁那種),排版看上去土土的(網頁代碼簡單好寫parser),沒有太多控制項,最好也不用賬戶登錄更不要沒事跳出一個驗證碼的那就是墜好的。越冷門的網站一般也越好,因為可能訪問量不高,網站管理者也不會設置太多的爬蟲限制。

業務方常常會提出比如去幾千個不同網站上去分別爬取信息的需求。這是不現實的,因為我們並不是谷歌或者百度這樣的搜索引擎,不同網站結構不一樣,意味著我們可能要分別寫幾千個爬蟲才能爬取所有的信息,更不要提之後的維護工作。最佳的情況是目標數據存在同一個網站內,網頁結構單一可以直接一次性爬取,後續維護工作也比較簡單。有時候我們也會爬兩到三個不同的網站然後做數據的cross validation,因為有的網站數據不見得是完整正確的,甚至一些網站檢測到爬蟲還會主動給你feed假數據…

爬蟲框架

市面上有多種不同的爬蟲框架可以選擇,不同的框架也可能基於java或者python等的不同語言。如scrapy這樣的爬蟲包已經將很多爬蟲功能如多線程並行爬取等打包實現。

當年自己寫爬蟲主要是python棧,簡單的流程就是使用selenium做框架,phantomJS做模擬瀏覽器拿到源代碼,然後用xpath或者beautifulSoup做網頁解析得到目標數據。解析前一般會用chrome的debug模式先直接在網頁中測試xpath的解析邏輯是否靠譜:

相應的爬蟲代碼教程很多,這裡不再啰嗦。

搏鬥經驗

寫完爬蟲代碼,把代碼跑起來,這才是一條爬蟲和目標網站搏鬥的剛剛開始…下麵是冰山一角的幾條經驗:

  1. 斷點續爬。這個很重要,因為你的網路很可能不穩定,中間爬蟲很可能會斷掉。如果每次斷掉都重頭開始爬數據可能永遠也爬不完,所以一定也寫好error handling也就是try exception的部分,connection error之類發生以後要及時等待重試而不是退出程式。

  2. 瀏覽器加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/'
                }
  3. 模擬登錄、隨機等待時間等等,這些都是為了模擬真實用戶的行為,防止激活網站的反爬蟲機制封殺掉你。

  4. 如果不幸你的ip被網站封殺了,就需要使用ip代理繼續爬取數據。實際上ip代理是爬蟲中非常重要的一環。有了大量代理ip就可以放心做多線程爬取,一個ip封掉可以自動及時替換為另一個ip。網上有一些免費的ip代理服務,但是速度和穩定性都不夠;一般推薦付費的ip代理服務如kuaidaili,會提供API直接調取和動態更新代理池,穩定度也會好很多。

  5. 爬蟲維護。網站改版、網址改動、新數據上線等都可能造成原先的爬蟲不再適用,加上目標網站的IT也會不斷更新反爬蟲策略,所以爬蟲維護是一個持久戰。

另一個障礙是很多網站為了防止爬蟲還會設置有驗證碼。不過道高一尺魔高一丈,我曾經也和各種驗證碼搏鬥過一些時間,而且這個經驗很有意思,我下麵單獨聊聊。

幹掉驗證碼

比較古舊的網站驗證碼往往是如下的樣子:

這種驗證碼的破解方式其實就是訓練一個OCR的模型去模擬人識別這些扭曲變形或者不同背景的文字。然後訓練一個針對某一種驗證碼的OCR系統是需要大量訓練數據訓練一個圖像識別模型的。莫非我們還要去大量爬取驗證碼圖片先?實際中大部分情況的做法是,通過觀察驗證碼的樣式,寫一些簡單的規則自己生成類似的驗證碼。比如調整字體,隨機做圖片扭曲,加一些橫豎的裂紋線,或者加上不同背景花紋和顏色等等。規則寫好,就相當於有一套系統可以隨機生成無限多的訓練數據,這樣就可以當作用如捲積網路這樣的模型,最後面一層是26個英文字母的分類,訓練出一個驗證碼識別的模型。

我們當年的實際情況是遇到了中文驗證碼,而且是中文或者成語,有時候還是數學公式:

這就大大加大了模型驗證的難度,因為漢字個數要遠遠大於英文字母的個數。不過對於成語來講,我們又單獨爬取了一個成語庫。這樣對於識別出來的四字中文如果有一兩個識別錯了,我們會計算相似度從成語庫中找到最相近的正確成語,這樣就大大提高了識別的準確度。

當我們的深度學習驗證碼識別系統完美工作,爬取了數天數據之後,我們發現網站忽然改版了。新的驗證碼變成了這樣:

要找到拼圖,然後拖動滑塊到拼圖的附近才可以成功。

於是我們再次用圖像處理的方法找到拼圖,卻發現如果只是直接模擬把滑塊拖過去依然會驗證失敗。我們找到了這家驗證碼服務的提供商,然後發現他們的文檔里說他們也使用了人工智慧技術來通過拖動滑塊的滑鼠軌跡和速度以及拼圖契合度來判斷是真人還是機器人…如果勻速直線拖過去然後完美契合拼圖也會悲劇。

於是我又用了將近一個月的時間研究如何模擬出完美的滑鼠軌跡來騙過驗證碼。當年的成果現在還在 github裡面躺著 ,有興趣的讀者可以去挖一下墳。那時候已經崩潰到考慮用強化學習Reinforcement Learning來做破解了…

現今的驗證碼已經基本到了神乎其技的階段了。以Google為例,居然在用驗證碼幫助收集圖像識別的標註數據,也是真的醉了…

總結

業務有數據最幸福請珍惜。沒數據想要爬數據,先做調研看看技術難度,情況不妙就找數據提供商,不要怕花錢因為自己開發和維護爬蟲的開銷很可能更大。真要自己硬杠開發爬蟲的話,請對時間、資金和腦力的投入做好充分的心理準備,可能開發過程把你逼成一個深度強化學習的AI大神也不一定…

爬蟲是一門可以非常艱深的任務,某種程度上也其實是如谷歌和百度這樣的搜索引擎的根基,網上也有很多的爬蟲工程大神。這篇文章只是分享自己曾經寫爬蟲的的些許經驗,希望能拋磚引玉(或是嚇走一批想要學習爬蟲的人…)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 函數只能面向過程,來回互相調用後順序執行, 簡單的編碼項目,還能應付的過來, 複雜的大型項目,調用多了,就會亂。 如何才能不亂呢,可嘗試下, 面向對象類的概念, 將現實世界的事物抽象成對象,將現實世界中事物的關係抽象成類, 即要秉著“萬物皆對象,一切皆可歸類”的中心思想, 去建立你的代碼模型。 一聽 ...
  • 輸入年份,列印出該年的日曆: #include <stdio.h> void PrintEnter(int mod); void PrintSkip(int lastday); void PrintTitle(int year,int month); int JudgeDays(int year, ...
  • 反射(二) 通過慄子來更好的理解反射,以及對反射技術進行應用。 首先,整兩個model——car.java和Benz.java 獲取反射類的幾種方法 反射——類的操作 反射——方法操作 反射——構造器操作 最後,要寫一個main方法,調用以上幾個方法,感受一下效果 ...
  • 一、與用戶交互 1、接收用戶的輸入 在Python3中,input會將用戶的所有輸入內容都存為字元串類型 在Python2中,用戶輸入什麼類型,就保存為什麼類型 # raw_input():用法與python3的input一模一樣# input(): 要求用戶必須輸入一個明確的數據類型,輸入的是什麼 ...
  • notebook:筆記本ipython notebook是anaconda中自帶的網頁編輯器jupyter notebook和ipython是一樣的:ipython是以前的名字,現在都使用jupyter在帶一個微型的伺服器:預設的路在/home/user——name​#在jupyter中,預設會輸出 ...
  • 一.前言 python 2.x版本中才有內置函數raw_input和input兩個函數; python 3.x版本中並沒有內置函數raw_input,如果在python 3.x版本中使用內置函數raw_input,會提示:NameError: name ‘raw_input’ is not defi ...
  • golang 自學系列(四)——(調試)VSCode For Debug 這裡如何裝 vscode 我就不說了 這裡如何在 vscode 正常寫代碼我也不說了 在能正常用 vscode 寫 go 語言的前提下(何為正常?就是寫代碼有智能提示的那種) 在 終端/cmd/iterm 輸出以下命令 在執行 ...
  • Docker Compose 前面我們使用 Docker 的時候,定義 Dockerfile 文件,然後使用 docker build、docker run 等命令操作容器。然而微服務架構的應用系統一般包含若幹個微服務,每個微服務一般都會部署多個實例,如果每個微服務都要手動啟停,那麼效率之低,維護量 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...