最近中文字幕高清中文字幕无,亚洲欧美高清一区二区三区,一本色道无码道dvd在线观看 ,一个人看的www免费高清中文字幕

首頁 慕課教程 Scrapy 入門教程 Scrapy 入門教程 網(wǎng)站反爬蟲繞過技術(shù)分析

如何繞過反爬蟲技術(shù)分析

對(duì)于大型網(wǎng)站的爬取我們經(jīng)常會(huì)面臨網(wǎng)站設(shè)定的反爬技術(shù)封鎖,比如輸入圖片驗(yàn)證碼、識(shí)別圖中漢字,甚至直接禁止你的 ip 等。這樣我們的爬蟲可能剛開始運(yùn)行不久就會(huì)遭受嚴(yán)重打擊,無法進(jìn)行下去。如何才能偽裝的更像正常的請(qǐng)求是我們本節(jié)關(guān)注的重點(diǎn)。

1. 反爬封鎖應(yīng)對(duì)措施

面對(duì)網(wǎng)站的反爬封鎖,我們往往有如下幾個(gè)應(yīng)對(duì)措施,這些基本的方法已經(jīng)能應(yīng)對(duì)大部分網(wǎng)站的封鎖。更為深入的擬人技術(shù)還需要讀者自行去探索,多加實(shí)戰(zhàn)。

1.1 修改請(qǐng)求頭

我們前面爬蟲的第一步都是在請(qǐng)求頭中添加正常瀏覽器的 user-agent,但是請(qǐng)求頭的參數(shù)不止這些,還有一個(gè)值也會(huì)經(jīng)常被檢查到,那就是 referer 字段,它會(huì)告訴服務(wù)器該請(qǐng)求是從哪個(gè)頁面鏈接過來的,服務(wù)器基此可以獲得一些信息用于處理,因此為了更好的防止請(qǐng)求被封,我們也要盡量在請(qǐng)求 header 中加上referer 字段以及其正確的值。

圖片描述
另外,user-agent 是每個(gè)反爬網(wǎng)站必查的字段,如果大量請(qǐng)求重復(fù)使用固定的 user-agent 值,在某些程序中也會(huì)被判定為爬蟲。因此我們可以對(duì)所有的請(qǐng)求采用隨機(jī)的 user-agent 值來避免這種反爬檢測(cè)。Scrapy 中的中間件 UserAgentMiddleware 就是專門用來設(shè)置請(qǐng)求頭中 user-agent 值的。

1.2 降低請(qǐng)求頻率

正常情況下,我們的每次請(qǐng)求都會(huì)被記錄,如果我們請(qǐng)求太快,比如1秒內(nèi)發(fā)送10次請(qǐng)求,這明顯不是手動(dòng)實(shí)現(xiàn)的,很容易被識(shí)別然后采取相應(yīng)措施。我們不管是在普通的爬蟲代碼還是 scrapy 中都要設(shè)置請(qǐng)求的間隔時(shí)間,防止被檢測(cè)出來。在普通的爬蟲程序中,我們直接使用 python 的 time 模塊,調(diào)用 time.sleep() 方法進(jìn)行延時(shí)調(diào)用,而在 Scrapy 中,我們只需要在 settings.py 中設(shè)置 DOWNLOAD_DELAY 的值即可。例如:

DOWNLOAD_DELAY = 2

上述的配置表示我們將兩次請(qǐng)求的間隔設(shè)置為 2 秒,這已經(jīng)是一個(gè)符合人正常操作的時(shí)間間隔了。不過太過于規(guī)律的請(qǐng)求同樣會(huì)被更為智能的程序察覺,為了避免出現(xiàn)這樣的情況,在 Scrapy 框架的配置中提供了 RANDOMIZE_DOWNLOAD_DELAY 參數(shù)。當(dāng)它設(shè)置為 True 時(shí) ,Scrapy 會(huì)在兩次下載請(qǐng)求間設(shè)置一個(gè) 0.5 * DOWNLOAD_DELAY1.5 * DOWNLOAD_DELAY 之間的一個(gè)隨機(jī)延遲時(shí)間。

1.3 禁用Cookie

有些網(wǎng)站會(huì)通過 Cookie 來發(fā)現(xiàn)爬蟲的蹤跡,因此,我們?cè)谶M(jìn)行普通網(wǎng)站數(shù)據(jù)爬取時(shí)可以考慮關(guān)閉 Cookie:

COOKIES_ENABLED = False

不過,對(duì)于一些需要登錄后進(jìn)行操作的,比如我們之前爬取起點(diǎn)用戶書架以及刪除書架上數(shù)據(jù)的爬蟲,則需要使用 COOKIES 的情況下,我們不能禁用 Cookie。所以,特定場(chǎng)景需要特定的配置,不能一概而論。

1.4 驗(yàn)證碼突破

許多做的非常好的網(wǎng)站都會(huì)有驗(yàn)證碼校驗(yàn),比如京東、淘寶的登錄。更為復(fù)雜的還有12306網(wǎng)站那個(gè)讓人頭暈的識(shí)圖驗(yàn)證等等。目前而言,驗(yàn)證碼技術(shù)從原來的簡(jiǎn)單數(shù)字、字母識(shí)別,到滑塊拖動(dòng)、拼圖認(rèn)證以及最新的圖片識(shí)別、漢字倒立等,已經(jīng)越來越復(fù)雜和難辨。很多基于機(jī)器學(xué)習(xí)以及深度學(xué)習(xí)的高難度識(shí)別算法應(yīng)運(yùn)而生,但這些對(duì)于普通程序員而言,難以企及。我們唯有兩方面突破:

  • 花錢買服務(wù):網(wǎng)上有不少專門的驗(yàn)證碼識(shí)別服務(wù)提供商,比如幾年前比較流行的若快平臺(tái) (目前官網(wǎng)無法訪問,似乎已經(jīng)涼了)等;
  • 開源項(xiàng)目:如果舍不得花錢買服務(wù)的,我們只能寄希望于部分開源工具。好在還是有不少大神愿意將他們的研究代碼、工具進(jìn)行開源,這也使得我們能有機(jī)會(huì)去學(xué)習(xí)和使用這些工具去突破驗(yàn)證碼的限制;

圖片描述

京東的拼圖驗(yàn)證

圖片描述

12306的識(shí)圖驗(yàn)證

1.5 使用 ip 代理

對(duì)于一些比較狠的網(wǎng)站,會(huì)對(duì)一些爬蟲的程序客戶端 ip 進(jìn)行封殺,這樣我們至少在一段時(shí)間內(nèi)無法在運(yùn)行該程序去爬取網(wǎng)站數(shù)據(jù)。此時(shí),我們可以使用代理 ip 去隱藏真實(shí)的請(qǐng)求 ip,這樣又可以訪問網(wǎng)站并爬取數(shù)據(jù)。如果這個(gè)代理 ip 被封了怎么辦?那就需要有多個(gè)可用的代理 ip,一旦發(fā)現(xiàn)該 ip 被封,我們立馬換下一個(gè) ip 代理繼續(xù)請(qǐng)求數(shù)據(jù)。假設(shè)我們有十萬代理 ip,每個(gè)代理能支撐我們爬取 1分鐘數(shù)據(jù),那么我們至少能順利爬取2個(gè)多月,且一般1-2天左右,原來被封的 ip 又會(huì)被解除禁封。這樣,只要我們有大量的 ip 代理,我們就不怕網(wǎng)站的封殺,能源源不斷獲取相應(yīng)的網(wǎng)站數(shù)據(jù)。那么到哪里去獲取這樣免費(fèi)的代理 ip 呢?同樣有兩種途徑:

  • 網(wǎng)絡(luò)上的免費(fèi) ip 代理:免費(fèi)、不穩(wěn)定且大部分不可用;
  • 付費(fèi) ip 代理池:略貴、大部分穩(wěn)定可用;

圖片描述

在 github 上也有許多維護(hù)和獲取免費(fèi)代理服務(wù)器地址的項(xiàng)目,我們也可以直接使用這些免費(fèi)的項(xiàng)目幫我們抓取并維護(hù)可用的代理 ip 池。

2. 偽裝成隨機(jī)瀏覽器

我們來看看 Scrapy 給我們提供的、用于偽裝 User-Agent 字段的中間件:UserAgentMiddleware 。其定義位于 scrapy/downloadermiddlewares/useragent.py 文件中,我們來看看其具體內(nèi)容:

class UserAgentMiddleware:
    """This middleware allows spiders to override the user_agent"""

    def __init__(self, user_agent='Scrapy'):
        self.user_agent = user_agent

    @classmethod
    def from_crawler(cls, crawler):
        o = cls(crawler.settings['USER_AGENT'])
        crawler.signals.connect(o.spider_opened, signal=signals.spider_opened)
        return o

    def spider_opened(self, spider):
        self.user_agent = getattr(spider, 'user_agent', self.user_agent)

    def process_request(self, request, spider):
        if self.user_agent:
            request.headers.setdefault(b'User-Agent', self.user_agent)

從上面的代碼我們可以看到,該中間件會(huì)從 settings.py 中取得 USER_AGENT 參數(shù)值, 然后進(jìn)行實(shí)例化:

o = cls(crawler.settings['USER_AGENT'])

在處理請(qǐng)求的核心方法 process_request() 會(huì)將該值賦給請(qǐng)求頭中的 User-Agent 字段。注意該中間件屬于下載中間件,在 Scrapy 中默認(rèn)被啟用,如下圖所示:

圖片描述

我們來看看如何在這個(gè)中間件的基礎(chǔ)上實(shí)現(xiàn)隨機(jī)的 User-Agent 請(qǐng)求:

  • 編寫一個(gè)基于 UserAgentMiddleware 的中間件類,可以放到 scrapy 項(xiàng)目的 middlewares.py 文件中。這里我們使用 fake-useragent 模塊來幫我們生成各種各樣的 user-agent 值,這樣避免我們手工維護(hù)一個(gè) user-agent 的值列表。該模塊的使用非常簡(jiǎn)單:

    (scrapy-test) [root@server china_pub]# python 
    Python 3.8.1 (default, Dec 24 2019, 17:04:00) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from fake_useragent import UserAgent
    >>> ua = UserAgent()
    >>> ua.random
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36'
    >>> ua.random
    'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36'
    >>> ua.random
    'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1464.0 Safari/537.36'
    >>> ua.random
    'Mozilla/5.0 (Windows NT 6.2; rv:21.0) Gecko/20130326 Firefox/21.0'
    >>> 
    

    注意:使用這個(gè)模塊需要聯(lián)網(wǎng),根據(jù)相應(yīng)的版本要請(qǐng)求網(wǎng)站的相應(yīng)接口,獲取相應(yīng)數(shù)據(jù)。例如我這里的版本是0.1.11,于是請(qǐng)求的 URL 及其接口數(shù)據(jù)如下:

圖片描述

來看我們自定義的中間件代碼如下:

# 寫入位置:scrapy項(xiàng)目的middlewares.py文件中

from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware
from fake_useragent import UserAgent

# ...

class MyUserAgentMiddleware(UserAgentMiddleware):
    def process_request(self, request, spider):
        ua = UserAgent()
        user_agent = ua.random
        if user_agent:
            request.headers.setdefault(b'User-Agent', user_agent)
        return None
  • 另外,我們這里繼承了 UserAgentMiddleware 中間件,那么原來的這個(gè)中間件就失去了意義、因此,在 settings.py 中,我們要啟用新的設(shè)置 User-Agent 的中間件且關(guān)閉原來的中間件:

    # 代碼位置:scrapy項(xiàng)目的settings.py文件中
    
    DOWNLOADER_MIDDLEWARES = {
       '項(xiàng)目名稱.middlewares.MyUserAgentMiddleware': 500,
       'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    }
    

3. 使用代理

在 Scrapy 項(xiàng)目中使用代理是非常簡(jiǎn)單的一件事情,我們只需要在發(fā)送的 Request 請(qǐng)求中添加 meta 參數(shù)即可實(shí)現(xiàn)代理功能:

yield Request(url, callback=回調(diào)方法, errback=錯(cuò)誤回調(diào), meta={"proxy": proxy, "download_timeout": 10})

上面生成的 Request 請(qǐng)求帶上了 meta 參數(shù),該參數(shù)中又設(shè)置了代理服務(wù)器的地址以及相應(yīng)的超時(shí)時(shí)間。我們可以簡(jiǎn)單來看看代理服務(wù)器的使用:

  • 首先我們來自己搭建一個(gè) Nginx 服務(wù),具體的搭建過程可以參考這個(gè)教程: Nginx入門手冊(cè);

  • 接著我們使用9999這個(gè)端口做為代理轉(zhuǎn)發(fā)端口,相關(guān)的配置如下:

    # nginx.conf
    
    server {
         resolver 114.114.114.114;
         resolver_timeout 5s;
    
         listen 9999;
    
         location / {
             proxy_pass $scheme://$host$request_uri;
             proxy_set_header Host $http_host;
    
             proxy_buffers 256 8k;
             proxy_max_temp_file_size 0;
    
             proxy_connect_timeout 30;
    
             proxy_cache_valid 200 302 10m;
             proxy_cache_valid 301 1h;
             proxy_cache_valid any 1m;
        }
    }
    
  • 啟動(dòng) nginx 服務(wù)后,我們這個(gè)代理服務(wù)就搞定了。我們可以使用 requests 測(cè)試下這個(gè)代理服務(wù),看看是不是生效了:

    import requests
    
    proxies = {
      "http": "http://180.76.152.113:9999",
    }
    
    response = requests.get("http://www.china-pub.com/browse/", proxies=proxies)
    response.encoding = 'gbk'
    print(response.text)
    

    上述代碼位于另一臺(tái)云服務(wù)器,請(qǐng)求的是互動(dòng)出版物的圖書分類頁面,這次我們會(huì)在 requests 請(qǐng)求中加上我們剛剛配置的代理,使用 nginx 代理轉(zhuǎn)發(fā)請(qǐng)求,請(qǐng)看視頻演示:

往往在 Scrapy 中,我們往往會(huì)采用這樣的方式去使用代理服務(wù):

  • 準(zhǔn)備好一個(gè) redis 和 web 服務(wù)。其中 web 服務(wù)往往會(huì)使用 django 或者 flask 等 web 框架開發(fā),用于爬取免費(fèi)的代理 ip,同時(shí)會(huì)對(duì)爬取到的 ip:port 進(jìn)行校驗(yàn)。如果代理 ip 有效則將其緩存至 redis 服務(wù)中,形成有效的 ip 代理池;
  • web 服務(wù)會(huì)定期檢查 ip 代理池的所有數(shù)據(jù),對(duì)于無效的 ip 及時(shí)清除。同時(shí),也會(huì)定時(shí)爬取新的有效的代理 ip 并保存到 redis 中;
  • web 服務(wù)會(huì)提供一個(gè)獲取當(dāng)前 ip 池內(nèi)有效 HTTP 代理地址的接口,這樣外部應(yīng)用只需要請(qǐng)求這個(gè)接口就能獲取一個(gè)有效的代理地址;

此外,在 Scrapy 的項(xiàng)目中,我們往往會(huì)按照如下的思路進(jìn)行代理爬?。?/p>

圖片描述

限于篇幅,這里不再對(duì)整個(gè)流程做案例演示,有興趣的讀者可以下去后一步步完成從 ip 代理池服務(wù)的開發(fā)到最后對(duì)接 Scrapy 框架的整個(gè)過程,推薦測(cè)試的網(wǎng)站為新浪微博,這也是 github 上許多案例的測(cè)試靶場(chǎng)。

4. 小結(jié)

本小節(jié)中我們主要講述了三方面的內(nèi)容:

  • 詳細(xì)介紹了常見的突破反爬封鎖措施;
  • 完成一個(gè) Scrapy 中間件實(shí)現(xiàn)偽裝隨機(jī)瀏覽器功能;
  • 介紹代理技術(shù)與 Scrapy 項(xiàng)目結(jié)合的方式;

當(dāng)然這些對(duì)于淘寶、微博等大廠的反爬技術(shù)而言還遠(yuǎn)遠(yuǎn)不夠。后續(xù)讀者可以技術(shù)深入研究如何突破各種驗(yàn)證碼的校驗(yàn)、模擬人點(diǎn)擊的軌跡,真正實(shí)現(xiàn)模擬用戶瀏覽器請(qǐng)求操作,才能實(shí)現(xiàn)無所不爬的 Spider。

圖片描述