1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import time
import ddddocr
import random
from DrissionPage import ChromiumPage
import os
import shutil
 
 
class SlideCaptchaSolver:
    def __init__(self):
        self.page = ChromiumPage()
 
    @staticmethod
    def delete_img_folder():
        """删除img文件夹"""
        folder_name = 'img'
        # 获取当前工作目录
        current_directory = os.getcwd()
        # 构造要删除的文件夹的完整路径
        folder_path = os.path.join(current_directory, folder_name)
        try:
            # 删除文件夹及其内容
            shutil.rmtree(folder_path)
            # print(f"成功删除文件夹: {folder_path}")
        except FileNotFoundError:
            # print(f"文件夹 '{folder_path}' 不存在")
            pass
        except Exception as e:
            print(f"发生错误: {e}")
 
    @staticmethod
    def get_distance_by_ddddocr():
        """使用ddddocr计算缺口距离"""
        det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
        with open('./img/target.png', 'rb') as f:
            target_bytes = f.read()
        with open('./img/background.png', 'rb') as f:
            background_bytes = f.read()
        res = det.slide_match(target_bytes, background_bytes)
        x_distance = res["target"][0]
        return x_distance
 
    @staticmethod
    def get_tracks(distance):
        """滑块的运动轨迹"""
        value = round(random.uniform(0.55, 0.75), 2)
        v, t, sum = 0, 0.3, 0
        plus = []
        mid = distance * value
        while sum < distance:
            if sum < mid:
                a = round(random.uniform(2.5, 3.5), 1)
            else:
                a = -round(random.uniform(2.0, 3.0), 1)
            s = v * t + 0.5 * a * (t ** 2)
            v = v + a * t
            sum += s
            plus.append(round(s))
 
        reduce = [-6, -4, -6, -4]
        return {'plus': plus, 'reduce': reduce}
 
    def move_to_gap(self, slide_ele, tracks):
        """模拟滑块滑动 https://g1879.gitee.io/drissionpagedocs/ChromiumPage/actions/#-%E4%BD%BF%E7%94%A8%E5%86%85%E7%BD%AEactions%E5%B1%9E%E6%80%A7"""
        self.page.actions.hold(f"{slide_ele}"# 此方法用于按住鼠标左键不放,按住前可先移动到元素上
        # 使鼠标相对当前位置移动若干距离
        for track in tracks['plus']:
            self.page.actions.move(
                offset_x=track,
                offset_y=round(random.uniform(1.0, 3.0), 0),
                duration=.1
            )
        time.sleep(0.5)
        self.page.actions.release(f"{slide_ele}"# 此方法用于释放鼠标左键,释放前可先移动到元素上。
 
    def solve_captcha1(self):
        """嵌入式滑块"""
        self.delete_img_folder()
        self.page.get("https://castatic.fengkongcloud.cn/pr/v1.0.4/demo.html")
        self.page.ele("@text()=嵌入式(embed)").click()
        self.page.ele('@name=account').input("test")
        self.page.ele('@name=password').input("test")
        # 下载滑块和背景图,target.png 指的是滑块的图片。background.png指的是带有缺口的背景图
        self.page.ele('.shumei_captcha_loaded_img_fg').save(path="./img/", name='target.png')
        self.page.ele('.shumei_captcha_loaded_img_bg').save(path="./img/", name='background.png')
        x_distance = self.get_distance_by_ddddocr()
        # 该网址缺口的计算得除2,因为下载的图片为600 × 300 px ,而在网页上的图片大小为300 × 150 px
        x_distance = x_distance / 2
        # 计算出的轨迹
        trajectory = self.get_tracks(x_distance)
        # 进行移动
        self.move_to_gap(slide_ele=".shumei_captcha_slide_btn_icon sm-iconfont", tracks=trajectory)
        time.sleep(0.2)
        # 对验证码页面进行截图。
        captcha1 = self.page.ele('#shumei_form_captcha_wrapper')
        if captcha1:
            captcha1.get_screenshot(path="./img/captcha1.png")
 
    def solve_captcha2(self):
        """浮动式(float)"""
        self.delete_img_folder()
        self.page.get("https://castatic.fengkongcloud.cn/pr/v1.0.4/demo.html")
        self.page.ele("@text()=浮动式(float)").click()
        time.sleep(1)
        # 必须先输入密码再输入账号,要不然不会弹窗
        self.page.ele('@name=password').input("test")
        self.page.ele('@name=account').input("test")
        # 下载滑块和背景图,target.png 指的是滑块的图片。background.png指的是带有缺口的背景图
        self.page.ele('.shumei_captcha_loaded_img_fg').save(path="./img/", name='target.png')
        self.page.ele('.shumei_captcha_loaded_img_bg').save(path="./img/", name='background.png')
        x_distance = self.get_distance_by_ddddocr()
        # 该网址缺口的计算得除2,因为下载的图片为600 × 300 px ,而在网页上的图片大小为300 × 150 px
        x_distance = x_distance / 2
        # 计算出的轨迹
        trajectory = self.get_tracks(x_distance)
        # 进行移动
        self.move_to_gap(slide_ele=".shumei_captcha_slide_btn_icon sm-iconfont", tracks=trajectory)
        time.sleep(0.2)
        # 对验证码页面进行截图。
        captcha2 = self.page.ele('#shumei_form_captcha_wrapper')
        if captcha2:
            captcha2.get_screenshot(path="./img/captcha2.png")
 
    def solve_captcha3(self):
        """弹出式(popup)"""
        self.delete_img_folder()
        self.page.get("https://castatic.fengkongcloud.cn/pr/v1.0.4/demo.html")
        self.page.ele("@text()=弹出式(popup)").click()
        self.page.ele('@name=account').input("test")
        self.page.ele('@name=password').input("test")
        # 点击登录,弹出验证码
        time.sleep(1)
        self.page.ele('.shumei_login_btn').click()
        # 下载滑块和背景图,target.png 指的是滑块的图片。background.png指的是带有缺口的背景图
        self.page.ele('.shumei_captcha_loaded_img_fg').save(path="./img/", name='target.png')
        self.page.ele('.shumei_captcha_loaded_img_bg').save(path="./img/", name='background.png')
        x_distance = self.get_distance_by_ddddocr()
        # 该网址缺口的计算得除2,因为下载的图片为600 × 300 px ,而在网页上的图片大小为300 × 150 px
        x_distance = x_distance / 2
        # 计算出的轨迹
        trajectory = self.get_tracks(x_distance)
        # 进行移动
        self.move_to_gap(slide_ele=".shumei_captcha_slide_btn_icon sm-iconfont", tracks=trajectory)
        time.sleep(0.2)
        # 对验证码页面进行截图。
        captcha3 = self.page.ele('#shumei_form_captcha_wrapper')
        if captcha3:
            captcha3.get_screenshot(path="./img/captcha3.png")
 
    def solve_captcha4(self):
        """无图直接滑动"""
        self.delete_img_folder()
        self.page.get("https://castatic.fengkongcloud.cn/pr/v1.0.4/demo.html")
        self.page.ele("@text()=无图直接滑动").click()
        self.page.ele('@name=account').input("test")
        self.page.ele('@name=password').input("test")
        # 点击登录,弹出验证码
        self.page.ele('.shumei_login_btn').click()
        x_distance = (300 - 40)
        # 计算出的轨迹
        trajectory = self.get_tracks(x_distance)
        # 进行移动
        self.move_to_gap(slide_ele=".shumei_captcha_slide_btn_icon sm-iconfont", tracks=trajectory)
        time.sleep(0.2)
        # 对验证码页面进行截图。
        captcha4 = self.page.ele('#shumei_form_captcha_wrapper', timeout=0.5)
        if captcha4:
            captcha4.get_screenshot(path="./img/captcha4.png")
 
    def solve_captcha5(self):
        """使用bytes传参,不下载验证码图片"""
        self.delete_img_folder()
        self.page.get("https://castatic.fengkongcloud.cn/pr/v1.0.4/demo.html")
        self.page.ele("@text()=嵌入式(embed)").click()
        self.page.ele('@name=account').input("test")
        self.page.ele('@name=password').input("test")
        # 点击登录,弹出验证码
        self.page.ele('.shumei_login_btn').click()
        # 直接获取到验证码滑块和背景图的bytes
        target_bytes = self.page.ele('.shumei_captcha_loaded_img_fg').src()
        background_bytes = self.page.ele('.shumei_captcha_loaded_img_bg').src()
 
        det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
        res = det.slide_match(target_bytes, background_bytes)
 
        x_distance = res["target"][0] / 2
        trajectory = self.get_tracks(x_distance)
        self.move_to_gap(slide_ele=".shumei_captcha_slide_btn_icon sm-iconfont", tracks=trajectory)
        time.sleep(0.2)
        captcha5 = self.page.ele('#shumei_form_captcha_wrapper')
        if captcha5:
            captcha5.get_screenshot(path="./img/captcha5.png")
 
 
captcha_solver = SlideCaptchaSolver()
captcha_solver.solve_captcha1()
# captcha_solver.solve_captcha2()
# captcha_solver.solve_captcha3()
# captcha_solver.solve_captcha4()
# captcha_solver.solve_captcha5()