Socks5Proxy

การตั้งค่าพร็อกซี Scrapy ใช้ meta proxy เพื่อใช้ IP ต่างกันในแต่ละคำขอ

คู่มือนี้จะอธิบายวิธีการเชื่อมต่อ HTTP Proxy ของ Socks5Proxy ด้วย meta proxy ใน Scrapy ดาวน์โหลด middleware สำหรับหมุนเวียนรายการที่ได้รับจาก API ตามคำขอ และการตั้งค่าความเร็วที่เหมาะสมกับเว็บไซต์เป้าหมาย

Scrapy จัดการพร็อกซีอย่างไร?

Scrapy มี HttpProxyMiddleware เปิดใช้งานโดย default หากกำหนดที่อยู่พร็อกซีใน meta ของคำขอ คำขอนั้นจะถูกส่งผ่านพร็อกซีนั้น และชื่อผู้ใช้และรหัสผ่านในที่อยู่จะถูกแปลงเป็นส่วนหัว Proxy-Authorization โดย middleware ที่อยู่ HTTPS จะถูกส่งผ่าน tunnel CONNECT

ตัวจัดการดาวน์โหลด default ของ Scrapy รองรับ HTTP Proxy หากต้องการ SOCKS5 จำเป็นต้องมีตัวจัดการแยกต่างหาก ดังนั้นใน Scrapy จึงแนะนำให้ใช้พอร์ต HTTP ของ IP เดียวกัน เนื่องจากเซิร์ฟเวอร์เป้าหมายจะเห็น IP เดียวกัน

ตัวอย่างใช้ IP 198.51.100.23 พอร์ต HTTP 8000 ชื่อผู้ใช้ spx_user และรหัสผ่าน spx_pass

pip install scrapy
scrapy startproject shop
cd shop

วิธีใส่พร็อกซีในการร้องขอแต่ละครั้ง?

เพียงเพิ่ม proxy ใน meta ของ Request เมื่อสร้างใน start_requests เมื่อร้องขอหน้าถัดไปใน callback ให้เพิ่มในลักษณะเดียวกัน หากต้องการรักษาเซสชันไว้ ให้ส่งค่า proxy จาก meta ของการตอบกลับก่อนหน้าเพื่อรักษา 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 อยู่แล้ว จะปล่อยไว้ตามเดิมเพื่อให้สามารถใช้ทั้งสองวิธีร่วมกัน

เก็บคีย์ 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 หนึ่งยังคงเดิม เช่น ส่งคำขอพร้อมกัน 50 ครั้งด้วย IP 500 ตัว แต่ละ IP จะใช้เฉลี่ย 1 ครั้งในทุก 10 คำขอ

เปิด AUTOTHROTTLE เพื่อปรับช่วงเวลาการส่งคำขออัตโนมัติตามความเร็วการตอบสนอง หากคำตอบ 429 เพิ่มขึ้น ใช้ RETRY_HTTP_CODES เพื่อลองใหม่ แต่มีวิธีลบพร็อกซี่ใน meta เพื่อให้มิดเดิลแวร์ใส่พร็อกซี่ถัดไปเมื่อลองใหม่

ควรมีขั้นตอนตรวจสอบใน pipeline ว่าผลลัพธ์ที่รวบรวมมาเป็นหน้าจริงหรือไม่ เพื่อปรับปรุงคุณภาพข้อมูล หากคำตอบไม่มีองค์ประกอบที่ต้องการสามารถให้ร้องขอใหม่ด้วย IP อื่น

  • ปรับจำนวนคำขอพร้อมกันต่อโดเมนให้ตรงกับจำนวน IP
  • AUTOTHROTTLE เพื่อปรับช่วงเวลาตามความเร็วการตอบสนอง
  • 429 และ 5xx ให้ลองใหม่ด้วย IP อื่น
  • การตรวจสอบเนื้อหาการตอบสนองเพื่อกรองหน้าตรวจสอบ

อะไรจะเปลี่ยนไปเมื่อเชื่อมต่อด้วยการรับรอง IP?

เมื่อลงทะเบียน IPv4 ของเซิร์ฟเวอร์ที่รัน Scrapy ในแดชบอร์ด คุณสามารถใช้ meta proxy โดยไม่ต้องใช้ชื่อผู้ใช้และรหัสผ่าน เช่น http://198.51.100.23:8000 และสามารถรับรายการในรูปแบบ format=ip:port หากรันสไปเดอร์บนเซิร์ฟเวอร์หลายเครื่อง ให้ลงทะเบียน IP ของแต่ละเซิร์ฟเวอร์ทั้งหมด (สูงสุด 10 IP)

วิธีการผูกคำขอที่ต้องการเซสชันกับ IP เดียวกัน?

สำหรับกระบวนการที่ต้องใช้คุกกี้ต่อเนื่อง เช่น การเข้าสู่ระบบหรือตะกร้าสินค้า ควรใช้ IP เดียวกัน ใส่ meta proxy โดยตรงในคำขอแรก และส่งค่า proxy จาก response.meta ไปยังคำขอถัดไปใน callback เพื่อให้ middleware ไม่เปลี่ยน IP การใช้ cookiejar meta key ของ Scrapy จะช่วยแยกคุกกี้สำหรับแต่ละเซสชัน

หากจับคู่ proxy หนึ่งตัวกับชุดคุกกี้หนึ่งชุดในแต่ละเซสชัน แม้จะรันหลายเซสชันพร้อมกันก็จะไม่ปะปนกัน

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"])

จะพัก proxy ที่ล้มเหลวชั่วคราวได้อย่างไร?

หากได้รับคำตอบ 403 หรือ 429 ใน middleware process_response คุณสามารถให้พร็อกซีนั้นพักสักครู่แล้วส่งคำขอเดิมไปยังพร็อกซีอื่นได้ โดยคัดลอกคำขอ ลบพร็อกซีออกจาก meta เปิด dont_filter แล้วส่งกลับไป คำขอจะถูกส่งไปยังพร็อกซีถัดไป

การจัดการรายการ proxy ที่พักและเวลาที่จะใช้ใหม่ใน dictionary จะทำให้ง่ายขึ้น การไม่ใช้ IP เดิมทันทีจะช่วยลดเวลาที่เว็บไซต์เป้าหมายจะปลดข้อจำกัด

ควรตั้งค่าอะไรใน Scrapy เพื่อประหยัดแบนด์วิธ?

Scrapy รับเฉพาะ HTML เป็นค่าเริ่มต้น จึงใช้แบนด์วิธน้อยกว่าเครื่องมือเบราว์เซอร์มาก นอกจากนี้ยังมี HttpCompressionMiddleware ที่เปิดใช้งานโดย default เพื่อรับการตอบสนองแบบบีบอัด ทำให้ปริมาณการส่งข้อมูลลดลงอีก นี่คือเหตุผลที่สามารถรวบรวมข้อมูลหน้าเพจจำนวนมากได้ภายในแบนด์วิธรายเดือนของแผน Shared

เพื่อไม่ให้รับหน้าเดิมซ้ำ เปิด HTTPCACHE_ENABLED ในระหว่างการพัฒนา จะไม่เรียกเว็บไซต์เป้าหมายและ Proxy ซ้ำทุกครั้งที่ทดสอบ ในขั้นปฏิบัติการ รักษาการกรองที่อยู่ซ้ำ (เปิดโดยค่าเริ่มต้น) และใช้ dont_filter เฉพาะกับคำขอที่จำเป็นต้องรับใหม่จริงๆ

การจำกัดขอบเขตการตามลิงก์เพื่อไม่ให้กระจายไปยังหน้าที่ย่อยที่ไม่จำเป็นก็สำคัญ การกำหนดขอบเขตการรวบรวมที่ชัดเจนจะช่วยลดเวลา แบนด์วิธ และภาระบนเว็บไซต์เป้าหมาย

วิธีแก้ไขปัญหาที่พบบ่อย?

หากได้รับคำตอบ 407 กรุณาตรวจสอบชื่อผู้ใช้และรหัสผ่านในที่อยู่ หากรหัสผ่านมีอักขระพิเศษ ต้องเข้ารหัสเปอร์เซ็นต์ก่อนนำมาใช้ TunnelError เกิดขึ้นเมื่อพร็อกซี่ไม่ได้รับคำขอ CONNECT กรุณาตรวจสอบว่าพอร์ตเป็นพอร์ต HTTP หรือไม่

หากคำขอทั้งหมดออกไปด้วย IP เดียวกัน อาจเป็นเพราะลำดับหมายเลข middleware อยู่หลัง HttpProxyMiddleware หรือ spider ใส่ meta proxy โดยตรง ตรวจสอบลำดับใน settings.py และโค้ด spider พร้อมกัน

การตั้งค่าพร็อกซี Scrapy ใช้ meta proxy และ middleware หมุนเวียน | Socks5Proxy