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

如何在請求中加入proxy?

在 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次請求中的1次。

啟用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?

登入流程或購物車等需維持cookie的連續操作,應使用相同IP。首次請求直接設置meta proxy,並在回調時將response.meta中的proxy值傳遞,Scrapy的中間件便不會更換IP。搭配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"])

如何暫時移除失敗的代理?

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

管理休息中的 proxy 列表和重新使用的時間,可以簡化操作。避免立即重複使用相同 IP,可以減少目標網站的限制。

在 Scrapy 中如何節省頻寬?

Scrapy 預設只接收 HTML,比瀏覽器工具節省大量頻寬。內建的 HttpCompressionMiddleware 會接收壓縮回應,進一步減少傳輸量。這是共享方案月流量內能爬取大量頁面的原因。

開發時啟用HTTPCACHE_ENABLED可避免重複請求,測試時不會反覆呼叫目標網站與代理。正式環境請保持過濾重複地址功能(預設開啟),僅對需重新獲取的請求使用dont_filter。

限制不必要的子頁面擴散範圍也很重要。明確設定收集範圍可節省時間、頻寬,並減輕目標網站的負擔。

如何解決常見問題?

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

如果所有請求都從同一個IP發出,可能是中間件順序在HttpProxyMiddleware之後,或是爬蟲直接設定了meta proxy。請檢查settings.py的順序和爬蟲代碼。

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