当前位置:嗨网首页>书籍在线阅读

08-9kw入门

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

[toc]

7.4.1 9kw入门

要想开始使用9kw,首先需要创建一个账号,注册网址为 https://www.9kw.eu/register.html

然后,按照账号确认说明进行操作。登录后,我们被定位到 https://www.9kw.eu/usercaptcha.html

在本页中,需要处理其他用户的验证码来获取后面使用API时所需的积分。在处理了几个验证码之后,会被定位到 https://www.9kw.eu/index.cgi?action=userapinew&source=api 来创建API key。

9kw验证码API

9kw的API文档地址为 https://www.9kw.eu/api.html#apisubmit-tab 。我们用于提交验证码和检查结果的主要部分总结如下。

如果想要提交要解析的验证码,可以使用该API方法及参数。

URL:https://www.9kw.eu/index.cgi (POST)
apikey:你的API key
action:必须设为“usercaptchaupload”
file-upload-01:需要处理的图像(文件、url或字符串)
base64:如果输入是Base64编码,则设为“1”
maxtimeout:等待处理的最长时间(必须为60~3999秒)
selfsolve:如果自己处理该验证码,则设为“1”
json:如果要以JSON格式接收响应,则设为“1”
API返回值:该验证码的ID

如果想要请求已提交验证码的结果,需要使用不同的API方法和参数。

URL:https://www.9kw.eu/index.cgi (GET)
apikey:你的API key
action:必须设为“usercaptchacorrectdata”
id:要检查的验证码ID
info:若设为1,没有得到结果时返回“NO DATA”(默认返回空)
json:如果要以JSON格式接收响应,则设为“1”
API返回值:要处理的验证码文本或错误码

此外,API还有一些错误代码。

0001 API key不存在
0002 没有找到API key
0003 没有找到激活的API key
……
0031 账号被系统禁用24小时
0032 账号没有足够的权限
0033 需要升级插件

下面是发送验证码图像到该API的初始实现代码。

import requests
API_URL = 'https://www.9kw.eu/index.cgi'
def send_captcha(api_key, img_data):
    data = {
        'action': 'usercaptchaupload',
        'apikey': api_key,
        'file-upload-01': img_data,
        'base64': '1',
        'selfsolve': '1',
        'maxtimeout': '60',
        'json': '1',
    }
    response = requests.post(API_URL, data)
    return response.content

这个结构应该看起来很熟悉,首先我们创建了一个所需参数的字典,对其进行编码,然后将该数据作为请求体提交。需要注意的是,这里将 selfsolve 选项设为 '1' ,这种设置下,如果我们正在使用9kw的Web界面处理验证码,那么验证码图像就会传给我们自己处理,从而可以节约我们的积分。如果此时我们没有处于登录状态,验证码则会传给其他用户。

下面是获取验证码图像处理结果的代码。

def get_captcha_text(api_key, captcha_id):
    data = {
        'action': 'usercaptchacorrectdata',
        'id': captcha_id,
        'apikey': api_key,
        'json': '1',
    }
    response = requests.get(API_URL, data)
    return response.content

9kw的API的一个缺点是,错误信息是在与结果相同的JSON字段中传输的,这样就会使它们的区分更加复杂。例如,此时没有用户处理验证码图像,则会返回 ERROR NO USER 字符串。不过幸好我们提交的验证码图像永远不会包含这类文本。

另一个困难是,只有在其他用户有时间人工处理验证码图像时, get_captcha_text() 函数才能返回错误信息,正如之前提到的,通常要在30秒之后。

为了使实现更加友好,我们将会增加一个封装函数,用于提交验证码图像以及等待结果返回。下面的扩展版本代码把这些功能封装到一个可复用类当中,另外还增加了检查错误信息的功能。

import base64
import re
import time
import requests
from io import BytesIO
class CaptchaAPI:
    def __init__(self, api_key, timeout=120):
        self.api_key = api_key
        self.timeout = timeout
        self.url = 'https://www.9kw.eu/index.cgi'
    def solve(self, img):
        """Submit CAPTCHA and return result when ready"""
        img_buffer = BytesIO()
        img.save(img_buffer, format="PNG")
        img_data = img_buffer.getvalue()
        captcha_id = self.send(img_data)
        start_time = time.time()
        while time.time() < start_time + self.timeout:
            try:
                resp = self.get(captcha_id)
            except CaptchaError:
                pass # CAPTCHA still not ready
            else:
                if resp.get('answer') != 'NO DATA':
                    if resp.get('answer') == 'ERROR NO USER':
                        raise CaptchaError(
                            'Error: no user available to solve CAPTCHA')
                    else:
                        print('CAPTCHA solved!')
                        return captcha_id, resp.get('answer')
            print('Waiting for CAPTCHA ...')
            time.sleep(1)
        raise CaptchaError('Error: API timeout')
    def send(self, img_data):
        """Send CAPTCHA for solving """
        print('Submitting CAPTCHA')
        data = {
            'action': 'usercaptchaupload',
            'apikey': self.api_key,
            'file-upload-01': base64.b64encode(img_data),
            'base64': '1',
            'selfsolve': '1',
            'json': '1',
            'maxtimeout': str(self.timeout)
        }
        result = requests.post(self.url, data)
        self.check(result.text)
        return result.json()
    def get(self, captcha_id):
        """Get result of solved CAPTCHA """
        data = {
            'action': 'usercaptchacorrectdata',
            'id': captcha_id,
            'apikey': self.api_key,
            'info': '1',
            'json': '1',
        }
        result = requests.get(self.url, data)
        self.check(result.text)
        return result.json()
    def check(self, result):
        """Check result of API and raise error if error code"""
        if re.match('00dd w+', result):
            raise CaptchaError('API error: ' + result)
    def report(self, captcha_id, correct):
        """ Report back whether captcha was correct or not"""
        data = {
            'action': 'usercaptchacorrectback',
            'id': captcha_id,
            'apikey': self.api_key,
            'correct': (lambda c: 1 if c else 2)(correct),
            'json': '1',
        }
        resp = requests.get(self.url, data)
        return resp.json()
class CaptchaError(Exception):
    pass

CaptchaAPI 类的源码位于本书源码文件的 chp7 文件夹中,其名为 captcha_api.py ,这个代码文件会在9kw.eu修改其API时保持更新。这个类使用你的API key以及超时时间进行实例化,其中超时时间默认为120秒。 solve() 方法把验证码图像提交给API,并持续请求,直到验证码图像处理完成或者到达超时时间。

目前,检查API响应中的错误信息时, check() 方法会检查初始字符,确认其是否遵循错误信息前包含4位数字错误码的格式。要想该API在使用时更加健壮,可以对该方法进行扩展,使其包含全部34种错误类型。

下面是使用 CaptchaAPI 类处理验证码图像时的执行过程示例。

>>> API_KEY = ...
>>> captcha = CaptchaAPI(API_KEY)
>>> img = Image.open('captcha.png')
>>> captcha_id, text = captcha.solve(img)
Submitting CAPTCHA
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
Waiting for CAPTCHA ...
CAPTCHA solved!
>>> text
juxhvgy

这是本章前面给出的第一个复杂验证码图像的正确识别结果。如果再次提交相同的验证码图像,则会立即返回缓存结果,并且不会再次消耗积分。

>>> captcha_id, text = captcha.solve(img_data)
Submitting CAPTCHA
>>> text
juxhvgy