如何應對網站反爬蟲策略?如何高效地爬大量數據?

像一些大型的網站會有反爬蟲策略…比如我之前在爬淘寶評論後很快就會被封,大概是短時間爬太多…有什麼好的策略嗎?比如代理?不過感覺代理也不能穩定吧…


爬蟲(Spider),反爬蟲(Anti-Spider),反反爬蟲(Anti-Anti-Spider),這之間的鬥爭恢宏壯闊...

Day 1
小莫想要某站上所有的電影,寫了標準的爬蟲(基於HttpClient庫),不斷地遍歷某站的電影列表頁面,根據 Html 分析電影名字存進自己的資料庫。
這個站點的運維小黎發現某個時間段請求量陡增,分析日誌發現都是 IP(1.1.1.1)這個用戶,並且 useragent 還是 JavaClient1.6 ,基於這兩點判斷非人類後直接在Nginx 伺服器上封殺。

Day 2
小莫電影只爬了一半,於是也針對性的變換了下策略:1. useragent 模仿百度("Baiduspider..."),2. IP每爬半個小時就換一個IP代理。
小黎也發現了對應的變化,於是在 Nginx 上設置了一個頻率限制,每分鐘超過120次請求的再屏蔽IP。 同時考慮到百度家的爬蟲有可能會被誤傷,想想市場部門每月幾十萬的投放,於是寫了個腳本,通過 hostname 檢查下這個 ip 是不是真的百度家的,對這些 ip 設置一個白名單。

Day 3
小莫發現了新的限制後,想著我也不急著要這些數據,留給伺服器慢慢爬吧,於是修改了代碼,隨機1-3秒爬一次,爬10次休息10秒,每天只在8-12,18-20點爬,隔幾天還休息一下。
小黎看著新的日誌頭都大了,再設定規則不小心會誤傷真實用戶,於是準備換了一個思路,當3個小時的總請求超過50次的時候彈出一個驗證碼彈框,沒有準確正確輸入的話就把 IP 記錄進黑名單。

Day 4
小莫看到驗證碼有些傻臉了,不過也不是沒有辦法,先去學習了圖像識別(關鍵詞 PIL,tesseract),再對驗證碼進行了二值化,分詞,模式訓練之後,識別了小黎的驗證碼(關於驗證碼,驗證碼的識別,驗證碼的反識別也是一個恢弘壯麗的鬥爭史,這裡先不展開....),之後爬蟲又跑了起來。
小黎是個不折不撓的好同學,看到驗證碼被攻破後,和開發同學商量了變化下開發模式,數據並不再直接渲染,而是由前端同學非同步獲取,並且通過 js 的加密庫生成動態的 token,同時加密庫再進行混淆(比較重要的步驟的確有網站這樣做,參見微博的登陸流程)。

Day5
混淆過的加密庫就沒有辦法了么?當然不是,可以慢慢調試,找到加密原理,不過小莫不準備用這麼耗時耗力的方法,他放棄了基於 HttpClient的爬蟲,選擇了內置瀏覽器引擎的爬蟲(關鍵詞:PhantomJS,Selenium),在瀏覽器引擎中js 加密腳本算出了正確的結果,又一次拿到了對方的數據。
小黎:.....

爬蟲與發爬蟲的鬥爭還在繼續。
不過實際應用時候,一般大家做到根據 IP 限制頻次就結束了,除非很核心的數據,不會再進行更多的驗證,畢竟工程的問題一半是成本的問題。

至於高效部分,一些 Tips:
1.盡量減少請求次數,能抓列表頁就不抓詳情頁
2.不要只看 Web 網站,還有 App 和 H5,他們的反爬蟲措施一般比較少
3.如果真的對性能要求很高,可以考慮多線程(一些成熟的框架如 scrapy都已支持),甚至分散式

另外,想深入研究爬蟲/反爬蟲的同學,可以把簡歷發過來: shenyubao&http://souche.com ,本廣告長期有效。

====
2016.1.3 修改幾處 spider 拼寫錯誤,感謝 @Danilo


關於反爬蟲是如何做的,昨晚剛好寫了一個回答(時間原因還沒有寫完),鏈接如下:當爬蟲不遵守 robots 協議時,有沒有防止抓取的可能? - xlzd 的回答

作者:xlzd
鏈接:當爬蟲不遵守 robots 協議時,有沒有防止抓取的可能? - xlzd 的回答
來源:知乎
著作權歸作者所有,轉載請聯繫作者獲得授權。

先說結論:在爬蟲與反爬蟲的對弈中,爬蟲一定會勝利。換言之,只要人類能夠正常訪問的網頁,爬蟲在具備同等資源的情況下就一定可以抓取到。

robots.txt 只是約定,爬蟲遵守或者不遵守完全在於爬蟲作者的意願。舉個例子,公交車上貼著「請為老弱病殘孕讓座」,但是大部分人並不見得會遵守。一般來講,只有大的搜索引擎爬蟲會遵守你網站的 robots.txt 協議,其它的爬蟲基本都不會看一眼你的 robots.txt 寫的是什麼。

大部分情況下,反爬蟲的需求是不能影響到網站正常使用的,一個網站的功能性需求一定高於反爬蟲需求,所以大部分網站反爬蟲一定不會噁心到正常用戶的使用。比如豆瓣電影的電影詳情頁是 「https://movie.douban.com/subject/26266072/」,其中可變部分為後面代表每部電影的數字編號,豆瓣絕不會為了反爬蟲將網頁 URL 結構替換成淘寶的 URL 那樣複雜。同理百度也一定不會要求你每次訪問就輸入一個驗證碼,來確認你是人類而不是機器。所以這裡首先需要明確一個概念就是:只能儘可能加大爬蟲抓取數據的代價,而不可能做到百分之百防止爬蟲

----------------
那麼,如何加大爬蟲的抓取難度呢?下面根據自己做 Anti-Spider 的一點經驗,胡說幾句吧。

首先,最簡單的方式便是校驗 User-Agent。校驗 User-Agent 其實並不能起到反爬蟲的作用,因為幾乎所有寫爬蟲的人,看到的前三篇教程里,就會有一篇講到要模擬 User-Agent。除了 User-Agent,所有通過 HTTP 請求傳遞到伺服器的客戶端參數都不能完全當做反爬蟲的依據,因為模擬和偽造的成本太低了

然後,一個比較常見的反爬蟲策略是基於訪問數量,爬蟲的訪問總數會遠高於人類,設定一個閾值,超過閾值的就是爬蟲。常見使用這樣處理方式的網站有 58 同城等,在訪問 58 同城較快時,會彈出一個驗證碼。然而只要有規律的 sleep,就可以輕鬆繞過這條限制。

這種處理方案的升級版是找到人與爬蟲訪問特徵的不一致究竟在哪裡。爬蟲與人類在訪問特徵上最大的不一樣在於,人不會長時間持續訪問一個網站,正常人類在天級的時間周期里訪問一個網站的總次數 y 大致滿足——
y = k*x^{a}  (0< a < 1, k > 0)

我們不關心 k、a 的值具體是什麼,但是比較明顯的是,一個正常用戶訪問會在較短時間裡完成某一時間周期的總請求數的絕大部分。映射到總用戶上,確定的一段時間裡,正常用戶訪問的總頁數會在某個量級時開始驟減。
而爬蟲訪問一個網站的總次數 y 與某個時間周期的關係則大致為——
y = k*x(k > 0)

其實就是,爬蟲的訪問數量會隨著時間增長而線性增長。於是,根據這樣的特點,可以參考人類社會的個人所得稅制度或者階梯電價制度,對於一個較短周期設置比較寬的閾值,而隨著時間長度的增加而逐步收緊閾值。當然,具體的閾值設置為多少合適,要根據特定網站的日誌分析之後得出具體數據。

到這裡,很多爬蟲已經會開始表現的精力不足了。大部分爬蟲會直接命中短時間的策略被封,那些 sleep 一下的爬蟲,在爬取一段時間之後,依然會命中中長時間的策略。如果再 sleep,抓取的效率太低,成本與收益不成正比,自然就不會再抓了。

對應的,爬蟲的開發者會想辦法繼續反反爬蟲。常見的方案是通過代理 IP 和批量註冊的賬號。那些大規模抓取數據的爬蟲,為了能夠長時間抓取數據,一般是不會跑在個人電腦上的,而是通過雲伺服器或者 VPS。再進一步的識別爬蟲,則可以根據來訪 IP 的風險屬性進一步識別。一般需要這樣處理的話,都是一些中大型的商業網站了。個人網站一來沒必要,二是沒有精力,一般不會更進一步反爬蟲了。

-----------------
最後,再最後水一下不再更新的破爬蟲相關博客:

  • 爬蟲必備——requests
  • 01. 準備
  • 02. 簡單的嘗試
  • 番外篇. 搭建稱手的Python開發環境
  • 03. 豆瓣電影TOP250
  • 04. 另一種抓取方式
  • 05. 存儲
  • 06. 海量數據的抓取策略
  • 07. 反爬機制&<1&>
  • 08. 模擬登錄
  • 09. 通過爬蟲找出我和輪子哥之間的最短關注鏈

  • 看了回答區,基本的反爬蟲策略都提到了,下面說幾個作為補充。

    1、對於處理驗證碼,爬蟲爬久了通常網站的處理策略就是讓你輸入驗證碼驗證是否機器人,此時有三種解決方法:

    • 第一種把驗證碼down到本地之後,手動輸入驗證碼驗證,此種成本相對較高,而且不能完全做到自動抓取,需要人為干預。
    • 第二種圖像識別驗證碼,自動填寫驗證,但是現在的情況是大部分驗證碼雜訊較多複雜度大,對於像我這樣對圖像識別不是很熟悉的人很難識別出正確的驗證碼。
    • 第三種也是最實用的一種,接入自動打碼平台,個人感覺比上兩種方法好些。

    2、多賬號反爬,有很多的網站會通過同一個用戶單位時間內操作頻次來判斷是否機器人,比如像新浪微博等網站。這種情況下我們就需要先測試單用戶抓取閾值,然後在閾值前切換賬號其他用戶,如此循環即可。當然,新浪微博反爬手段不止是賬號,還包括單ip操作頻次等。

    3、分散式爬蟲,分散式能在一定程度上起到反爬蟲的作用,當然相對於反爬蟲分散式最大的作用還是能做到高效大量的抓取。

    4、保存cookies,記錄用戶的狀態,在模擬登陸十分麻煩的情況下,我們不妨直接在web上登陸之後取下cookie並保存然後帶上cookie做爬蟲,但這不是長久的方法,而且cookie隔一段時間可能失效。有的網站會根據cookie中的一些值去判斷是否機器人,這個需要自己不斷測試,比如豆瓣。

    5、注意配合移動端、web端以及桌面版,其中web端包括m站即手機站和pc站,往往是pc站的模擬抓取難度大於手機站,所以在m站和pc站的資源相同的情況下優先考慮抓取m站。同時如果無法在web端抓取,不可忽略在app以及桌面版的也可以抓取到目標數據資源。

    應對反爬蟲的策略,首先要發現網站的反爬蟲手段是什麼?這個發現的過程就是不斷測試的過程,有點類似於A/B測試,弄清楚它的反爬蟲機制,就成功了一大半了。

    很多人問我如何學習Python爬蟲,為此我整理編寫了一本Python爬蟲相關的電子書,主要包括Python入門、Python爬蟲入門到進階、Python爬蟲面試總結等等。可以在微信公眾號【一個程序員的日常】後台回復關鍵詞【1】獲取這本電子書。


    「爬」,本身就是一種對抗行為。
    要盡量隱匿自己的行為,方法論很多不細講了,沒有屠龍之技。
    最重要的是不能影響對方運維的 KPI ,不能嚴重到對方研發介入。碼農都是混口飯過日子的,都不容易,逼的對方加班升級加策略的最終碼農和產品經理去PK 直接就把功能下線了。


    Python入門網路爬蟲之精華版

    Python學習網路爬蟲主要分3個大的版塊:抓取分析存儲

    另外,比較常用的爬蟲框架Scrapy,這裡最後也詳細介紹一下。

    首先列舉一下本人總結的相關文章,這些覆蓋了入門網路爬蟲需要的基本概念和技巧:寧哥的小站-網路爬蟲

    當我們在瀏覽器中輸入一個url後回車,後台會發生什麼?比如說你輸入寧哥的小站專註數據挖掘、機器學習方向。,你就會看到寧哥的小站首頁。

    簡單來說這段過程發生了以下四個步驟:

    • 查找域名對應的IP地址。
    • 向IP對應的伺服器發送請求。
    • 伺服器響應請求,發回網頁內容。
    • 瀏覽器解析網頁內容。

    網路爬蟲要做的,簡單來說,就是實現瀏覽器的功能。通過指定url,直接返回給用戶所需要的數據,而不需要一步步人工去操縱瀏覽器獲取。

    抓取

    這一步,你要明確要得到的內容是什麼?是HTML源碼,還是Json格式的字元串等。

    1. 最基本的抓取

    抓取大多數情況屬於get請求,即直接從對方伺服器上獲取數據。

    首先,Python中自帶urllib及urllib2這兩個模塊,基本上能滿足一般的頁面抓取。另外,requests也是非常有用的包,與此類似的,還有httplib2等等。

    Requests:
    import requests
    response = requests.get(url)
    content = requests.get(url).content
    print "response headers:", response.headers
    print "content:", content
    Urllib2:
    import urllib2
    response = urllib2.urlopen(url)
    content = urllib2.urlopen(url).read()
    print "response headers:", response.headers
    print "content:", content
    Httplib2:
    import httplib2
    http = httplib2.Http()
    response_headers, content = http.request(url, "GET")
    print "response headers:", response_headers
    print "content:", content

    此外,對於帶有查詢欄位的url,get請求一般會將來請求的數據附在url之後,以?分割url和傳輸數據,多個參數用連接。

    data = {"data1":"XXXXX", "data2":"XXXXX"}
    Requests:data為dict,json
    import requests
    response = requests.get(url=url, params=data)
    Urllib2:data為string
    import urllib, urllib2
    data = urllib.urlencode(data)
    full_url = url+"?"+data
    response = urllib2.urlopen(full_url)

    相關參考:網易新聞排行榜抓取回顧

    參考項目:網路爬蟲之最基本的爬蟲:爬取網易新聞排行榜

    2. 對於登陸情況的處理

    2.1 使用表單登陸

    這種情況屬於post請求,即先向伺服器發送表單數據,伺服器再將返回的cookie存入本地。

    data = {"data1":"XXXXX", "data2":"XXXXX"}
    Requests:data為dict,json
    import requests
    response = requests.post(url=url, data=data)
    Urllib2:data為string
    import urllib, urllib2
    data = urllib.urlencode(data)
    req = urllib2.Request(url=url, data=data)
    response = urllib2.urlopen(req)

    2.2 使用cookie登陸

    使用cookie登陸,伺服器會認為你是一個已登陸的用戶,所以就會返回給你一個已登陸的內容。因此,需要驗證碼的情況可以使用帶驗證碼登陸的cookie解決。

    import requests
    requests_session = requests.session()
    response = requests_session.post(url=url_login, data=data)

    若存在驗證碼,此時採用response = requests_session.post(url=url_login, data=data)是不行的,做法應該如下:

    response_captcha = requests_session.get(url=url_login, cookies=cookies)
    response1 = requests.get(url_login) # 未登陸
    response2 = requests_session.get(url_login) # 已登陸,因為之前拿到了Response Cookie!
    response3 = requests_session.get(url_results) # 已登陸,因為之前拿到了Response Cookie!

    相關參考:網路爬蟲-驗證碼登陸

    參考項目:網路爬蟲之用戶名密碼及驗證碼登陸:爬取知乎網站

    3. 對於反爬蟲機制的處理

    3.1 使用代理

    適用情況:限制IP地址情況,也可解決由於「頻繁點擊」而需要輸入驗證碼登陸的情況。

    這種情況最好的辦法就是維護一個代理IP池,網上有很多免費的代理IP,良莠不齊,可以通過篩選找到能用的。對於「頻繁點擊」的情況,我們還可以通過限制爬蟲訪問網站的頻率來避免被網站禁掉。

    proxies = {"http":"http://XX.XX.XX.XX:XXXX"}
    Requests:
    import requests
    response = requests.get(url=url, proxies=proxies)
    Urllib2:
    import urllib2
    proxy_support = urllib2.ProxyHandler(proxies)
    opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
    urllib2.install_opener(opener) # 安裝opener,此後調用urlopen()時都會使用安裝過的opener對象
    response = urllib2.urlopen(url)

    3.2 時間設置

    適用情況:限制頻率情況。

    Requests,Urllib2都可以使用time庫的sleep()函數:

    import time
    time.sleep(1)

    3.3 偽裝成瀏覽器,或者反「反盜鏈」

    有些網站會檢查你是不是真的瀏覽器訪問,還是機器自動訪問的。這種情況,加上User-Agent,表明你是瀏覽器訪問即可。有時還會檢查是否帶Referer信息還會檢查你的Referer是否合法,一般再加上Referer。

    headers = {"User-Agent":"XXXXX"} # 偽裝成瀏覽器訪問,適用於拒絕爬蟲的網站
    headers = {"Referer":"XXXXX"}
    headers = {"User-Agent":"XXXXX", "Referer":"XXXXX"}
    Requests:
    response = requests.get(url=url, headers=headers)
    Urllib2:
    import urllib, urllib2
    req = urllib2.Request(url=url, headers=headers)
    response = urllib2.urlopen(req)

    4. 對於斷線重連

    不多說。

    def multi_session(session, *arg):
    retryTimes = 20
    while retryTimes&>0:
    try:
    return session.post(*arg)
    except:
    print ".",
    retryTimes -= 1

    或者

    def multi_open(opener, *arg):
    retryTimes = 20
    while retryTimes&>0:
    try:
    return opener.open(*arg)
    except:
    print ".",
    retryTimes -= 1

    這樣我們就可以使用multi_session或multi_open對爬蟲抓取的session或opener進行保持。

    5. 多進程抓取

    這裡針對華爾街見聞進行並行抓取的實驗對比:Python多進程抓取 與 Java單線程和多線程抓取

    相關參考:關於Python和Java的多進程多線程計算方法對比

    6. 對於Ajax請求的處理

    對於「載入更多」情況,使用Ajax來傳輸很多數據。

    它的工作原理是:從網頁的url載入網頁的源代碼之後,會在瀏覽器里執行JavaScript程序。這些程序會載入更多的內容,「填充」到網頁里。這就是為什麼如果你直接去爬網頁本身的url,你會找不到頁面的實際內容。

    這裡,若使用Google Chrome分析」請求「對應的鏈接(方法:右鍵→審查元素→Network→清空,點擊」載入更多「,出現對應的GET鏈接尋找Type為text/html的,點擊,查看get參數或者複製Request URL),循環過程。

    • 如果「請求」之前有頁面,依據上一步的網址進行分析推導第1頁。以此類推,抓取抓Ajax地址的數據。
    • 對返回的json格式數據(str)進行正則匹配。json格式數據中,需從"uxxxx"形式的unicode_escape編碼轉換成u"uxxxx"的unicode編碼。

    7. 自動化測試工具Selenium

    Selenium是一款自動化測試工具。它能實現操縱瀏覽器,包括字元填充、滑鼠點擊、獲取元素、頁面切換等一系列操作。總之,凡是瀏覽器能做的事,Selenium都能夠做到。

    這裡列出在給定城市列表後,使用selenium來動態抓取去哪兒網的票價信息的代碼。

    參考項目:網路爬蟲之Selenium使用代理登陸:爬取去哪兒網站

    8. 驗證碼識別

    對於網站有驗證碼的情況,我們有三種辦法:

    • 使用代理,更新IP。
    • 使用cookie登陸。
    • 驗證碼識別。

    使用代理和使用cookie登陸之前已經講過,下面講一下驗證碼識別。

    可以利用開源的Tesseract-OCR系統進行驗證碼圖片的下載及識別,將識別的字元傳到爬蟲系統進行模擬登陸。當然也可以將驗證碼圖片上傳到打碼平台上進行識別。如果不成功,可以再次更新驗證碼識別,直到成功為止。

    參考項目:驗證碼識別項目第一版:Captcha1

    爬取有兩個需要注意的問題:

    • 如何監控一系列網站的更新情況,也就是說,如何進行增量式爬取?
    • 對於海量數據,如何實現分散式爬取?

    分析

    抓取之後就是對抓取的內容進行分析,你需要什麼內容,就從中提煉出相關的內容來。

    常見的分析工具有正則表達式,BeautifulSoup,lxml等等。

    存儲

    分析出我們需要的內容之後,接下來就是存儲了。

    我們可以選擇存入文本文件,也可以選擇存入MySQL或MongoDB資料庫等。

    存儲有兩個需要注意的問題:

    • 如何進行網頁去重?
    • 內容以什麼形式存儲?

    Scrapy

    Scrapy是一個基於Twisted的開源的Python爬蟲框架,在工業中應用非常廣泛。

    相關內容可以參考基於Scrapy網路爬蟲的搭建,同時給出這篇文章介紹的微信搜索爬取的項目代碼,給大家作為學習參考。

    參考項目:使用Scrapy或Requests遞歸抓取微信搜索結果


    反爬蟲的本質是找去真正人類用戶和爬蟲程序的區別,限制爬蟲程序的訪問,理論上只要爬蟲程序可以模擬任何人上網的行為,就可以完美擊敗反爬蟲機制。
    現在市場上領先的採集器全都是內置瀏覽器的,比如八爪魚採集器,內置瀏覽器幾乎可以模擬用戶的所有行為,包括移動滑鼠,點擊滑鼠,翻頁,點擊鏈接,滾動滑鼠滾輪,切換下拉菜單,輸入文字,自動識別驗證碼(人工打碼+機器識別),甚至看到不同的頁面還能採取不同的處理流程,雲採集還有成千上萬的IP實時切換。

    互聯網上90%的訪問流量都是機器而不是人類,所以,爬蟲與反爬蟲永遠是物競天擇的進化過程中,反爬蟲只要做到針對常見爬蟲手段限制IP等即可達到一般目標,要做到更高級的反爬策略也是要付出很高的成本的。爬蟲也沒必要以遠超人類的速度請求目標網站數據,給對方造成太大訪問壓力,互聯網本身就是開放的,但有些數據是由版權的,採集後一定要合理合法利用。


    只要網站正確的做了反爬蟲策略,不管你怎麼折騰,爬蟲幾乎不可能自動爬起來的

    • 比如網頁多處放幾個一個像素的隨機圖片名假鏈,人一般點不到,爬蟲一定不會錯過,一旦掉進陷阱,game over
    • 比如網頁多處放幾個隨機不可見的假鏈,人一般點不到,爬蟲也許不會判斷不可見的鏈接,一旦掉進陷阱,game over
    • 比如網頁多處放幾個隨機的的前景色和背景色相同的假鏈,人一般點不到,爬蟲基本不可能不掉進陷阱,然後game over
    • Persistent cookie很早就被認為不安全,成熟一點的web app基本都禁止使用
    • 分散式爬?想得美。發現是第一次訪問直接轉到相同的入口點。然後所有分散式都是從同一個頁面開始。
    • Single Page Application你怎麼爬?後台送的都是JSON數據,沒有鏈接

    我寫過一個rss個小工具,https://diy-devz.rhcloud.com/

    爬取搜狗微信公眾號搜索的非公開介面,沒做宣傳的時候,流量不大,用的比較好,宣傳後,用的人多了,就發現被反爬蟲了,一直500

    通過chrome的開發者工具分析搜狗頁面的請求,發現不是通過ip反爬,而是cookie里的幾個關鍵欄位,應對方法就是寫個定時任務,維護一個cookie池,定時更新cookie,爬的時候隨機取cookie,現在基本不會出現500

    所以應對反爬蟲,先分析伺服器是通過什麼來反爬,通過ip就用代理,通過cookie就換cookie,針對性的構建request。


    我們生活在信息爆炸的時代,窮盡一個人的一生也無法瀏覽完萬分之一的網路信息。那如果給你猜,你會覺得整個互聯網的流量里,非人類的比例有多大?

    是20%?

    還是30%?

    還是40%?

    據統計,2013年機器人占互聯網訪問的比例就已經超過了60%(很遺憾我並沒有查到更近時間的數據,但只會多不會少),也就是大部分的互聯網流量並不是由人類產生的。這60%孜孜不倦晝夜不息樂此不疲的機器人,我們就稱之為爬蟲。

    爬蟲分善良的爬蟲和惡意的爬蟲。善良的就像搜索引擎蜘蛛,它們掃描整個網路的內容,協助人類索引、保存、組織、排序信息,讓人人都成了現代的諸葛亮,足不出戶就可以窺探自然宇宙、知道天下興替。如果你不希望信息被索引,也只需大咧咧寫個robot.txt聲明,就跟國際法一樣神聖不被侵犯。更別說對做數據分析和數據挖掘的,爬蟲簡直是一門必須學精的手藝。公開的數據、新聞、微博,抓下來輸入模型演算一遍,什麼趨勢、什麼分布、什麼畫像,都盡入掌握,站在大數據之前,你會覺得自己就是這個時代的魔法師,能知前,能知後,能無中生有。

    正邪相生。惡意的爬蟲遠不只偷你的數據那麼簡單,他們像蝗蟲一樣盯著用戶聚集的地方,忙碌著在你的數據中注入水分,破壞正常用戶的體驗,損害你服務的處理能力。刷了你的排行榜,讓沒有價值的信息排到前面去了;打開大廳,遊戲玩家看到的滿屏都是爬蟲留下的廣告,或者有害的色情信息;好不容易真金白銀做個廣告,一群薅羊毛的機器人一擁而上,熱心的用戶趕了個晚集,反而連渣都沒剩下,運營觸達的效果大打折扣;競爭對手眼紅了,來一波DDOS,利用大量的主機和硬體對你進行流量攻擊,網站癱瘓了,正常用戶都服務不了。

    所以這註定是一場沒有硝煙的戰爭。不管是操縱善良的爬蟲攻擊,還是阻止惡意的爬蟲入侵,都必須要把攻防當成戰爭看待,一點都大意不得。以下就給一些爬蟲戰爭的Tips:

    當你是攻擊方時:

    • 了解敵方網站的URL路徑

    • 熟悉數據請求和返回的格式(Chrome的控制台和FireBug都是不錯的調試工具)

    • 解析目標欄位(用BeautifulSoup或者Xpath來提高你的效率)

    • 帶上正常的User-Agent,讓伺服器誤以為你是人類

    • 代理IP池,每次輪換不同的IP去請求數據

    • 如果敵方網站是通過JS請求數據,那麼可以試試Phantomjs這個小工具(這裡2shou叔要賣賣自己基於Phantomjs的爬蟲組件,歡迎GitHub搜索PhantomjsFetcher,目前剛破百Star,求繼續支持)

    • 遇到要求登陸的,給敵方一個小點心(Cookies)

    • 欲速不達,降低頻率慢慢抓,反正可以日夜不停嘛,不妨再設置一個隨機的停頓讓伺服器摸不著頭腦

    當你是防禦方時:

    • 找惡意群體的聚集特徵。托爾斯泰說,幸福的家庭是相似的,不幸的家庭則各有不同。區分機器人和人類也是如此,人類多種多樣,機器人千人一面。那些IP相同的,那些只索取、不奉獻的,那些行為單一的,通通殺個天地間白茫茫真乾淨

    • 加大關鍵數據的獲取成本,例如使用JS傳輸(注意這會影響SEO)、先登陸再瀏覽、JS代碼混淆、異或加密甚至非對稱加密

    • 涉及到真金白銀的,繼續加大敵方的獲取成本,綁定手機、綁定微信、APP掃碼,綁定惟一住址,能上的武器都堆上

    • 防DDOS攻擊要從內部做起:不要留無密碼或簡單密碼的Web界面,關注底層組件的漏洞(烏雲等平台),關鍵賬號密碼不要外泄(GitHub定期掃一掃,看看有沒有誰不聽話)

    有利益在的地方就有戰爭,企圖完全把對方消滅是不可能的,倒不如把惡意的爬蟲也作為你的產品生態的一部分,儘可能多掌握這部分人的動態,甚至想方設法讓敵方也為你所用,至少能按照你的預測那樣去行動。最後一句話說得有點玄乎了,留給懂行的人自己參悟吧。


    以前在MSRA協助別人做人工智慧的研究的時候,我也寫過爬蟲。不過在公司裡面寫爬蟲超級安全,我們只需要跟bing申請一下,然後爬cache(逃


    其實有時候反爬蟲是件很無奈的事情,谷歌的爬蟲也是爬蟲,但是為了 seo, 不能給封禁了吧,另外寫個小爬蟲做點高效的工具,其實也無可厚非。所以反爬蟲其實反的是惡意爬蟲,剛學個爬蟲,暴力循環個 id 一頓猛爬,導致目標網站資源飆升,這不是給工程師找事么。

    所以最好應對反爬蟲策略的方式就是遵守 robots 協議,對網站溫柔點,彼此和平相處。


    如何反爬蟲?常用的,基於IP,基於cookie,挑戰響應,等.
    如何爬的快又多?如果基於IP,找到闕值,在鄰近闕值的情況下分散式採集,
    基於cookie?cookie池
    基於挑戰響應?如果挑戰是一個隨機js,爬蟲要麼內置個js解釋器(麻煩)要麼爬蟲在某個開源瀏覽內核一起工作,如果挑戰是個隨機的flash,最簡單的方法,找這個網站的ios版


    首先要明確一點的就是:在爬蟲與反爬的對抗中,爬蟲最終會獲勝,因為爬蟲可以模仿人的行為去瀏覽網頁。
    那麼如何對抗反爬呢?下面是做法。
    1.代理和流控的結合
    一般網站檢測到一個ip在短時間內多次向本站發出不同的HTTP請求,就會認為這是一個爬蟲,並將其ip封一段時間。所以對於單個ip來說,降低發出請求的速率可以較好的逃過反爬的檢測,如果有上萬個代理ip,同時做流控就會比較快的爬取。至於代理如何快速的獲得,可以通過購買高質量的代理服務(比如 快代理 快代理 - 高速http代理ip每天更新),或者自己爬取。
    2.動態修改http head
    下面幾個欄位

    隨時動態的修改,可以避過反爬策略。

    1. cookie
    2. refer
    3. user agent

    以及http 頭中的幾個常用欄位。但是,一個ip不要用多個user agent,用了的話這明顯是告訴人家你在用爬蟲。。

    如何高效的爬取?下面給出幾個建議吧:

    構建一個能高效爬取的系統,你還需要:

    1. 高帶寬的網路:這個你懂,平均一個網頁100+kb,小水管的話爬個毛線,那麼多代理給你回傳數據你接都接不過來
    2. 容錯機制:代理伺服器都是不穩定的,隨時可能就不可用了,爬著爬著就會出現很多HTTP錯誤,所以針對一個爬蟲系統需要一個容錯機制,沒爬下來的url要繼續爬,直到爬下來確認數據完整為止。
    3. 高速存儲:爬蟲系統的速度瓶頸主要就在存儲和帶寬上,至於存儲,選用Hbase而不是MySQL,實測過,導出300+GB的數據,Hbase幾分鐘搞定,MySQL好幾個小時。
    4. PhantomJS、cURL等API,驗證碼識別。
    5. 登陸功能:要爬取微博這種需要登陸才能瀏覽內容的網站,肯定需要寫一個登陸功能的,這裡就需要註冊很多的殭屍賬號了,而且還需要維護殭屍賬號的cookie池,很麻煩。
    6. 採用非人力的方法寫爬蟲:針對一個網站寫爬蟲太累了。。來一個任務寫一個爬蟲,用java寫真心累啊。。所以還是想想怎麼把爬蟲的所有工具和API封裝一下吧,用簡單的配置和操作就可以完成對當前任務的快速爬取。

    嗯,以上。


    對於反爬蟲我是比較陰的,通過行為判斷出是爬蟲來,我是不直接拒絕的,而是提供比較真實的偽數據和真數據混在一起,讓他們抓幾個月後才發現數據不是全部正確,白白浪費時間,讓他們很難發現我的反扒規則。

    關於如何通過行為判斷是爬蟲,這個至關重要,訪客和爬蟲最大區別是,訪客是至少訪問你幾個頁面,每個頁面間隔也是比較長的,而且每個頁面都是載入解析整個html代碼和資源,包括img,js,css。而爬蟲只是簡單粗暴的獲取你的數據,不管你的網頁元素。


    如 @朱添一 所說, 反反爬蟲策略是依靠定向爬取源的反爬蟲策略而定的.
    一般有一下幾種


    一些常用的方法

    • IP代理
      • 對於IP代理,各個語言的Native Request API都提供的IP代理響應的API, 需要解決的主要就是IP源的問題了.
      • 網路上有廉價的代理IP(1元4000個左右), 我做過簡單的測試, 100個IP中, 平均可用的在40-60左右, 訪問延遲均在200以上.
      • 網路有高質量的代理IP出售, 前提是你有渠道.
      • 因為使用IP代理後, 延遲加大, 失敗率提高, 所以可以將爬蟲框架中將請求設計為非同步, 將請求任務加入請求隊列(RabbitMQ,Kafka,Redis), 調用成功後再進行回調處理, 失敗則重新加入隊列. 每次請求都從IP池中取IP, 如果請求失敗則從IP池中刪除該失效的IP.
    • Cookies
      • 有一些網站是基於cookies做反爬蟲, 這個基本上就是如 @朱添一 所說的, 維護一套Cookies池
      • 注意研究下目標網站的cookies過期事件, 可以模擬瀏覽器, 定時生成cookies
    • 限速訪問
      • 像開多線程,循環無休眠的的暴力爬取數據, 那真是分分鐘被封IP的事, 限速訪問實現起來也挺簡單(用任務隊列實現), 效率問題也不用擔心, 一般結合IP代理已經可以很快地實現爬去目標內容.

    一些坑

    大批量爬取目標網站的內容後, 難免碰到紅線觸發對方的反爬蟲機制. 所以適當的告警提示爬蟲失效是很有必有的.

    一般被反爬蟲後, 請求返回的HttpCode為403的失敗頁面, 有些網站還會返回輸入驗證碼(如豆瓣), 所以檢測到403調用失敗, 就發送報警, 可以結合一些監控框架, 如Metrics等, 設置短時間內, 告警到達一定閥值後, 給你發郵件,簡訊等.

    當然, 單純的檢測403錯誤並不能解決所有情況. 有一些網站比較奇葩, 反爬蟲後返回的頁面仍然是200的(如去哪兒), 這時候往往爬蟲任務會進入解析階段, 解析失敗是必然的. 應對這些辦法, 也只能在解析失敗的時候, 發送報警, 當告警短時間到達一定閥值, 再觸發通知事件.
    當然這個解決部分並不完美, 因為有時候, 因為網站結構改變, 而導致解析失敗, 同樣回觸發告警. 而你並不能很簡單地區分, 告警是由於哪個原因引起的.


    只有是自動化的反爬蟲策略都能破。唯一不能破的就是人工干預的反爬蟲機制——編死的代碼永遠不能與人的智慧抗衡。


    只要你開價夠高,對方會直接把你想要的數據按照你希望的方式提供給你。


    我有個反爬蟲的想法,在頁面放一個鏈接,但是display屬性設置為none或者顏色等於background-color或者鏈接被其他的div擋住或者鏈接位置超出屏幕,正常用戶是不可能訪問這個頁面的,如果有人訪問了我就認為他是爬蟲,封ip。

    第一次修改:如果是很有針對的抓取,上面的方法就沒用了。

    第二次修改:給頁面加上一些埋點,如果某個鏈接被訪問了,但是找不到曝光埋點也能發現機器人訪問。


    要知道反爬蟲是一定能輕易幹掉反反爬蟲的。只是別人不願意,或懶得去做罷了。

    什麼代理ip,cookies,都弱爆了。反爬蟲方一個行為驗證加蜜罐直接把代理ip封地連媽都不認識。


    1.Headers限制

    這應該是最常見的,最基本的反爬蟲手段,主要是初步判斷你是否是真實的瀏覽器在操作。

    這個一般很好解決,把瀏覽器中的Headers信息複製上去就OK了。

    值得注意的是,很多網站只需要userAgent信息就可以通過,但是有的網站還需要驗證一些其他的信息,比如知乎,有一些頁面還需要 authorization 的信息。所以需要加哪些Headers,還需要嘗試,可能還需要Referer、Accept-encoding等信息。

    常用的請求頭

    在代碼中添加 Headers 信息

    2.IP限制

    限制IP也是很多網站反爬蟲的初衷,有些人隨便寫一個循環,就開始暴力爬取 ,確實會給網站伺服器帶來很大的負擔,而這種頻繁的訪問,顯然也不會是真實用戶行為,索性果斷把你封掉。

    這種情況,你可以遵守規則,把你爬取的速度變慢,每次爬取停個幾秒就行了。如果爬取的數據量不大,其實也浪費不了多少時間,反正你也可以利用這段時間做做其他事情,或者好好思考一下人生。

    time.sleep(5)

    當然,你也可以通過不斷換IP的形式來繞過這種限制,網上很多免費的IP資源,你可以自己搭一個IP池,爬到一定的量就切換IP。

    3.動態載入

    通過非同步載入,一方面是為了反爬蟲,一方面也可以給網頁瀏覽帶來不同的體驗,實現更多的功能。很多動態網站都是通過ajax或者JavaScript來載入請求的網頁。

    在遇到動態載入的網頁的時候就需要去分析ajax請求,一般情況都能直接找到包含我們想要數據的json文件。

    如果網站給文件加密,那麼可以通過selenium+phantomJS框架,調用瀏覽器內核,並利用phantomJS執行js來模擬人為操作以及觸發頁面中的js腳本。理論上selenium是比較全能的爬蟲方案,因為這個確實算是真實的用戶行為。除非網站的反爬蟲嚴苛到寧願誤殺的地步。

    selenium爬取淘寶

    4.驗證碼

    我們在很多網站會遇到,如果請求量大了之後就會遇到驗證碼的情況。最讓人詬病的12306,其實也是一定程度上的防止非正當請求的產生。

    對於驗證碼,可以通過OCR來識別圖片,Github上面有很多大神分享的代碼可以用,可以去看看。

    5.減少返回的信息

    最基本的隱藏真實的數據量,只有不斷載入才能刷新信息。還有的就更變態,會只給你展示一部分信息,人都看不到,爬蟲也無能為力。比如CNKI,你每次搜索能夠得到的內容就是非常有限的。這個貌似沒有很好的解決辦法,但是這麼乾的網站畢竟是少數,因為這種方式,其實在某種程度上是犧牲了一部分真實用戶的體驗。

    6.返回偽造的信息

    這個真的是程序員何苦為難程序員。反爬蟲的工程師也是煞費苦心,一方面是不讓真實的數據被大規模爬取,另一方面也給你後期的數據處理增加負擔。如果數據偽造的好,可能你真的不容易發現自己爬的是假數據,當然只能依靠你後期去清洗這些數據了。

    如果想系統學習爬蟲,可以看看我們的課程:Python爬蟲:入門+進階


    推薦閱讀:

    如何爬取伺服器日誌log和資料庫?
    當爬蟲不遵守 robots 協議時,有沒有防止抓取的可能?
    網路搜索引擎為什麼又要叫爬蟲?
    python抓取新浪微博,求教!!?
    scrapy可以進行線性/順序抓取嗎?

    TAG:Python | 編程 | 爬蟲計算機網路 |