You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
5.7 KiB
189 lines
5.7 KiB
from __future__ import absolute_import
|
|
|
|
import requests
|
|
|
|
try:
|
|
from urlparse import urlparse
|
|
except ImportError:
|
|
from urllib.parse import urlparse
|
|
|
|
from ..exceptions import (
|
|
CaptchaServiceUnavailable,
|
|
CaptchaAPIError,
|
|
CaptchaTimeout,
|
|
CaptchaParameter,
|
|
CaptchaBadJobID
|
|
)
|
|
|
|
try:
|
|
import polling2
|
|
except ImportError:
|
|
raise ImportError("Please install the python module 'polling2' via pip")
|
|
|
|
from . import Captcha
|
|
|
|
|
|
class captchaSolver(Captcha):
|
|
def __init__(self):
|
|
super(captchaSolver, self).__init__('capsolver')
|
|
self.host = 'https://api.capsolver.com'
|
|
self.session = requests.Session()
|
|
self.captchaType = {
|
|
'reCaptcha': 'ReCaptchaV2Task',
|
|
'hCaptcha': 'HCaptchaTask',
|
|
'turnstile': 'AntiCloudflareTask'
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------- #
|
|
|
|
@staticmethod
|
|
def checkErrorStatus(response, fnct):
|
|
if response.status_code in [500, 502]:
|
|
raise CaptchaServiceUnavailable(f'CapSolver: Server Side Error {response.status_code}')
|
|
|
|
try:
|
|
rPayload = response.json()
|
|
except Exception:
|
|
return
|
|
|
|
if rPayload.get('errorDescription', False) and 'Current system busy' not in rPayload['errorDescription']:
|
|
raise CaptchaAPIError(
|
|
f"CapSolver -> {fnct} -> {rPayload.get('errorDescription')}"
|
|
)
|
|
|
|
# ------------------------------------------------------------------------------- #
|
|
|
|
def requestJob(self, jobID):
|
|
if not jobID:
|
|
raise CaptchaBadJobID("CapSolver: Error bad job id to request task result.")
|
|
|
|
def _checkRequest(response):
|
|
self.checkErrorStatus(response, 'requestJob')
|
|
try:
|
|
if response.ok and response.json()['status'] == 'ready':
|
|
return True
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
response = polling2.poll(
|
|
lambda: self.session.post(
|
|
f'{self.host}/getTaskResult',
|
|
json={
|
|
'clientKey': self.api_key,
|
|
'taskId': jobID
|
|
},
|
|
timeout=30
|
|
),
|
|
check_success=_checkRequest,
|
|
step=5,
|
|
timeout=180
|
|
)
|
|
|
|
if response:
|
|
try:
|
|
rPayload = response.json()['solution']
|
|
if 'token' in rPayload:
|
|
return rPayload['token']
|
|
else:
|
|
return rPayload['gRecaptchaResponse']
|
|
except Exception:
|
|
pass
|
|
|
|
raise CaptchaTimeout(
|
|
"CapSolver: Error failed to solve Captcha."
|
|
)
|
|
|
|
# ------------------------------------------------------------------------------- #
|
|
|
|
def requestSolve(self, captchaType, url, siteKey):
|
|
|
|
# ------------------------------------------------------------------------------- #
|
|
|
|
def _checkRequest(response):
|
|
self.checkErrorStatus(response, 'createTask')
|
|
try:
|
|
rPayload = response.json()
|
|
if response.ok:
|
|
if rPayload.get("taskId", False):
|
|
return True
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
# ------------------------------------------------------------------------------- #
|
|
|
|
payload = {
|
|
'clientKey': self.api_key,
|
|
'appId': '9E717405-8C70-49B3-B277-7C2F2196484B',
|
|
'task': {
|
|
'type': self.captchaType[captchaType],
|
|
'websiteURL': url,
|
|
'websiteKey': siteKey
|
|
}
|
|
}
|
|
|
|
if captchaType == 'turnstile':
|
|
payload['task']['metadata'] = {'type': 'turnstile'}
|
|
|
|
if self.proxy:
|
|
payload['task']['proxy'] = self.proxy
|
|
else:
|
|
payload['task']['type'] = f"{self.captchaType[captchaType]}Proxyless"
|
|
|
|
response = polling2.poll(
|
|
lambda: self.session.post(
|
|
f'{self.host}/createTask',
|
|
json=payload,
|
|
allow_redirects=False,
|
|
timeout=30
|
|
),
|
|
check_success=_checkRequest,
|
|
step=5,
|
|
timeout=180
|
|
)
|
|
|
|
if response:
|
|
rPayload = response.json()
|
|
if rPayload.get('taskId'):
|
|
return rPayload['taskId']
|
|
|
|
raise CaptchaBadJobID(
|
|
'CapSolver: Error no job id was returned.'
|
|
)
|
|
|
|
# ------------------------------------------------------------------------------- #
|
|
|
|
def getCaptchaAnswer(self, captchaType, url, siteKey, captchaParams):
|
|
if not captchaParams.get('api_key'):
|
|
raise CaptchaParameter("CapSolver: Missing api_key parameter.")
|
|
self.api_key = captchaParams.get('api_key')
|
|
|
|
if captchaParams.get('proxy') and not captchaParams.get('no_proxy'):
|
|
hostParsed = urlparse(captchaParams.get('proxy', {}).get('https'))
|
|
|
|
if not hostParsed.scheme:
|
|
raise CaptchaParameter('Cannot parse proxy correctly, bad scheme')
|
|
|
|
if not hostParsed.netloc:
|
|
raise CaptchaParameter('Cannot parse proxy correctly, bad netloc')
|
|
|
|
self.proxy = captchaParams['proxy']['https']
|
|
else:
|
|
self.proxy = None
|
|
|
|
try:
|
|
jobID = self.requestSolve(captchaType, url, siteKey)
|
|
return self.requestJob(jobID)
|
|
except polling2.TimeoutException:
|
|
raise CaptchaTimeout(
|
|
f"CapSolver: Captcha solve (task ID: {jobID}) took to long."
|
|
)
|
|
|
|
raise CaptchaAPIError('CapSolver: Job Failure.')
|
|
|
|
|
|
# ------------------------------------------------------------------------------- #
|
|
|
|
captchaSolver()
|