Scrapy 다운로더 미들웨어에서 solvethree 사용하기
비동기 다운로더 미들웨어를 사용해 스파이더가 명시적으로 표시한 요청만 해결하세요. 동기 solvethree SDK를 작업자 스레드에서 실행한 다음 토큰, 프록시, 반환된 브라우저 식별 정보를 포함하는 FormRequest를 반환하세요.
예제는 설정된 reCAPTCHA Enterprise 폼 엔드포인트 하나를 처리합니다. 챌린지를 감지하거나 임의의 웹사이트가 어떤 방식으로 토큰을 요구하는지 알아내지는 않습니다.
이 페이지의 내용
미들웨어 활성화 전 대상 설정
- Scrapy 2.19+, Python 3.10+, 공식 solvethree Python SDK를 사용하세요. SDK는 동기식이며 네이티브 비동기 클라이언트는 없습니다.
- 콘솔에서 워크스페이스의 활성 사이트 프로필을 생성하세요. 호스트 이름과 액션을 전송한다고 프로필이 생성되지는 않습니다. 사이트 프로필 설정을 참고하세요.
- TARGET_URL은 정확한 폼 제출 URL로, SOLVETHREE_PROXY는 이 애플리케이션 요청에 사용할 프록시로, SOLVETHREE_API_KEY는 워크스페이스 키로 설정하세요. 키는 서버 측에 보관하세요.
- 아래와 같이 AsyncioSelectorReactor를 활성화하고 미들웨어를 우선순위 740으로 등록하세요. 이렇게 하면 우선순위 750인 HttpProxyMiddleware보다 앞에 배치됩니다.
명시적으로 표시한 요청만 해결
# 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.미들웨어의 process_request 메서드는 더 이상 사용되지 않는 spider 인수 없이 request만 받습니다. 표시되지 않은 요청은 변경 없이 통과합니다. 표시된 요청은 TARGET_URL과 정확히 일치해야 합니다. 일치하지 않으면 다른 엔드포인트에 토큰을 보내는 대신 오류를 발생시킵니다.
asyncio.to_thread는 동기 SDK의 네트워크 호출과 폴링이 이벤트 루프 스레드에서 실행되지 않도록 합니다. process_request를 단순히 async로 선언하는 것만으로는 이렇게 동작하지 않습니다. SDK는 작업을 생성하고 준비된 결과를 기다리거나 예외를 발생시키며, 이후 미들웨어가 폼 제출 요청을 구성합니다.
애플리케이션이 실제로 제출하는 폼에 맞추기
- 1.
올바른 액션 및 토큰 필드 설정
예제는 login 액션을 사용하고 solution.token을 g-recaptcha-response에 넣습니다. 대상의 통합 방식에 맞게 변경하세요. 작업의 site는 TARGET_URL의 호스트 이름에서 가져옵니다. reCAPTCHA 작업은 type이나 url 필드를 받지 않습니다. recaptchaType을 생략하면 enterprise-v3가 선택됩니다.
- 2.
기존 폼 필드 제공
스파이더는 현재 CSRF 값을 포함해 엔드포인트에 필요한 필드를 solvethree_fields에 채워야 합니다. 미들웨어는 이 필드를 복사하고 토큰을 추가할 뿐, 폼을 로드하거나 숨겨진 입력 필드를 추출하지 않습니다.
- 3.
세션 일관성 유지
애플리케이션이 요구하는 동일한 프록시와 브라우저 식별 정보를 사용해 초기 폼을 로드하세요. 해당 cookiejar ID를 표시된 요청의 메타데이터에 전달하세요. 반환된 FormRequest는 그 cookiejar를 유지하고 solution.userAgent와 solution.secChUa를 사용하지만, 예제는 이전 세션을 준비하거나 복구하지 않습니다.
- 4.
애플리케이션 응답 처리
폼 제출 성공 여부를 확인하는 콜백과 요청 실패를 처리하는 errback을 제공하세요. 작업이 준비되었다는 것은 솔루션이 생성되었다는 뜻이지 웹사이트가 후속 요청을 수락했다는 뜻은 아닙니다.
이 예제는 의도적으로 해결 작업과 제출에 프록시 하나를 사용합니다. 해결 후 관련 없는 프록시로 교체하지 마세요. User-Agent나 클라이언트 힌트를 다시 쓰는 사용자 정의 다운로더 미들웨어도 검사하세요. 솔루션과 함께 반환된 식별 정보를 덮어쓰면 안 됩니다.
재시도로 추가 해결 작업이 생성되지 않도록 방지
표시된 요청을 yield하기 전에 solvethree_request_id를 저장하고 해당 논리적 해결 작업에 계속 사용하세요. requestId에는 1–64자의 ASCII 영문자, 숫자, 밑줄 또는 하이픈을 사용할 수 있습니다. 동일한 작업 입력으로 재사용하면 기존 작업을 복구합니다. ID를 유지한 채 입력을 변경하면 충돌이 발생합니다.
반환된 FormRequest는 추가 해결 작업을 실행하지 않도록 solvethree_applied를 설정합니다. dont_retry와 dont_redirect도 설정해 해당 제출의 자동 재시도와 리디렉션을 방지합니다. 이 플래그는 자체 콜백이나 작업 실행기가 다른 요청을 시작하는 것까지 막지는 않으므로, 그 여부는 명시적으로 결정하세요.
- 해결 호출이 시간 초과됩니다.
작업이 이미 생성되었는지 확인하세요. 연결 시간 초과만으로 생성 실패가 확정되지는 않습니다.
다음을 시도해 보세요: 새 논리적 해결 요청을 생성하기 전에 기존 작업을 조회하거나, 저장한 requestId와 동일한 작업 입력을 사용해 복구하세요.
- 해결 과정에서 결과를 반환하는 대신 예외가 발생합니다.
HTTP 요청 오류와 최종 상태인 작업 실패를 구분하세요. 실패한 작업은 errorCode와 error를 확인하세요.
다음을 시도해 보세요: 동일한 표시된 요청을 반복해서 yield하지 말고 실패를 처리하세요. 다시 시도하기 전에 잘못된 입력을 수정하세요. 실패한 작업은 계속 폴링하면 안 됩니다.
- 웹사이트가 제출된 양식을 거부합니다.
먼저 전송되는 토큰 필드, CSRF 필드, 쿠키, 프록시, 브라우저 식별 정보를 확인하세요.
다음을 시도해 보세요: 다른 해결 요청에 비용을 지불하기 전에 애플리케이션 요청을 수정하세요. 필드에는 작업 ID나 오래된 토큰이 아닌 solution.token이 들어 있어야 합니다.
출처 및 API 레퍼런스
첫 작업을 실행하세요.
워크스페이스 크레딧 $5로 시작하세요.