1import requests
2import time
3
4from six.moves.urllib_parse import urljoin
5from .exceptions import AnticaptchaException
6
7SLEEP_EVERY_CHECK_FINISHED = 3
8MAXIMUM_JOIN_TIME = 60 * 5
9
10
11class Job(object):
12    client = None
13    task_id = None
14    _last_result = None
15
16    def __init__(self, client, task_id):
17        self.client = client
18        self.task_id = task_id
19
20    def _update(self):
21        self._last_result = self.client.getTaskResult(self.task_id)
22
23    def check_is_ready(self):
24        self._update()
25        return self._last_result['status'] == 'ready'
26
27    def get_solution_response(self):  # Recaptcha
28        return self._last_result['solution']['gRecaptchaResponse']
29
30    def get_token_response(self):  # Funcaptcha
31        return self._last_result['solution']['token']
32
33    def get_answers(self):
34        return self._last_result['solution']['answers']
35
36    def get_captcha_text(self):  # Image
37        return self._last_result['solution']['text']
38
39    def report_incorrect(self):
40        return self.client.reportIncorrectImage(self.task_id)
41
42    def join(self, maximum_time=None):
43        elapsed_time = 0
44        maximum_time = maximum_time or MAXIMUM_JOIN_TIME
45        while not self.check_is_ready():
46            time.sleep(SLEEP_EVERY_CHECK_FINISHED)
47            elapsed_time += SLEEP_EVERY_CHECK_FINISHED
48            if elapsed_time is not None and elapsed_time > maximum_time:
49                raise AnticaptchaException(None, 250,
50                                           "The execution time exceeded a maximum time of {} seconds. It takes {} seconds.".format(
51                                               maximum_time, elapsed_time))
52
53
54class AnticaptchaClient(object):
55    client_key = None
56    CREATE_TASK_URL = "/createTask"
57    TASK_RESULT_URL = "/getTaskResult"
58    BALANCE_URL = "/getBalance"
59    REPORT_IMAGE_URL = "/reportIncorrectImageCaptcha"
60    SOFT_ID = 847
61    language_pool = "en"
62
63    def __init__(self, client_key, language_pool="en", host="api.anti-captcha.com", use_ssl=True):
64        self.client_key = client_key
65        self.language_pool = language_pool
66        self.base_url = "{proto}://{host}/".format(proto="https" if use_ssl else "http",
67                                                   host=host)
68        self.session = requests.Session()
69
70    @property
71    def client_ip(self):
72        if not hasattr(self, '_client_ip'):
73            self._client_ip = self.session.get('http://httpbin.org/ip').json()['origin']
74        return self._client_ip
75
76    def _check_response(self, response):
77        if response.get('errorId', False) == 11:
78            response['errorDescription'] = "{} Your missing IP address is {}.".format(response['errorDescription'],
79                                                                                      self.client_ip)
80        if response.get('errorId', False):
81            raise AnticaptchaException(response['errorId'],
82                                       response['errorCode'],
83                                       response['errorDescription'])
84
85    def createTask(self, task):
86        request = {"clientKey": self.client_key,
87                   "task": task.serialize(),
88                   "softId": self.SOFT_ID,
89                   "languagePool": self.language_pool,
90                   }
91        response = self.session.post(urljoin(self.base_url, self.CREATE_TASK_URL), json=request).json()
92        self._check_response(response)
93        return Job(self, response['taskId'])
94
95    def getTaskResult(self, task_id):
96        request = {"clientKey": self.client_key,
97                   "taskId": task_id}
98        response = self.session.post(urljoin(self.base_url, self.TASK_RESULT_URL), json=request).json()
99        self._check_response(response)
100        return response
101
102    def getBalance(self):
103        request = {"clientKey": self.client_key}
104        response = self.session.post(urljoin(self.base_url, self.BALANCE_URL), json=request).json()
105        self._check_response(response)
106        return response['balance']
107
108    def reportIncorrectImage(self, task_id):
109        request = {"clientKey": self.client_key,
110                   "taskId": task_id
111                   }
112        response = self.session.post(urljoin(self.base_url, self.REPORT_IMAGE_URL), json=request).json()
113        self._check_response(response)
114        return response.get('status', False) != False
115