爬蟲框架Scrapy之Downloader Middlewares


反反爬蟲相關機制

Some websites implement certain measures to prevent bots from crawling them, with varying degrees of sophistication. Getting around those measures can be difficult and tricky, and may sometimes require special infrastructure. Please consider contacting commercial support if in doubt. (有些些網站使用特定的不同程度的復雜性規則防止爬蟲訪問,繞過這些規則是困難和復雜的,有時可能需要特殊的基礎設施。如果有疑問請聯系商業支持。)

來自於Scrapy官方文檔描述:http://doc.scrapy.org/en/master/topics/practices.html#avoiding-getting-banned

通常防止爬蟲被反主要有以下幾個策略:

  • 動態設置User-Agent(隨機切換User-Agent,模擬不同用戶的瀏覽器信息)

  • 禁用Cookies(也就是不啟用cookies middleware,不向Server發送cookies,有些網站通過cookie的使用發現爬蟲行為)

    • 可以通過COOKIES_ENABLED 控制 CookiesMiddleware 開啟或關閉
  • 設置延遲下載(防止訪問過於頻繁,設置為 2秒 或更高)

  • Google Cache 和 Baidu Cache:如果可能的話,使用谷歌/百度等搜索引擎服務器頁面緩存獲取頁面數據。

  • 使用IP地址池:VPN和代理IP,現在大部分網站都是根據IP來ban的。

  • 使用 Crawlera(專用於爬蟲的代理組件),正確配置和設置下載中間件后,項目所有的request都是通過crawlera發出。

DOWNLOADER_MIDDLEWARES = {
    'scrapy_crawlera.CrawleraMiddleware': 600
}

CRAWLERA_ENABLED = True
CRAWLERA_USER = '注冊/購買的UserKey'
CRAWLERA_PASS = '注冊/購買的Password'

如何設置下載中間件(Downloader Middlewares)

下載中間件是處於引擎(crawler.engine)和下載器(crawler.engine.download())之間的一層組件,可以有多個下載中間件被加載運行。

  1. 當引擎傳遞請求給下載器的過程中,下載中間件可以對請求進行處理 (例如增加http header信息,增加proxy信息等);

  2. 在下載器完成http請求,傳遞響應給引擎的過程中, 下載中間件可以對響應進行處理(例如進行gzip的解壓等)

要激活下載器中間件組件,將其加入到 DOWNLOADER_MIDDLEWARES 設置中。 該設置是一個字典(dict),鍵為中間件類的路徑,值為其中間件的順序(order)。

這里是一個例子:

DOWNLOADER_MIDDLEWARES = {
    'mySpider.middlewares.MyDownloaderMiddleware': 543, } 

編寫下載器中間件十分簡單。每個中間件組件是一個定義了以下一個或多個方法的Python類:

class scrapy.contrib.downloadermiddleware.DownloaderMiddleware

process_request(request, spider)

  • 當每個request通過下載中間件時,該方法被調用。

  • process_request() 必須返回以下其中之一:一個 None 、一個 Response 對象、一個 Request 對象或 raise IgnoreRequest:

    • 如果其返回 None ,Scrapy將繼續處理該request,執行其他的中間件的相應方法,直到合適的下載器處理函數(download handler)被調用, 該request被執行(其response被下載)。

    • 如果其返回 Response 對象,Scrapy將不會調用 任何 其他的 process_request() 或 process_exception() 方法,或相應地下載函數; 其將返回該response。 已安裝的中間件的 process_response() 方法則會在每個response返回時被調用。

    • 如果其返回 Request 對象,Scrapy則停止調用 process_request方法並重新調度返回的request。當新返回的request被執行后, 相應地中間件鏈將會根據下載的response被調用。

    • 如果其raise一個 IgnoreRequest 異常,則安裝的下載中間件的 process_exception() 方法會被調用。如果沒有任何一個方法處理該異常, 則request的errback(Request.errback)方法會被調用。如果沒有代碼處理拋出的異常, 則該異常被忽略且不記錄(不同於其他異常那樣)。

  • 參數:

    • request (Request 對象) – 處理的request
    • spider (Spider 對象) – 該request對應的spider

process_response(request, response, spider)

當下載器完成http請求,傳遞響應給引擎的時候調用

  • process_request() 必須返回以下其中之一: 返回一個 Response 對象、 返回一個 Request 對象或raise一個 IgnoreRequest 異常。

    • 如果其返回一個 Response (可以與傳入的response相同,也可以是全新的對象), 該response會被在鏈中的其他中間件的 process_response() 方法處理。

    • 如果其返回一個 Request 對象,則中間件鏈停止, 返回的request會被重新調度下載。處理類似於 process_request() 返回request所做的那樣。

    • 如果其拋出一個 IgnoreRequest 異常,則調用request的errback(Request.errback)。 如果沒有代碼處理拋出的異常,則該異常被忽略且不記錄(不同於其他異常那樣)。

  • 參數:

    • request (Request 對象) – response所對應的request
    • response (Response 對象) – 被處理的response
    • spider (Spider 對象) – response所對應的spider

使用案例:

1. 創建middlewares.py文件。

Scrapy代理IP、Uesr-Agent的切換都是通過DOWNLOADER_MIDDLEWARES進行控制,我們在settings.py同級目錄下創建middlewares.py文件,包裝所有請求。

# middlewares.py import random import base64 # 導入settings的PROXIES設置 from settings import PROXIES # 隨機使用預定義列表里的 User-Agent類 class RandomUserAgent(object): def __init__(self, agents): # 使用初始化的agents列表 self.agents = agents  @classmethod def from_crawler(cls, crawler): # 獲取settings的USER_AGENT列表並返回 return cls(crawler.settings.getlist('USER_AGENTS')) def process_request(self, request, spider): # 隨機設置Request報頭header的User-Agent request.headers.setdefault('User-Agent', random.choice(self.agents)) # 隨機使用預定義列表里的 Proxy代理 class ProxyMiddleware(object): def process_request(self, request, spider): # 隨機獲取from settings import PROXIES里的代理 proxy = random.choice(PROXIES) # 如果代理可用,則使用代理 if proxy['user_pass'] is not None: request.meta['proxy'] = "http://%s" % proxy['ip_port'] # 對代理數據進行base64編碼 encoded_user_pass = base64.encodestring(proxy['user_pass']) # 添加到HTTP代理格式里 request.headers['Proxy-Authorization'] = 'Basic ' + encoded_user_pass else: print "****代理失效****" + proxy['ip_port'] request.meta['proxy'] = "http://%s" % proxy['ip_port'] 

為什么HTTP代理要使用base64編碼:

HTTP代理的原理很簡單,就是通過HTTP協議與代理服務器建立連接,協議信令中包含要連接到的遠程主機的IP和端口號,如果有需要身份驗證的話還需要加上授權信息,服務器收到信令后首先進行身份驗證,通過后便與遠程主機建立連接,連接成功之后會返回給客戶端200,表示驗證通過,就這么簡單,下面是具體的信令格式:

CONNECT 59.64.128.198:21 HTTP/1.1
Host: 59.64.128.198:21
Proxy-Authorization: Basic bGV2I1TU5OTIz
User-Agent: OpenFetion

其中Proxy-Authorization是身份驗證信息,Basic后面的字符串是用戶名和密碼組合后進行base64編碼的結果,也就是對username:password進行base64編碼。

HTTP/1.0 200 Connection established

OK,客戶端收到收面的信令后表示成功建立連接,接下來要發送給遠程主機的數據就可以發送給代理服務器了,代理服務器建立連接后會在根據IP地址和端口號對應的連接放入緩存,收到信令后再根據IP地址和端口號從緩存中找到對應的連接,將數據通過該連接轉發出去。

2. 修改settings.py配置USER_AGENTS和PROXIES

  • 添加USER_AGENTS:
  USER_AGENTS = [
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)", "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)", "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)", "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0", "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5" ] 
  • 添加代理IP設置PROXIES:

    代理IP可以網上搜索,或者付費購買一批可用代理IP:

PROXIES = [
    {'ip_port': '111.8.60.9:8123', 'user_pass': ''}, {'ip_port': '101.71.27.120:80', 'user_pass': ''}, {'ip_port': '122.96.59.104:80', 'user_pass': ''}, {'ip_port': '122.224.249.122:8088', 'user_pass': ''}, ] 
  • 禁用cookies,防止某些網站根據Cookie來封鎖爬蟲。
COOKIES_ENABLED = False
  • 設置下載延遲
DOWNLOAD_DELAY = 3
  • 最后設置setting.py里的DOWNLOADER_MIDDLEWARES
DOWNLOADER_MIDDLEWARES = {
    #'mySpider.middlewares.MyCustomDownloaderMiddleware': 543, 'mySpider.middlewares.RandomUserAgent': 1, 'mySpider.middlewares.ProxyMiddleware': 100 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM