Use o solvethree em um middleware de download do Scrapy
Use um middleware de download assíncrono para resolver apenas as requisições que seu spider marcar explicitamente. Execute o SDK síncrono do solvethree em uma thread de trabalho e retorne uma FormRequest contendo o token, o proxy e a identidade de navegador retornada.
O exemplo trata um único endpoint de formulário reCAPTCHA Enterprise configurado. Ele não detecta desafios nem descobre como um site arbitrário espera receber seu token.
Nesta página
Configure o destino antes de habilitar o middleware
- Use Scrapy 2.19+, Python 3.10+ e o SDK oficial do solvethree para Python. O SDK é síncrono; não tem cliente assíncrono nativo.
- Crie um perfil de site ativo para seu workspace no console. Enviar um hostname e uma ação não cria um perfil. Consulte a configuração do perfil de site.
- Defina TARGET_URL como a URL exata de envio do formulário, SOLVETHREE_PROXY como o proxy usado nessa requisição da aplicação e SOLVETHREE_API_KEY como a chave do seu workspace. Mantenha a chave no lado do servidor.
- Habilite AsyncioSelectorReactor e registre o middleware com prioridade 740, como mostrado abaixo. Isso o coloca antes de HttpProxyMiddleware, na prioridade 750.
Resolva apenas requisições explicitamente marcadas
# middlewares.py; Scrapy 2.19+, Python 3.10+, official solvethree SDK.
import asyncio
import os
from urllib.parse import urlsplit
from scrapy.http import FormRequest
from solvethree import Solvethree
class CaptchaMiddleware:
async def process_request(self, request):
if not request.meta.get("solvethree_form") or request.meta.get("solvethree_applied"):
return None
target = os.environ["TARGET_URL"]
if request.url != target:
raise ValueError("Only the configured form target may use this middleware")
proxy = os.environ["SOLVETHREE_PROXY"]
def solve():
return Solvethree(os.environ["SOLVETHREE_API_KEY"]).solve({
"site": urlsplit(target).hostname, "action": "login", "proxy": proxy,
"requestId": request.meta["solvethree_request_id"],
}, timeout=180)
result = await asyncio.to_thread(solve)
solution = result["solution"]
fields = dict(request.meta["solvethree_fields"])
fields["g-recaptcha-response"] = solution["token"]
meta = {**request.meta, "proxy": proxy, "solvethree_applied": True,
"dont_retry": True, "dont_redirect": True}
return FormRequest(target, formdata=fields, callback=request.callback,
errback=request.errback, headers={"User-Agent": solution["userAgent"],
"sec-ch-ua": solution["secChUa"]}, meta=meta, dont_filter=True)
# settings.py:
# TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
# DOWNLOADER_MIDDLEWARES = {"myproject.middlewares.CaptchaMiddleware": 740}
# The spider first loads its form/CSRF data with the same proxy and cookiejar.
# Then yield a Request(TARGET_URL, callback=your_result_handler, meta={
# "solvethree_form": True, "solvethree_request_id": one_saved_logical_job_id,
# "solvethree_fields": {"csrf": token_from_the_form, "email": "your-test-value"},
# "cookiejar": your_cookiejar_id,
# })
# Inspect the final response in your_result_handler; a ready task is not that response.O método process_request do middleware recebe apenas request, sem o argumento spider obsoleto. Requisições não marcadas passam sem alterações. Uma requisição marcada deve corresponder exatamente a TARGET_URL; uma divergência gera um erro em vez de enviar um token para outro endpoint.
asyncio.to_thread mantém as chamadas de rede e as consultas periódicas do SDK síncrono fora da thread do loop de eventos. Apenas declarar process_request como async não faria isso. O SDK cria uma tarefa e aguarda um resultado pronto ou lança uma exceção; o middleware então monta o envio do formulário.
Use o formato do formulário que sua aplicação realmente envia
- 1.
Defina a ação e o campo de token corretos
O exemplo usa a ação login e coloca solution.token em g-recaptcha-response. Altere esses valores para corresponder à integração do destino. O campo site da tarefa é derivado do hostname de TARGET_URL; tarefas de reCAPTCHA não recebem os campos type ou url. Omitir recaptchaType seleciona enterprise-v3.
- 2.
Forneça os campos existentes do formulário
O spider deve preencher solvethree_fields com os campos exigidos pelo endpoint, incluindo seu valor CSRF atual. O middleware copia esses campos e adiciona o token; ele não carrega o formulário nem extrai campos ocultos.
- 3.
Mantenha a sessão consistente
Carregue o formulário inicial pelo mesmo proxy e com a mesma identidade de navegador exigidos pela aplicação. Passe o ID de cookiejar nos metadados da requisição marcada. A FormRequest retornada mantém esse cookiejar e usa solution.userAgent e solution.secChUa, mas o exemplo não prepara nem corrige a sessão anterior.
- 4.
Trate a resposta da aplicação
Forneça um callback que verifique se o envio do formulário foi bem-sucedido e um errback para falhas de requisição. Uma tarefa pronta significa que uma solução foi gerada, não que o site aceitou a requisição seguinte.
Este exemplo usa deliberadamente um único proxy para a resolução e o envio. Não o substitua por um proxy diferente após a resolução. Inspecione também qualquer middleware de download personalizado que reescreva User-Agent ou client hints: ele não deve sobrescrever a identidade retornada com a solução.
Evite que novas tentativas criem outra resolução
Salve solvethree_request_id antes de produzir a requisição marcada com yield e mantenha-o para essa resolução lógica. Um requestId aceita de 1–64 letras ASCII, números, sublinhados ou hífens. Reutilizá-lo com dados de entrada idênticos recupera a tarefa existente; alterar esses dados mantendo o ID gera um conflito.
A FormRequest retornada define solvethree_applied para não acionar outra resolução. Ela também define dont_retry e dont_redirect, impedindo novas tentativas e redirecionamentos automáticos para esse envio. Essas flags não impedem que seu próprio callback ou executor de jobs inicie outra requisição, portanto tome essa decisão explicitamente.
- A chamada de resolução excede o tempo limite.
Verifique se uma tarefa já foi criada. Um tempo limite de conexão não comprova que a criação falhou.
Experimente: Recupere a tarefa conhecida ou recupere-a usando o requestId salvo e as mesmas entradas da tarefa antes de criar uma nova resolução lógica.
- A resolução lança uma exceção em vez de retornar um resultado.
Diferencie um erro de requisição HTTP de uma falha terminal da tarefa. Para uma tarefa com falha, inspecione errorCode e error.
Experimente: Trate a falha em vez de continuar retornando a mesma requisição marcada com yield. Corrija as entradas inválidas antes de tentar novamente; tarefas com falha não devem continuar sendo consultadas.
- O site rejeita o formulário enviado.
Inspecione primeiro o campo de token enviado, os campos CSRF, os cookies, o proxy e a identidade do navegador.
Experimente: Corrija a requisição da aplicação antes de pagar por outra resolução. O campo deve conter solution.token, não o ID da tarefa nem um token antigo.
Fontes e referência da API
Execute sua primeira tarefa.
Comece com $5 em créditos no espaço de trabalho.