Szybka odpowiedź
Jak korzystać z rotujących proxy rezydencjalnych w Scrapy?
Ustaw request.meta["proxy"] na http://USERNAME:[email protected]:7777 w małym middleware downloadera uruchamianym przed Scrapy’s HttpProxyMiddleware; Scrapy wtedy sam wysyła poświadczenia. Przy użyciu CrawlRelay proxy rezydencjalnych kraj i sticky session koduje się w nazwie użytkownika, więc jedno middleware obsługuje oba. Ruch kosztuje 0,50 USD/GB od 50 GB. Płatność w krypto, bez KYC.
Podstawowa konfiguracja Scrapy
| Gdzie podać proxy | request.meta["proxy"], ustawione przez twoje middleware |
|---|---|
| Kolejność middleware | Twoje middleware poniżej 750, co jest priorytetem wbudowanego HttpProxyMiddleware |
| Dane uwierzytelniające | W URL proxy; Scrapy zamienia je na nagłówek Proxy-Authorization |
| SOCKS5 | Nie z domyślnym handlerem HTTP/1.1; Scrapy 2.17+ obsługuje SOCKS przez opcjonalny HttpxDownloadHandler. Port HTTP 7777 jest najprostszy |
| Rotacja | Nowe wyjście na nowe połączenie; unikatowe ID sesji na żądanie zwykle daje inny IP |
| Grzeczność | ROBOTSTXT_OBEY, CONCURRENT_REQUESTS_PER_DOMAIN, AUTOTHROTTLE_ENABLED |
| Retry | 429 i 5xx są w domyślnym RETRY_HTTP_CODES; Retry-After domyślnie nie jest brane pod uwagę |
Jak napisać middleware proxy?
Umieść klasę w middlewares.py. Buduje nazwę użytkownika z ustawień i z trzech opcjonalnych kluczy meta: proxy_country, proxy_session i proxy_ttl. Żądanie bez proxy_session powoduje rotację; z proxy_session="new" tworzy nową sesję, więc normalnie inny exit IP; z ustalonym ID sesji dzieli jedno wyjście z innymi żądaniami tego samego flow. Middleware oblicza proxy przy każdym przejściu, łącznie z retry, i nie zmienia proxy ustawionego gdzie indziej. Jeśli brakuje CRAWLRELAY_USER, crawl zatrzymuje się na starcie zamiast działać z twojego IP.
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 NoneJakie ustawienia Scrapy utrzymują proxied crawl grzecznym i szybkim?
Proxy rozkładają twoje żądania na wiele IP, ale cel widzi łączną liczbę. Te ustawienia utrzymują każdy domenę w zrównoważonym tempie i pozwalają AutoThrottle zwolnić samemu, gdy reakcje się wydłużają. Zachowaj ROBOTSTXT_OBEY = True, które nowe projekty Scrapy już mają.
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 = 45Jak utrzymać ten sam IP dla paginacji i rotować dla stron z elementami?
Przekaż stałe proxy_session w żądaniach przepływu zależnego od poprzedniej strony, a żadnego na stronach niezależnych. Pająk poniżej działa na books.toscrape.com, stronie-sandbox opublikowanej do ćwiczeń z web scrapingu.
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,
}Czy Scrapy ponownie wykorzystuje połączenia i czy to przerywa rotację?
Tak, Scrapy utrzymuje połączenia aktywne i ponownie je wykorzystuje dla proxy rezydencjalne oraz docelowego hosta, więc kolejne żądania na jednym połączeniu korzystają z tego samego adresu wyjścia. Dla większości crawli jest to w porządku: Scrapy otwiera do CONCURRENT_REQUESTS_PER_DOMAIN połączeń na stronę, a każde nowe połączenie zazwyczaj dostaje inny residential IP.
Gdy żądanie musi wyjść przez nowy IP, np. po ponownej próbie po błędzie 502 z problematycznego wyjścia, wyślij je ponownie z response.request.replace(meta={**response.meta, "proxy_session": "new"}, dont_filter=True). Middleware tworzy nową nazwę użytkownika sesji, inna nazwa użytkownika oznacza inny pulę połączeń, więc Scrapy otwiera nowe połączenie, a brama zwykle przydziela inny exit.
Jak honorować Retry-After na odpowiedziach 429 w Scrapy?
Wbudowany w Scrapy RetryMiddleware ponawia żądania 429, ale nie czeka na opóźnienie Retry-After. AutoThrottle stopniowo zwalnia domenę, co najczęściej wystarcza. Dla API zwracających długie wartości Retry-After, dodaj mały middleware, który odczytuje nagłówek i planuje ponowienie z opóźnieniem lub zmniejsz CONCURRENT_REQUESTS_PER_DOMAIN dla tej domeny. Strona 429 tłumaczy, co oznacza ten nagłówek.
Jak używać proxy z scrapy-playwright?
Dla stron wymagających JavaScript scrapy-playwright przekazuje opcje uruchomienia Playwright przez ustawienia. Podaj dane uwierzytelniające jako oddzielne pola: Chromium ignoruje dane wpisane w adres serwera. Użyj jednego kontekstu na sticky session, jeśli renderujesz przepływy dla niezalogowanych użytkowników obejmujące kilka stron.
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 i proxy: pytania
Czy potrzebuję scrapy-rotating-proxies lub listy proxy?
Nie. Te pakiety rotują listę indywidualnych adresów proxy i blokują te, które zawodzą. W przypadku residential gateway rotacja odbywa się za jednym adresem: każde nowe połączenie zwykle dostaje inny residential IP. Wystarczy jeden middleware ustawiający request.meta["proxy"].
Dlaczego Scrapy pokazuje TunnelError z moim proxy?
Ile równoczesnych żądań na domenę powinienem używać?
Zacznij od 2 do 4 na domenę i pozwól AutoThrottle dostosować. Zwiększaj liczbę tylko wtedy, gdy udział odpowiedzi 429, 403 i 5xx pozostaje stały, i obserwuj czasy odpowiedzi serwisu. Duże serwisy tolerują więcej niż małe; mały serwis może wymagać opóźnienia między żądaniami i pojedynczego połączenia.
Czy powinienem wyłączyć ROBOTSTXT_OBEY, żeby dostać więcej danych?
Nie. robots.txt to sposób, w jaki serwis informuje, które ścieżki mogą pobierać automatyczni klienci, a format ten został ustandaryzowany w RFC 9309 w 2022 roku. Ignorowanie go zwiększa Twoje ryzyko prawne i etyczne oraz narusza naszą Politykę Akceptowalnego Użytkowania, gdy służy do dostępu do treści wykluczonych przez serwis.
Ile ruchu generuje crawl Scrapy?
Scrapy pobiera tylko HTML, więc strony zwykle kosztują kilkadziesiąt kilobajtów każda, skompresowane. Sprawdź wartość downloader/response_bytes w statystykach, które Scrapy wyświetla na koniec działania, i podziel ją przez liczbę odpowiedzi. Przewodnik po transferze danych przelicza to na koszt.
Podłącz residential IP do swojego projektu Scrapy
5,94 USD dla 10 GB do testów, 0,50 USD/GB z 50 GB.