|
8 | 8 |
|
9 | 9 | import os, json
|
10 | 10 | from base64 import b64encode
|
| 11 | +from urllib import urlencode |
11 | 12 |
|
12 | 13 | # endpoints
|
13 | 14 | # -------------------------------------------------------------------------------------------
|
|
17 | 18 | BALANCE_ENDPOINT = 'http://captchatypers.com/Forms/RequestBalance.ashx'
|
18 | 19 | BAD_IMAGE_ENDPOINT = 'http://captchatypers.com/Forms/SetBadImage.ashx'
|
19 | 20 | PROXY_CHECK_ENDPOINT = 'http://captchatypers.com/captchaAPI/GetReCaptchaTextJSON.ashx'
|
| 21 | +GEETEST_SUBMIT_ENDPOINT = 'http://captchatypers.com/captchaapi/UploadGeeTest.ashx' |
| 22 | +GEETEST_RETRIEVE_ENDPOINT = 'http://captchatypers.com/captchaapi/getrecaptchatext.ashx' |
20 | 23 |
|
21 | 24 | CAPTCHA_ENDPOINT_CONTENT_TOKEN = 'http://captchatypers.com/Forms/UploadFileAndGetTextNEWToken.ashx'
|
22 | 25 | CAPTCHA_ENDPOINT_URL_TOKEN = 'http://captchatypers.com/Forms/FileUploadAndGetTextCaptchaURLToken.ashx'
|
|
25 | 28 | BALANCE_ENDPOINT_TOKEN = 'http://captchatypers.com/Forms/RequestBalanceToken.ashx'
|
26 | 29 | BAD_IMAGE_ENDPOINT_TOKEN = 'http://captchatypers.com/Forms/SetBadImageToken.ashx'
|
27 | 30 | PROXY_CHECK_ENDPOINT_TOKEN = 'http://captchatypers.com/captchaAPI/GetReCaptchaTextTokenJSON.ashx'
|
| 31 | +GEETEST_SUBMIT_ENDPOINT_TOKEN = 'http://captchatypers.com/captchaapi/UploadGeeTestToken.ashx' |
| 32 | + |
28 | 33 | # user agent used in requests
|
29 | 34 | # ---------------------------
|
30 | 35 | USER_AGENT = 'pythonAPI1.0'
|
@@ -76,6 +81,32 @@ def captcha_id(self):
|
76 | 81 | def response(self):
|
77 | 82 | return self._response
|
78 | 83 |
|
| 84 | +# Geetest class |
| 85 | +# --------------------------------- |
| 86 | +class Geetest: |
| 87 | + def __init__(self, captcha_id): |
| 88 | + self._captcha_id = captcha_id |
| 89 | + self._response = '' |
| 90 | + |
| 91 | + # set response |
| 92 | + def set_response(self, response): |
| 93 | + self._response = response |
| 94 | + |
| 95 | + @property |
| 96 | + def captcha_id(self): |
| 97 | + return self._captcha_id |
| 98 | + |
| 99 | + @property |
| 100 | + def response(self): |
| 101 | + s = self._response.split(';;;') |
| 102 | + if len(s) == 3: |
| 103 | + return { |
| 104 | + 'challenge': s[0], |
| 105 | + 'validate': s[1], |
| 106 | + 'seccode': s[2] |
| 107 | + } |
| 108 | + else: return self._response |
| 109 | + |
79 | 110 |
|
80 | 111 | # API class
|
81 | 112 | # -----------------------------------------
|
@@ -221,6 +252,81 @@ def submit_recaptcha(self, d):
|
221 | 252 |
|
222 | 253 | return self._recaptcha.captcha_id # return the ID
|
223 | 254 |
|
| 255 | + # submit geetest captcha |
| 256 | + def submit_geetest(self, d): |
| 257 | + # check if page_url and sitekey are != None |
| 258 | + if not d.has_key('domain'): raise Exception('domain is missing') |
| 259 | + if not d.has_key('challenge'): raise Exception('challenge is missing') |
| 260 | + if not d.has_key('gt'): raise Exception('gt is missing') |
| 261 | + d['action'] = 'UPLOADCAPTCHA' |
| 262 | + # credentials and url |
| 263 | + if self._username: |
| 264 | + d['username'] = self._username |
| 265 | + d['password'] = self._password |
| 266 | + url = GEETEST_SUBMIT_ENDPOINT |
| 267 | + else: |
| 268 | + d['token'] = self._access_token |
| 269 | + url = GEETEST_SUBMIT_ENDPOINT_TOKEN |
| 270 | + |
| 271 | + # affiliate ID |
| 272 | + if self._affiliate_id: d['affiliateid'] = self._affiliate_id |
| 273 | + |
| 274 | + url = '{}?{}'.format(url, urlencode(d)) |
| 275 | + # make request with all data |
| 276 | + response = self._session.post(url, data=d, |
| 277 | + headers=self._headers, timeout=self._timeout) |
| 278 | + response_text = response.text.encode('utf-8') # get text from response |
| 279 | + |
| 280 | + # check if we got an error |
| 281 | + # ------------------------------------------------------------- |
| 282 | + if 'ERROR:' in response_text and response_text.split('|') != 2: |
| 283 | + response_err = response_text.split('ERROR:')[1].strip() |
| 284 | + self._error = response_err |
| 285 | + raise Exception(response_err) # raise Ex |
| 286 | + |
| 287 | + self._geetest = Geetest(response_text) # init recaptcha obj with captcha_id (which is in the resp) |
| 288 | + return self._geetest.captcha_id # return the ID |
| 289 | + |
| 290 | + # retrieve geetest captcha |
| 291 | + def retrieve_geetest(self, captcha_id = None): |
| 292 | + # if captcha id is not specified, use the ID of the last captcha submited |
| 293 | + if not captcha_id: |
| 294 | + if not self._geetest: raise Exception('no geetest was submited previously, submit a captcha' |
| 295 | + ' first or give captcha_id as argument') # raise it |
| 296 | + captcha_id = self._geetest.captcha_id |
| 297 | + # create params dict (multipart) |
| 298 | + data = { |
| 299 | + 'action': 'GETTEXT', |
| 300 | + 'captchaid': captcha_id |
| 301 | + } |
| 302 | + # set URL |
| 303 | + if self._username: |
| 304 | + data['username'] = self._username |
| 305 | + data['password'] = self._password |
| 306 | + url = GEETEST_RETRIEVE_ENDPOINT |
| 307 | + else: |
| 308 | + data['token'] = self._access_token |
| 309 | + url = GEETEST_RETRIEVE_ENDPOINT |
| 310 | + |
| 311 | + url = '{}?{}'.format(url, urlencode(data)) |
| 312 | + # make request with all data |
| 313 | + response = self._session.get(url, |
| 314 | + headers=self._headers, timeout=self._timeout) |
| 315 | + response_text = response.text.encode('utf-8') # get text from response |
| 316 | + |
| 317 | + # check if we got an error |
| 318 | + # ------------------------------------------------------------- |
| 319 | + if 'ERROR:' in response_text and response_text.split('|') != 2: |
| 320 | + response_err = response_text.split('ERROR:')[1].strip() |
| 321 | + # if error is different than NOT_DECODED, save it to obj |
| 322 | + if response_err != 'NOT_DECODED': self._error = response_err |
| 323 | + |
| 324 | + raise Exception(response_err) # raise Ex |
| 325 | + |
| 326 | + self._geetest.set_response(response_text) # set response to recaptcha obj |
| 327 | + |
| 328 | + return self._geetest.response # return response |
| 329 | + |
224 | 330 | # retrieve recaptcha
|
225 | 331 | def retrieve_recaptcha(self, captcha_id = None):
|
226 | 332 | # if captcha id is not specified, use the ID of the last captcha submited
|
@@ -264,8 +370,14 @@ def retrieve_recaptcha(self, captcha_id = None):
|
264 | 370 | # check if captcha is still being decoded
|
265 | 371 | def in_progress(self, captcha_id = None):
|
266 | 372 | try:
|
267 |
| - self.retrieve_recaptcha(captcha_id) # retrieve captcha |
268 |
| - return False # captcha got decoded |
| 373 | + if self._geetest: |
| 374 | + # geetest |
| 375 | + self.retrieve_geetest(captcha_id) |
| 376 | + return False |
| 377 | + else: |
| 378 | + # recaptcha |
| 379 | + self.retrieve_recaptcha(captcha_id) # retrieve captcha |
| 380 | + return False # captcha got decoded |
269 | 381 | except Exception, ex:
|
270 | 382 | if 'NOT_DECODED' in str(ex): # if NOT_DECODED in response, it's 'OK'
|
271 | 383 | return True
|
|
0 commit comments