1. 程式人生 > >網路爬蟲設計中需要注意的幾個問題us時時彩原始碼五合一盤口藍色版本 親測功能完美運營版

網路爬蟲設計中需要注意的幾個問題us時時彩原始碼五合一盤口藍色版本 親測功能完美運營版

我是通過看「靜覓」上的文章接觸爬蟲的。作者最近還寫了本書「Python3網路爬蟲開發實戰 」,算是現在市面上比較系統的爬蟲書籍了。我也寫點東西總結一下做爬蟲過程中遇到的主要問題,希望對沒有接觸過的同學有參考意義,也希望老鳥們幫忙看看路子是否正確。本文主要是為了釐清爬蟲執行的思路,不會涉及太多的具體程式碼。

「網路爬蟲」又叫網路蜘蛛,實際上就是一種自動化的網路機器人,代替了人工來獲取網路上的資訊。所以只要復原使用者獲取網路資訊的步驟,就能夠釐清爬蟲執行的整個脈絡。

網址管理

第一種策略稱為「廣度優先」,第二種策略稱為「深度優先」。實際使用過程中一般是採用廣度優先的策略。我們先從入口返回的資料中拿到我們感興趣的 URL,放到一個列表中,每爬取完一個 URL,就把它放到已完成的列表中。對於異常的,另外作標記後續處理。

實際上最簡單的爬蟲只作一件事:訪問地址,獲取資料。 當要訪問的地址變得很多時,成立一個 URL 管理器,對所有需要處理的 URL 作標記。當邏輯不復雜的時候可以使用陣列等資料結構,邏輯複雜的時候使用資料庫進行儲存。資料庫記錄有個好處是當程式意外掛掉以後,可以根據正在處理的 ID 號繼續進行,而不需要重新開始,把之前已經處理過的 URL 再爬取一遍。以 Python3 為例,編寫以下虛擬碼:

def main():
    root_url = 'https://www.cnblogs.com'
    res = get_content(root_url)
    first_floor_urls = get_wanted_urls(res)

    for
url in first_floor_urls: res_url = get_content(url) if sth_wrong(res_url): put_to_error_list(url) else: sencond_floor_urls = get_wanted_urls(res_url) # rest of the code if __name__ == '__main__': main()

什麼語言可以做爬蟲

雖然我會的語言不多,但是我相信任何語言,只要他具備訪問網路的標準庫,都可以很輕易的做到這一點。剛剛接觸爬蟲的時候,我總是糾結於用 Python 來做爬蟲,現在想來大可不必,無論是 JAVA,PHP 還是其他更低階語言,都可以很方便的實現,靜態語言可能更不容易出錯,低階語言執行速度可能更快,Python 的優勢在於庫更豐富,框架更加成熟,但是對於新手來說,熟悉庫和框架實際上也要花費不少時間。

比如我接觸的 Scrapy,配環境就配了兩天,對於裡面複雜的結構更是雲裡霧裡,後來我果斷放棄了,任何爬蟲我都只使用幾個簡單的庫來實現,雖然耗費了很多時間,但是我對整個 HTTP 流程有了更深的理解。我認為:

在沒有搞清楚設計優勢的時候盲目的學習框架是阻礙技術進步的。

在我剛轉行學習 Python 的那段時間,我每天都花很多時間在社群裡去讀那種比較 Flask,Django,Tornado 甚至是 Bottom,Sanic 這樣的文章。這些文章很多都寫得非常好,我也從中學到了很多知識,我知道了 Flask 勝在靈活,Django 更大更全面等等。

可是說真的,這浪費了我很多時間。新手總是有一種傾向,花費巨大的精力去尋找那些一勞永逸的方法,語言和框架,妄想只要學了這個,以後長時間就可以高枕無憂,面對各種挑戰。如果要我重來一次,我會選擇看一兩篇這種優質的比較文章,然後大膽的選用其中一種主流的框架,在不重要的學習專案中嘗試其他的框架,用了幾次自然而然就會發現他們的優劣。

現在我還發現這種傾向不僅在新手中存在,老鳥也有很多患有這種技術焦慮症。他們看到媒體鼓吹 Go 語言和 Assembly,大家都在討論微服務和 React Native,也不知所以的加入。但是有的人還是真心看懂了這些技術的優勢,他們在合適的場景下進行試探性的嘗試,然後步步為營,將這些新技術運用到了主要業務中,我真佩服這些人,他們不焦不燥熱的引領著新技術,永遠都不會被新技術推著走。

解析資料

本來應該叫解析網頁,但是因為現在大多數資料都是在移動端,所以叫解析資料應該更合適。解析資料是說當我訪問一個網址,伺服器返回內容給了我,我怎麼把我需要的資料提取出來。當伺服器返回給我的是 HTML 時,我需要提取到具體哪個 DIV 下面的內容;當伺服器返回給我的是 XML 時,我也需要提取某個標籤下面的內容。

最原始的辦法是使用「正則表示式」,這是門通用的技術,應該大多數語言都有類似的庫吧,在 Python 中對應的是 re 模組,不過正則表示式非常難於理解,不到萬不得已我真不想使用。Python 中的 BeautifulSoup 和 Requests-HTML 非常適合通過標籤進行內容提取。

應對反爬蟲策略

爬蟲對於伺服器是一種巨大的資源負荷,想象一下,你從雲服務商那裡買了個 30 塊錢一個月的虛擬雲伺服器,搭建了一個小型的部落格用於分享自己的技術文章。你的文章非常優質,很多人慕名來訪問,於是伺服器的響應速度變慢了。有些人開始做爬蟲來訪問你的部落格,為了做到實施更新,這些爬蟲每秒鐘都要瘋狂的訪問幾百次,這時候可能你的部落格再也沒人能成功獲取到內容了。

這時候你就必須想辦法遏制爬蟲了。伺服器遏制爬蟲的策略有很多,每次 HTTP 請求都會帶很多引數,伺服器可以根據引數來判斷這次請求是不是惡意爬蟲。

比如說 Cookie 值不對,Referer 和 User-Agent 不是伺服器想要的值。這時候我們可以通過瀏覽器來實驗,看哪些值是伺服器能夠接受的,然後在程式碼裡修改請求頭的各項引數偽裝成正常的訪問。

除了固定的請求頭引數,伺服器可能還會自定義一些引數驗證訪問是否合法,這種做法在 app 端尤其常見。伺服器可能要求你利用時間戳等一系列引數生成一個 key 傳送給伺服器,伺服器會校驗這個 key 是否合法。這種情況需要研究 key 的生成,如果不行乾脆用模擬瀏覽器以及虛擬機器來完全冒充使用者。

伺服器還會限制 IP,限制 IP 的訪問速度。比如我用 IP 為 45.46.87.89 的機器訪問伺服器,伺服器一旦自認為我是爬蟲,會立刻加入黑名單,下一次起我的訪問就完全無效了。絕大多數的 IP 限制都不會有這麼嚴格,但是限制訪問速度是很常見的,比如伺服器規定 1 個小時以內,每個 IP 只能訪問 40 次。

這要求爬蟲設計者要注意兩件事:

  • 珍惜伺服器資源,不要太暴力的獲取伺服器資源
  • 時刻注意 IP 代理池的設計

設計太快的訪問速度是一種不道德的行為,不應該受到任何鼓勵,伺服器在受到爬蟲暴力訪問後可能會將迅速反應,將反爬蟲策略設計得更加嚴格,因此我從來不將爬蟲的速度設計得太快,有時候會延時 1 分鐘再做下一次爬取,我始終認為免費獲取別人的內容也應該珍惜。

在設計爬蟲的時候不要忘記隱藏自己的真實 IP 來保護自己。IP 代理池是每一次訪問都換不同的 IP,避免被伺服器封掉。網上有很多免費的代理池,可以做個爬蟲爬取下來儲存備用。也有很多現成的庫比如 proxy_pool 就非常好用,安裝完成以後訪問本地地址就可以獲取到可以用的 IP 列表。

爬蟲和反爬蟲會長時間鬥志鬥勇,除了上述問題還會遇到其他問題,比如說驗證碼設定。不同的驗證碼有不同的處理方式,常見的應對策略有買付費的驗證服務,影象識別等。

其他具體的問題可以使用「抓包工具」去分析,比較常用的抓包工具有 charles 和 Fiddler,使用也很簡單,搜教程看幾分鐘就會了。命令列我用過 mitmproxy,名字非常高大上,「中間人攻擊」。我還嘗試了 Wireshark,這個操作起來複雜得多,不過整個訪問流程都不放過,不愧是學習 HTTP 的利器,有精力應該看一下 『網路是怎樣連結的』和『WireShark網路分析就這麼簡單』這兩本書,對理解網路訪問非常有幫助。

抓包工具非常有用,不僅可以用來做爬蟲分析,還可以用做網路攻防練習。我曾經用 Fiddler 發現了一個主流健身軟體的很多漏洞,不過很快被他們發現了,他們通知我通過他們官方的渠道提交漏洞會有獎勵,我照做了,不過沒有得到他們的任何獎勵和回覆。可見,大公司也並不都靠譜。

模擬器

設計爬蟲還需要注意一個非常殘酷的現狀:Web 端越來越 JS 化,手機端 key 值校驗越來越複雜以致無法破解。這時候只能選擇模擬器來完全假扮成使用者了。

網頁端常見的模擬瀏覽器工具有 Selenium,這是一個自動化測試工具,它可以控制瀏覽器作出點選,拖拉等動作,總之就是代替人來操作瀏覽器,通常搭配 PhantomJS 來使用。

PhantomJS 是一個基於WebKit的伺服器端 JavaScript API,它基於 BSD開源協議釋出。PhantomJS 無需瀏覽器的支援即可實現對 Web 的支援,且原生支援各種Web標準,如DOM 處理、JavaScript、CSS選擇器、JSON、Canvas 和可縮放向量圖形SVG。不過目前好像已經停止維護啦。

不過沒關係,Selenium 同樣可以操作 FireFox 和 Chrome 等瀏覽器。如果有需要再學不遲。

除了 web 端,手機端 APP 也可以使用模擬器技術來完全模擬人的動作。我使用過 uiautomator,另外還有 Appium 非常強大,我暫時還沒用過。

當需要併發的時候,我們手頭上沒有足夠多的真機用來爬取,就要使用 genymotion 這樣的虛擬機器,使用起來跟 linux 虛擬機器是一樣的,下載安裝包配置就可以了。

爬蟲的併發和分散式

Python 作併發爬蟲實際上毫無優勢,不過如之前所講,太高併發的爬蟲對別人的伺服器影響太大了,聰明的人不可能不作限制,所以高併發語言實際上優勢也不大。Python 3.6 以後非同步框架 Aiohttp 配合 async/await 語法也非常好用的,能在效率上提升不少。

至於分散式問題,我還沒有好好研究,我做的大多數爬蟲還達不到這個級別。我用過分散式儲存,mongodb 配個叢集不是很難。

總結

爬蟲說起來是件簡單的事情。但是往往簡單的事情要做到極致就需要克服重重困難。要做好一個爬蟲我能想到的主要事項有:

  • URL 的管理和排程。聰明的設計往往容錯性很高,爬蟲掛掉以後造成的損失會很小。
  • 資料解析。多學點正則表示式總是好事情,心裡不慌。
  • 限制反爬蟲策略。要求對 HTTP 有一定的理解,最好系統的學習一下。
  • 模擬器。這樣做的效率有點低,而且電腦不能做其他事情。

我非常喜歡設計爬蟲,以後我會嘗試設計個通用性質的爬蟲。這篇文章沒有寫具體的程式碼,因為我看到網上的原始碼都非常好懂,我就不做重複的事情了。我學爬蟲的時候收集了幾個,是 Python 的,如果你感興趣,可以找我索要。