Zonder KYC — geen ID, geen selfie, geen documenten. Betaal met crypto: BTC, USDT, USDC, ETH, SOL, LTC
Taal: Nederlands
Aan de slag

Docs · Scrapy 2.x · middleware · AutoThrottle

Scrapy proxy middleware voor roterende residentiële proxy's

Een downloader middleware van 30 regels die per request het land en de sessie kiest, plus instellingen die een crawl netjes houden: robots.txt, per-domein gelijktijdigheid, AutoThrottle en retries.

Laatst bijgewerkt: · 6 min leestijd

Kort antwoord

Hoe gebruik ik roterende proxy's met Scrapy?

Stel request.meta["proxy"] in op http://USERNAME:[email protected]:7777 in een kleine downloader middleware die draait vóór Scrapy's HttpProxyMiddleware; Scrapy stuurt dan voor jou de inloggegevens mee. Met CrawlRelay mobiele 4G-proxy's gaan het land en de sticky sessie in de gebruikersnaam, zodat één middleware beide afhandelt. Verkeer kost US$ 0,50/GB vanaf 50 GB. Betaalbaar in crypto, zonder KYC.

Scrapy setup in één oogopslag

Waar de proxy komtrequest.meta["proxy"], ingesteld door je middleware
Middleware volgordeJe middleware onder 750, de prioriteit van de ingebouwde HttpProxyMiddleware
CredentialsIn de proxy-URL; Scrapy zet ze om in een Proxy-Authorization header
SOCKS5Niet met de standaard HTTP/1.1 handler; Scrapy 2.17+ ondersteunt SOCKS via de optionele HttpxDownloadHandler. De HTTP-poort 7777 is het eenvoudigst
RotatieNieuwe exit per nieuwe verbinding; een unieke sessie-ID per request geeft normaal een ander IP
NetheidROBOTSTXT_OBEY, CONCURRENT_REQUESTS_PER_DOMAIN, AUTOTHROTTLE_ENABLED
Retries429 en 5xx zitten in de standaard RETRY_HTTP_CODES; Retry-After wordt standaard niet gelezen

Hoe schrijf ik de proxy middleware?

Plaats de klasse in middlewares.py. Deze bouwt de gebruikersnaam op uit instellingen en drie optionele meta sleutels: proxy_country, proxy_session en proxy_ttl. Een request zonder proxy_session roteert; een request met proxy_session="new" krijgt een nieuwe sessie, dus normaal een ander exit-IP; een request met vaste sessie-ID deelt één exit met andere requests in dezelfde flow. De middleware herberekent zijn proxy bij elke doorgang, inclusief retries, en laat een proxy die door andere code is gezet ongemoeid. Ontbreekt CRAWLRELAY_USER, dan stopt de crawl bij opstarten in plaats van vanaf je eigen IP te draaien.

middlewares.py
import uuid
from urllib.parse import quote


class CrawlRelayProxyMiddleware:
    """Sets request.meta["proxy"]; Scrapy's HttpProxyMiddleware then sends the credentials."""

    def __init__(self, user, password, country):
        self.user, self.password, self.country = user, password, country

    @classmethod
    def from_crawler(cls, crawler):
        s = crawler.settings
        if not s.get("CRAWLRELAY_USER"):
            # Fail loudly: NotConfigured would only disable the middleware and crawl from your own IP
            raise ValueError("CRAWLRELAY_USER is not set: refusing to crawl without the proxy")
        return cls(s.get("CRAWLRELAY_USER"), s.get("CRAWLRELAY_PASSWORD", ""), s.get("CRAWLRELAY_COUNTRY", "us"))

    def process_request(self, request, spider=None):
        if "proxy" in request.meta and not request.meta.get("_crawlrelay"):
            return None  # a proxy set by other code: leave it alone
        parts = [self.user, "country", request.meta.get("proxy_country", self.country)]
        session = request.meta.get("proxy_session")
        if session == "new":  # a fresh session for this request (and for each of its retries)
            session = uuid.uuid4().hex[:12]
        if session:
            parts += ["session", session, "ttl", str(request.meta.get("proxy_ttl", 10))]
        username = "-".join(parts)
        request.meta["proxy"] = "http://%s:%[email protected]:7777" % (
            quote(username, safe=""), quote(self.password, safe=""))
        request.meta["_crawlrelay"] = True
        return None

Welke Scrapy-instellingen houden een proxied crawl netjes en snel?

Proxy's spreiden je requests over veel IP's, maar het doel ziet je totale tempo. Met deze instellingen houd je per domein een verantwoord tempo en kan AutoThrottle langzaam vertragen als de reacties trager worden. Houd ROBOTSTXT_OBEY = True aan, dat nieuwe Scrapy-projecten al instellen.

settings.py (excerpt)
import os

BOT_NAME = "myproject"
ROBOTSTXT_OBEY = True
USER_AGENT = "ExampleCrawler/1.0 (+https://example.com/crawler-info)"

CRAWLRELAY_USER = os.environ.get("CRAWLRELAY_USER")  # e.g. the username from your dashboard
CRAWLRELAY_PASSWORD = os.environ.get("CRAWLRELAY_PASSWORD")
CRAWLRELAY_COUNTRY = "us"

DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.CrawlRelayProxyMiddleware": 350,  # runs before HttpProxyMiddleware (750)
}

CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 4
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 1.0
AUTOTHROTTLE_MAX_DELAY = 30.0
AUTOTHROTTLE_TARGET_CONCURRENCY = 2.0

RETRY_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [429, 500, 502, 503, 504, 522, 524, 408]
DOWNLOAD_TIMEOUT = 45

Hoe houd ik één IP vast voor paginering en roteer ik voor itempagina's?

Geef een vaste proxy_session mee bij de verzoeken van een flow die afhankelijk is van de vorige pagina, en geen bij aparte pagina's. De onderstaande spider draait op books.toscrape.com, een sandboxsite gepubliceerd voor scraping-oefeningen.

spiders/catalog.py
import scrapy


class CatalogSpider(scrapy.Spider):
    name = "catalog"
    start_urls = ["https://books.toscrape.com/"]

    def parse(self, response):
        for href in response.css("article.product_pod h3 a::attr(href)").getall():
            # Product pages are independent: rotating exits
            yield response.follow(href, callback=self.parse_item)
        next_page = response.css("li.next a::attr(href)").get()
        if next_page:
            # The listing flow keeps one sticky exit for 30 minutes
            yield response.follow(next_page, callback=self.parse,
                                  meta={"proxy_session": "listing1", "proxy_ttl": 30})

    def parse_item(self, response):
        yield {
            "title": response.css("div.product_main h1::text").get(),
            "price": response.css("p.price_color::text").get(),
            "url": response.url,
        }

Herbruikt Scrapy verbindingen en stopt dat rotatie?

Ja, Scrapy houdt verbindingen levend en hergebruikt ze per proxy en doelhost, dus opeenvolgende verzoeken op één verbinding delen een exit. Voor de meeste crawls is dat prima: Scrapy opent tot CONCURRENT_REQUESTS_PER_DOMAIN verbindingen per site, en elke nieuwe verbinding krijgt meestal een ander residentieel IP.

Als een verzoek via een nieuw IP moet verlopen, bijvoorbeeld een retry na een 502 van een falende exit, stuur het dan opnieuw met response.request.replace(meta={**response.meta, "proxy_session": "new"}, dont_filter=True). De middleware bouwt een nieuwe sessie-gebruikersnaam, een andere gebruikersnaam betekent een ander connection pool, dus Scrapy opent een nieuwe verbinding en de gateway wijst normaal gesproken een andere exit toe.

Hoe houd ik rekening met Retry-After bij 429 reacties in Scrapy?

Scrapy's ingebouwde RetryMiddleware probeert 429 opnieuw maar wacht niet op de Retry-After vertraging. AutoThrottle vertraagt het domein na verloop van tijd, wat meestal genoeg is. Voor API's die lange Retry-After waarden sturen, voeg een kleine middleware toe die de header leest en de retry met vertraging plant, of verlaag de CONCURRENT_REQUESTS_PER_DOMAIN voor dat domein. De 429-pagina legt uit wat de header betekent.

Hoe gebruik ik de proxy met scrapy-playwright?

Voor pagina's die JavaScript nodig hebben, geeft scrapy-playwright de launchopties van Playwright door via een instelling. Geef de inloggegevens als aparte velden: Chromium negeert inloggegevens die in de server-URL staan. Gebruik één context per sticky sessie als je uitgelogde flows rendert die meerdere pagina's beslaan.

settings.py voor scrapy-playwright
import os

DOWNLOAD_HANDLERS = {
    "http": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
    "https": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
}
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"

PLAYWRIGHT_LAUNCH_OPTIONS = {
    "proxy": {
        "server": "http://gw.crawlrelay.com:7777",
        "username": os.environ.get("CRAWLRELAY_USER", "USERNAME") + "-country-us",
        "password": os.environ.get("CRAWLRELAY_PASSWORD", "PASSWORD"),
    },
}

Scrapy en proxies: vragen

Heb ik scrapy-rotating-proxies of een proxylijst nodig?

Nee. Die pakketten roteren een lijst met individuele proxyadressen en blokkeren de proxy's die falen. Met een residentiële gateway gebeurt rotatie achter één adres: elke nieuwe verbinding krijgt meestal een ander residentieel IP. Een enkele middleware die request.meta["proxy"] instelt is alles wat je nodig hebt.

Waarom toont Scrapy TunnelError met mijn proxy?

TunnelError: Could not open CONNECT tunnel betekent dat de proxy het CONNECT-verzoek voor een HTTPS-site weigerde of mislukte. De status in het bericht vertelt waarom: 407 betekent inloggegevens, 502 of 504 betekent de exit of het doel. Zie de 407 en 502 pagina's.

Hoeveel gelijktijdige verzoeken per domein moet ik gebruiken?

Begin met 2 tot 4 per domein en laat AutoThrottle aanpassen. Verhoog het aantal alleen als het aandeel van 429, 403 en 5xx reacties stabiel blijft, en let op de responstijden van de site. Grote sites verdragen meer dan kleine; een kleine site heeft mogelijk een vertraging tussen verzoeken nodig en één enkele verbinding.

Moet ik ROBOTSTXT_OBEY uitschakelen om meer data te krijgen?

Nee. robots.txt geeft aan welke paden geautomatiseerde gebruikers mogen ophalen, en RFC 9309 standaardiseerde het formaat in 2022. Het negeren vergroot je juridische en ethische risico en breekt ons Acceptable Use Policy als het gebruikt wordt om inhoud te bereiken die de site heeft uitgesloten.

Hoeveel verkeer gebruikt een Scrapy-crawl?

Scrapy downloadt alleen HTML, dus pagina's kosten meestal tientallen kilobytes elk, gecomprimeerd. Controleer de waarde downloader/response_bytes in de statistieken die Scrapy aan het eind van een run toont en deel die door het aantal responses. De bandbreedtegids zet dat om in een kostenindicatie.

Plug residentiële IP's in je Scrapy-project

US$ 5,94 voor 10 GB om te testen, US$ 0,50/GB van 50 GB.

Vanaf US$ 0,50/GB · zonder KYC

Aan de slag