Socks5Proxy

Scrapy代理設置,使用meta proxy為每個請求分配不同IP

本指南說明Scrapy框架中,透過meta proxy參數連接Socks5Proxy的HTTP代理,以API動態輪替下載器中介IP,並針對目標網站調整爬取速度的設定技巧。

Scrapy如何處理代理?

Scrapy默認啟用HttpProxyMiddleware。在請求的meta字典中添加proxy鍵和地址,該請求就會通過指定代理發出,地址中的用戶名和密碼會被中間件轉換為Proxy-Authorization頭髮送。HTTPS地址通過CONNECT隧道傳輸。

Scrapy默認下載處理器支持HTTP代理。若必須使用SOCKS5需額外處理器,建議在Scrapy中使用同一IP的HTTP端口。目標網站看到的IP相同。

示例使用 IP 198.51.100.23,HTTP 端口 8000,用戶名 spx_user,密碼 spx_pass。

pip install scrapy
scrapy startproject shop
cd shop

如何在請求中加入代理?

於start_requests建立Request時,透過meta傳入proxy參數即可。回調中請求下一頁時請以相同方式設定。需維持相同會話時,可從前次響應的meta中繼承proxy值以保持IP不變。

import scrapy

PROXY = "http://spx_user:spx_pass@198.51.100.23:8000"

class IpCheckSpider(scrapy.Spider):
    name = "ip_check"

    def start_requests(self):
        yield scrapy.Request("https://api.ipify.org?format=json", meta={"proxy": PROXY})

    def parse(self, response):
        self.logger.info("seen as %s", response.json()["ip"])

如何實現每次請求更換IP?

創建下載器中間件,為所有請求添加代理即可無需修改爬蟲代碼實現輪換。以下中間件啟動時通過API獲取列表,若meta已含proxy則保留原值,兼容會話固定與輪換需求。

請將API密鑰置於settings.py或從環境變量讀取。註冊順序需早於默認HttpProxyMiddleware(750)的數字,以便中間件處理由基本中間件插入的地址。

import itertools
import requests

class RotatingProxyMiddleware:
    def __init__(self, key):
        text = requests.get(
            "https://socks5proxy.io/api/v1/proxies/download",
            params={"format": "user:pass@ip:port", "protocol": "http"},
            headers={"Authorization": "Bearer " + key},
            timeout=30,
        ).text
        self.pool = itertools.cycle(["http://" + l.strip() for l in text.splitlines() if l.strip()])

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler.settings.get("SPX_API_KEY"))

    def process_request(self, request, spider):
        if "proxy" not in request.meta:  # keep a proxy that was set on purpose (sticky sessions)
            request.meta["proxy"] = next(self.pool)

如何調整速度和重試次數?

CONCURRENT_REQUESTS_PER_DOMAIN 係指同一個域名可以同時發出嘅請求數量。當你有多個代理 IP 時,提高呢個數值並唔會增加單一 IP 嘅負擔。例如,用 500 個 IP 同時發出 50 個請求,每個 IP 平均只會處理 10 次請求中嘅一次。

啟用AUTOTHROTTLE可根據響應速度自動調整請求間隔。429響應增多時可用RETRY_HTTP_CODES重試,重試時清除meta的proxy使中間件插入下一代理。

在管道中加入檢查收集結果是否為實際頁面而非確認頁面的步驟,可以提高數據質量。如果回應中缺少所需元素,可以使用其他 IP 重新請求。

  • 根據 IP 數量調整各域名並發請求數
  • AUTOTHROTTLE根據響應速度自動調整間隔
  • 429及5xx錯誤請嘗試其他IP
  • 透過響應內容過濾驗證頁面

IP 授權連接有何不同?

在儀表板中註冊運行Scrapy的伺服器的IPv4地址,這樣在meta proxy中就可以像http://198.51.100.23:8000這樣無需用戶名和密碼使用。列表也可以以format=ip:port的格式獲取。如果有多台伺服器運行爬蟲,請註冊每台伺服器的IP。最多可以註冊10個IP。

如何將需要會話的請求綁定到相同 IP?

像登入或購物車這樣需要保持Cookie連續的流程,必須使用同一IP。在首次請求中直接加入meta proxy,並在回調中創建下一個請求時,將response.meta的proxy值直接傳遞,這樣循環中間件就不會更改它。與Scrapy的cookiejar meta鍵一起使用,Cookie也會按會話分離。

將會話與代理和 Cookie 綁定,即使同時運行多個會話也不會混淆。

import scrapy

PROXIES = [
    "http://spx_user:spx_pass@198.51.100.23:8000",
    "http://spx_user:spx_pass@198.51.100.24:8000",
]

class SessionSpider(scrapy.Spider):
    name = "sessions"

    def start_requests(self):
        for i, proxy in enumerate(PROXIES):
            yield scrapy.Request("https://example.com/", meta={"proxy": proxy, "cookiejar": i}, dont_filter=True)

    def parse(self, response):
        # follow-up request keeps the same proxy and the same cookie jar
        yield response.follow("/account", meta={"proxy": response.meta["proxy"], "cookiejar": response.meta["cookiejar"]}, callback=self.parse_account)

    def parse_account(self, response):
        self.logger.info("status %s via %s", response.status, response.meta["proxy"])

如何暫時移除失敗代理?

如果從 middleware 的 process_response 收到 403 或 429 回應,可以讓該代理休息幾分鐘,並將相同的請求發送到另一個代理。複製請求,刪除 meta 中的 proxy,開啟 dont_filter,然後返回,下一個代理就會接手。

簡單管理休息中的 proxy 列表和重新使用的時間。避免立即重複使用同一 IP,可以讓目標網站的限制有時間解除。

在Scrapy中如何節省帶寬?

Scrapy默認僅獲取HTML,比瀏覽器工具消耗少得多帶寬。啟用默認的HttpCompressionMiddleware接收壓縮響應可進一步減少傳輸量。這是共享計劃月帶寬內能採集大量頁面的原因。

開發時啟用HTTPCACHE_ENABLED可避免重複獲取頁面,減少測試時對目標網站與代理的請求。正式運行時保持去重功能(預設開啟),僅對必須重新獲取的請求使用dont_filter。

限制鏈接跟蹤範圍避免爬取不必要子頁面也很重要。明確收集範圍可節省時間、帶寬並減輕目標網站負擔。

如何解決常見問題?

出現407回應時,請檢查地址中的用戶名及密碼。若密碼包含特殊字符,需進行百分比編碼後輸入。TunnelError表示代理未收到CONNECT請求,請確認是否使用HTTP端口。

如果所有請求都經同一IP發出,可能係middleware順序中HttpProxyMiddleware排得太後,或者爬蟲直接喺meta加入proxy。請同時檢查settings.py嘅順序同爬蟲代碼。

Scrapy代理設置:meta proxy與輪換中間件 | Socks5Proxy