Resposta rápida
Como usar proxies rotativos com Scrapy?
Defina request.meta["proxy"] para http://USERNAME:[email protected]:7777 num middleware enxuto que roda antes do HttpProxyMiddleware do Scrapy; Scrapy então envia as credenciais para você. Com proxies residenciais CrawlRelay, o país e sessão fixa vão no nome de usuário, assim um middleware trata os dois casos. O tráfego custa US$ 0,50/GB a partir de 50 GB. Pague com cripto, sem KYC.
Configuração Scrapy resumida
| Onde colocar o proxy | request.meta["proxy"], definido pelo seu middleware |
|---|---|
| Ordem do middleware | Seu middleware abaixo de 750, a prioridade do HttpProxyMiddleware builtin |
| Credenciais | Na URL do proxy; Scrapy converte para um header Proxy-Authorization |
| SOCKS5 | Não com o handler HTTP/1.1 padrão; Scrapy 2.17+ suporta SOCKS usando o HttpxDownloadHandler opcional. A porta HTTP 7777 é a mais simples |
| Rotação | Nova saída a cada conexão nova; um ID de sessão único por requisição normalmente gera IP diferente |
| Etiqueta | ROBOTSTXT_OBEY, CONCURRENT_REQUESTS_PER_DOMAIN, AUTOTHROTTLE_ENABLED |
| Retries | 429 e erros 5xx estão no RETRY_HTTP_CODES padrão; Retry-After não é lido por padrão |
Como escrever o middleware de proxy?
Coloque a classe em middlewares.py. Ela monta o nome de usuário a partir das configurações e de três chaves opcionais meta: proxy_country, proxy_session e proxy_ttl. Uma requisição sem proxy_session rotaciona; com proxy_session="new" cria uma sessão nova, logo IP de saída normalmente diferente; com ID fixo de sessão, compartilha saída com outras do mesmo fluxo. O middleware recalcula seu proxy a cada passagem, incluindo retries, e não altera um proxy definido por outro código. Se CRAWLRELAY_USER faltar, o crawl para no início ao invés de rodar com seu próprio 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 NoneQuais configurações do Scrapy mantêm um crawl via proxy educado e rápido?
Proxies distribuem suas requisições por muitos IPs, mas o alvo ainda vê a taxa total. Essas configurações mantêm o ritmo sustentável em cada domínio e deixam o AutoThrottle desacelerar sozinho quando respostas atrasam. Mantenha ROBOTSTXT_OBEY = True, que novos projetos Scrapy já definem.
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 = 45Como mantenho um IP fixo para paginação e rotaciono para páginas de itens?
Passe um proxy_session fixo nas requisições de um fluxo que depende da página anterior, e nenhum nas páginas independentes. O spider abaixo roda em books.toscrape.com, um site sandbox publicado para prática de scraping.
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,
}O Scrapy reutiliza conexões e isso impede a rotação?
Sim, o Scrapy mantém conexões ativas e as reutiliza por proxy e host alvo, então requisições consecutivas numa conexão compartilham uma saída. Para a maioria dos crawls isso é ótimo: o Scrapy abre até CONCURRENT_REQUESTS_PER_DOMAIN conexões por site, e cada nova conexão geralmente recebe um IP residencial diferente.
Quando uma requisição deve sair por um novo IP, por exemplo, uma nova tentativa após um erro 502 de saída com problema, reemita usando response.request.replace(meta={**response.meta, "proxy_session": "new"}, dont_filter=True). O middleware constrói um novo nome de usuário de sessão, nomes diferentes significam pools diferentes de conexão, assim o Scrapy abre uma conexão nova e o gateway normalmente atribui uma saída diferente.
Como respeitar Retry-After em respostas 429 no Scrapy?
O RetryMiddleware interno do Scrapy tenta novamente no 429, mas não espera o delay Retry-After. AutoThrottle desacelera o domínio com o tempo, o que geralmente basta. Para APIs que enviam valores Retry-After longos, adicione um pequeno middleware que lê o header e agenda a nova tentativa com atraso, ou diminua CONCURRENT_REQUESTS_PER_DOMAIN para esse domínio. A página 429 explica o que o header significa.
Como usar o proxy com scrapy-playwright?
Para páginas que precisam de JavaScript, scrapy-playwright passa as opções de launch do Playwright por uma configuração. Forneça as credenciais em campos separados: Chromium ignora credenciais embutidas na URL do servidor. Use um contexto por sessão fixa se renderizar fluxos desconectados em várias páginas.
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 e proxies: perguntas
Preciso de scrapy-rotating-proxies ou uma lista de proxies?
Não. Esses pacotes rotacionam uma lista de endereços proxy individuais e bloqueiam os que falham. Com um gateway residencial, a rotação ocorre atrás de um único endereço: cada nova conexão geralmente obtém um IP residencial diferente. Um único middleware que seta request.meta["proxy"] é tudo que você precisa.
Por que o Scrapy mostra TunnelError com meu proxy?
Quantas requisições concorrentes por domínio devo usar?
Comece com 2 a 4 por domínio e deixe o AutoThrottle ajustar. Aumente o número apenas enquanto a porcentagem de respostas 429, 403 e 5xx permanecer constante e observe os tempos de resposta do site. Sites grandes toleram mais requisições que sites pequenos; um site pequeno pode precisar de atraso entre requisições e uma única conexão.
Devo desabilitar ROBOTSTXT_OBEY para pegar mais dados?
Não. O robots.txt é como o site informa quais caminhos clientes automatizados podem acessar, e o formato foi padronizado pelo RFC 9309 em 2022. Ignorar isso aumenta seu risco legal e ético e viola nossa Política de Uso Aceitável quando usado para acessar conteúdo que o site excluiu.
Quanto tráfego um crawl Scrapy consome?
O Scrapy baixa só HTML, então páginas costumam custar dezenas de kilobytes cada, comprimidos. Verifique o valor downloader/response_bytes nas estatísticas que o Scrapy imprime ao final da execução e divida pelo número de respostas. O guia de banda transforma isso num custo.
Conecte IPs residenciais ao seu projeto Scrapy
US$ 5,94 para 10 GB para testar, US$ 0,50/GB a partir de 50 GB.