Middleware ของ proxy ใน Scrapy: คู่มือการตั้งค่าฉบับสมบูรณ์ (2026)

เผยแพร่เมื่อ 4 มิถุนายน 2026 · อ่าน ≈11 นาที

Scrapy ยังคงเป็นเครื่องมือหลักสำหรับการ crawl ในระดับ production ในปี 2026 — และยังเป็นเฟรมเวิร์กที่ทำให้คนสับสนกับการตั้งค่า proxy มากที่สุด เพราะมีถึงสี่จุดที่คุณเสียบ proxy เข้าไปได้ และสามในนั้นไม่เหมาะกับโปรเจกต์ส่วนใหญ่ คู่มือนี้จะให้จุดที่ถูกต้องกับคุณ: middleware แบบกำหนดเองขนาดเล็กที่มีการกำหนดเส้นทางต่อ request, sticky sessions, การตรวจจับการแบน และพฤติกรรมการ retry ที่สมเหตุสมผล

หากคุณใช้ requests/httpx/aiohttp ธรรมดาแทน ดูที่ วิธีหมุนเวียน Proxy ใน Python บทความนี้เจาะจงเฉพาะ Scrapy

เวอร์ชัน 30 วินาที

สำหรับ gateway แบบ residential ที่หมุนเวียน การตั้งค่าขั้นต่ำที่ใช้งานได้คือหนึ่งบรรทัดต่อ request — ไม่ต้องใช้ middleware:

def start_requests(self):
    for url in self.urls:
        yield scrapy.Request(
            url,
            meta={"proxy": "http://USERNAME:[email protected]:913"},
        )

HttpProxyMiddleware ที่มีมาในตัวของ Scrapy จะอ่าน request.meta["proxy"] และจัดการการยืนยันตัวตนจาก URL ให้ gateway จะหมุนเวียน exit IP ให้คุณเอง หากนี่คือทั้งหมดที่คุณต้องการ หยุดตรงนี้ได้เลย ส่วนที่เหลือของคู่มือนี้มีไว้สำหรับตอนที่คุณต้องการ การควบคุม: sticky sessions, การกำหนดเส้นทางตามประเทศ, การหมุนเวียนที่รับรู้การแบน และการปรับจูน concurrency

Proxy Middleware ระดับ Production

วางโค้ดนี้ลงใน middlewares.py มันจะกำหนด sticky session ต่อโดเมน หมุนเวียนเมื่อโดนแบน และติดแท็กทุก request เพื่อให้คุณดีบักได้ว่า session ไหนดึงอะไรมา:

import random
import string

GATEWAY = "us.jibaoproxy.com:913"
USERNAME = "USERNAME"          # move to settings.py / env in real projects
PASSWORD = "PASSWORD"

def _new_session(n=8):
    return "".join(random.choices(string.ascii_lowercase + string.digits, k=n))

class JibaoProxyMiddleware:
    """Sticky session per domain; rotate session on ban."""

    def __init__(self):
        self.sessions = {}          # domain -> session id

    def _proxy_url(self, session_id):
        user = f"{USERNAME}-session-{session_id}"
        return f"http://{user}:{PASSWORD}@{GATEWAY}"

    def process_request(self, request, spider):
        domain = request.url.split("/")[2]
        session = self.sessions.setdefault(domain, _new_session())
        request.meta["proxy"] = self._proxy_url(session)
        request.meta["proxy_session"] = session

    def rotate(self, domain):
        """Call when a session is burned."""
        self.sessions[domain] = _new_session()

และ downloader middleware คู่หูที่ตรวจจับการแบนและ retry บน session ใหม่:

from scrapy.downloadermiddlewares.retry import RetryMiddleware
from scrapy.utils.response import response_status_message

BAN_CODES = {403, 429}
BAN_MARKERS = (b"captcha", b"access denied", b"unusual traffic")

class BanAwareRetryMiddleware(RetryMiddleware):

    def process_response(self, request, response, spider):
        banned = (
            response.status in BAN_CODES
            or any(m in response.body[:2048].lower() for m in BAN_MARKERS)
        )
        if banned:
            domain = request.url.split("/")[2]
            proxy_mw = spider.crawler.engine.downloader.middleware.middlewares
            for mw in proxy_mw:
                if hasattr(mw, "rotate"):
                    mw.rotate(domain)        # burn the session
            reason = response_status_message(response.status)
            return self._retry(request, reason, spider) or response
        return super().process_response(request, response, spider)

เชื่อมต่อทั้งสองตัวเข้าด้วยกันใน settings.py:

DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.JibaoProxyMiddleware": 350,
    "scrapy.downloadermiddlewares.retry.RetryMiddleware": None,   # replace stock retry
    "myproject.middlewares.BanAwareRetryMiddleware": 550,
}
RETRY_TIMES = 2

ลำดับความสำคัญมีผล: proxy middleware ต้องทำงาน ก่อน HttpProxyMiddleware ของ Scrapy (750) ดังนั้นค่าใดก็ตามที่ต่ำกว่า 750 ใช้ได้ ค่า 350 ทำให้มันทำงานเร็วและคาดเดาได้

Sticky vs Rotating: โหมดไหนสำหรับ Spider แบบไหน

ประเภทการ Crawlโหมดการนำไปใช้
การเก็บเกี่ยวหน้าเว็บแบบไร้สถานะหมุนเวียนusername เปล่า gateway หมุนเวียนต่อ request
Login + crawl หลังการยืนยันตัวตนSticky ต่อบัญชี-session-{account_id}, ห้ามหมุนเวียนกลางการ login
รายการที่มีการแบ่งหน้าจำนวนมากSticky ต่อโดเมน หมุนเวียนเมื่อโดนแบนmiddleware ด้านบน
ราคาเฉพาะตามภูมิภาคหมุนเวียน + ปักหมุดประเทศพารามิเตอร์รูปแบบ USERNAME-country-de

การวิเคราะห์เชิงลึกเกี่ยวกับการแลกเปลี่ยนนี้: Sticky vs Rotating Proxy Sessions

การตั้งค่า Concurrency ที่ไม่ทำให้คุณโดนแบน

ค่าเริ่มต้นของ Scrapy ถูกปรับจูนมาสำหรับการ crawl แบบสุภาพด้วย IP เดียว เมื่ออยู่หลัง pool ที่หมุนเวียน คุณสามารถเร่งได้แรงกว่ามาก — แต่ขีดจำกัดต่อโดเมนยังคงสำคัญ เพราะ เป้าหมาย มองเห็นพฤติกรรมโดยรวม:

# settings.py - sane starting point behind a residential pool
CONCURRENT_REQUESTS = 64
CONCURRENT_REQUESTS_PER_DOMAIN = 8     # what the target experiences
DOWNLOAD_DELAY = 0.25                  # jitter applied per slot
RANDOMIZE_DOWNLOAD_DELAY = True        # 0.5x-1.5x the delay
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_TARGET_CONCURRENCY = 6.0
DOWNLOAD_TIMEOUT = 30
ROBOTSTXT_OBEY = True

เพิ่มค่า CONCURRENT_REQUESTS_PER_DOMAIN เฉพาะหลังจากเฝ้าดูอัตรา 403 ที่ระดับปัจจุบันไปสักสองสามพัน request การกระโดดจาก 8 → 32 เพราะ "ยังไง proxy ก็หมุนเวียน" คือวิธีที่คนเผาผลาญ GB ไปกับการ retry

วินัยด้านแบนด์วิดท์ (GB ของ Residential คือเงิน)

ความล้มเหลวที่พบบ่อยและความหมายที่แท้จริง

407 Proxy Authentication Required

credentials ไปไม่ถึง proxy ใส่มันลงใน URL (http://user:pass@host:port) ใน meta["proxy"] — Scrapy จะ parse และตั้งค่า Proxy-Authorization ให้คุณ การตั้งค่า header เองด้วย และ ใช้ credentials ใน URL ด้วยทำให้เกิดความผิดเพี้ยนจากการ auth ซ้ำ เลือกอย่างใดอย่างหนึ่ง

TunnelError: Could not open CONNECT tunnel

เกือบทุกครั้งเป็น host/port ที่พิมพ์ผิด หรือเป้าหมาย HTTPS ผ่าน endpoint ที่ไม่อนุญาต CONNECT บนพอร์ตนั้น ตรวจสอบด้วย curl -x นอก Scrapy ก่อน

Spider ทำงานได้ 10 นาที แล้วทุกอย่างกลายเป็น 403

sticky session ของคุณอยู่นานเกินที่จะได้รับการต้อนรับ หรืออัตราต่อโดเมนของคุณร้อนเกินไป ban-aware middleware ด้านบนจัดการกรณีแรก ลดค่า CONCURRENT_REQUESTS_PER_DOMAIN สำหรับกรณีที่สอง หากเป็นเป้าหมายที่ตรวจสอบ JA4 ตัว TLS stack ของ Scrapy เองอาจเป็นตัวบ่งบอก — ดู JA3/JA4 อธิบาย ว่าทำไมไม่มี proxy ใดแก้ปัญหานั้นได้

เครื่องมือฟรี · ไม่ต้องสมัคร

ตรวจสอบรายการ proxy ของคุณก่อนการ crawl

วาง endpoints ลงใน Proxy Checker ของเรา: มันทดสอบการเชื่อมต่อ, latency, ระดับความนิรนาม และประเภท exit-IP เป็นชุด — จับ proxy ที่ตายแล้วหรือติดป้ายผิดก่อนที่ Scrapy จะเสียการ retry ไปกับมัน

ตรวจสอบ proxy ของฉัน →

เบื่อกับการคอยดูแลรายการฟรีไหม? residential gateway หนึ่งตัวแทนที่ทั้งหมดนั้น — รับ500MB ทราฟฟิกฟรี →

สรุป

ชี้ Spider ของคุณไปที่ Pool จริง

session แบบหมุนเวียนและ sticky residential บน gateway เดียว 500MB ทราฟฟิกฟรี ไว้ใช้ crawl

เริ่มทดลองใช้ฟรี

สำหรับผลิตภัณฑ์ IP ทุกประเภท · พูลโหนดขนาดมหึมาพร้อมใช้งานได้ทุกเมื่อ

สมัครสมาชิกตอนนี้และรับเงินคืนการเติมเงินสูงสุด 100%

ผู้ใช้ใหม่รับ 500MB เมื่อสมัครสมาชิก พร้อมโบนัสในการเติมเงินครั้งแรก ข้อเสนอมีระยะเวลาจำกัด