识别方法参考:https://blog.csdn.net/zhangzeyuaaa/article/details/119508407

问题

当失败次数过多时, 再尝试登录时, 会出现验证信息:滑动图片补全缺口;

脚本内容

# coding=utf-8
# @Time : 2023/2/2 22:59 
# @Author : yu dian
# @BlogUrl: http://119.23.247.188/
# @email: hhuyudian@163.com/dian.yu@casstime.com
# @File : captcha_solver.py 
# @Software: PyCharm
import cv2
import requests
from urllib.parse import urljoin
import time
import base64

# fiddler_proxies = {'http': 'http://127.0.0.1:8888', 'https': 'http://127.0.0.1:8888'}
class ECCaptchaSolver:
    env = {
        'hwbeta': r'https://ec-hwbeta.casstime.com/'
    }

    def __init__(self, host, username, env=None):
        if env is None:
            self.host = host
        else:
            self.host = self.env[env]
        self.username = username
        self.sliderFile = 'slider.png'
        self.backgroundFile = "background.png"

    def _url(self, addr):
        return urljoin(self.host, addr)

    def isCaptchaNeed(self):
        """
        抓包判断是否会出现验证码
        :return:
        """
        # preurl = r'https://ec-hwbeta.casstime.com/passport/captcha/need'
        url = self._url(r'/passport/captcha/need')
        timestamp = int(time.time())
        datas = {
            'userName': self.username,
            'data': timestamp
        }
        res = requests.get(url, params=datas)
        return res.json()['data']

    def get_captcha_info(self):
        """
        获取验证码信息:背景图片, 碎片图片, y轴坐标
        :return:token, y轴坐标
        """
        url = self._url('/passport/captcha')
        timestamp = int(time.time())
        datas = {
            'userName': self.username,
            'data': timestamp
        }
        res = requests.get(url, params=datas).json()['data']
        # print(res)
        captchaToken = res['captchaToken']
        sliderImage = base64.b64decode(res['cutoutImage'])
        backgroundImage = base64.b64decode(res['shadeImage'])
        with open('slider.png', 'wb') as f:
            f.write(sliderImage)
        with open('background.png', 'wb') as f:
            f.write(backgroundImage)
        y = res['y']
        # print(f'y:{y}')
        return captchaToken, y

    def get_slide_distance(self):
        """
        通过cv2库获取要滑动的距离.
        :return: x
        """
        slider = self.sliderFile
        background = self.backgroundFile
        bg_img = cv2.imread(background)  # 背景图片
        tp_img = cv2.imread(slider)  # 缺口图片
        bg_edge = cv2.Canny(bg_img, 100, 200)
        tp_edge = cv2.Canny(tp_img, 100, 200)
        # 转换图片格式
        bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
        tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
        # 缺口匹配
        res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)  # 寻找最优匹配
        x = max_loc[0]  # 滑块在验证图片的x坐标(左边)
        # 绘制方框
        th, tw = tp_pic.shape[:2]
        tl = max_loc  # 左上角点的坐标
        br = (tl[0] + tw, tl[1] + th)  # 右下角点的坐标
        cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形
        cv2.imwrite('out.jpg', bg_img)  # 保存在本地
        return x

    def move(self, token, x, y):
        """
        调接口来实现滑动动作.
        :param token:
        :param x:
        :param y:
        :return:是否成功. True/False
        """
        url = self._url(r'/passport/captcha/verification')
        datas = {
            "y": y,
            "x": x,
            "captchaToken": token,
            "userName": "angus001"
        }
        res = requests.post(url, json=datas).json()
        return res['data']

    def exec(self, max_times=10):
        """
        将上面的方法串起来执行.
        :param max_times:
        :return:
        """
        if self.isCaptchaNeed():
            for i in range(max_times):
                token, y = self.get_captcha_info()
                x = self.get_slide_distance()
                if self.move(token, x, y) is True:
                    print('滑动拼图验证码解决成功.')
                    break

def cass_login(url, username, password):
    captchaSolver = ECCaptchaSolver(url, username)  # 环境要修改为制动获取
    captchaSolver.exec()
    session = requests.session()
    session.request(
        method="post", url=url + '/passport/login',
        data={'username': username, 'password': password, 'logintype': 'PASSWORD'}
    )
    res = session.request(method='get', url=url)
    session.headers.update({"Cookie": res.request.headers.get('cookie', '')})
    return session

if __name__ == '__main__':
    cass_login(r'https://ec-hwbeta.casstime.com', 'name', 'password')
最后修改日期: 2024年11月3日

作者

留言

撰写回覆或留言