简单验证码识别

复制 | import tesserocr |
| from PIL import Image |
| |
| image = Image.open('PFET.jpg') |
| |
| |
| image = image.convert('L') |
| |
| |
| threshold = 127 |
| |
| table = [] |
| for i in range(256): |
| if i < threshold: |
| table.append(0) |
| else: |
| table.append(1) |
| |
| image = image.point(table, '1') |
| |
| image = image.convert('1') |
| image.show() |
| |
| result = tesserocr.image_to_text(image) |
| print(result) |
复制
极验滑动验证码的识别
极客验证官网
数据初始化
复制 | EMAIL = 'zcs@163.com' |
| PASSWORD = '123' |
| BORDER = 6 |
| |
| class CrackGeetest(): |
| def __init__(self): |
| self.url = 'https://account.geetest.com/login' |
| self.browser = webdriver.Chrome() |
| self.wait = WebDriverWait(self.browser, 10) |
| self.email = EMAIL |
| self.password = PASSWORD |
获取验证按钮
复制 | def get_geetest_button(self): |
| """ |
| 获取初始验证按钮 |
| :return: |
| """ |
| button = self.wait.until( |
| EC.element_to_be_clickable( |
| (By.CLASS_NAME, 'geetest_radar_tip') |
| ) |
| ) |
| return button |
获取验证码图片所在位置
复制 | def get_position(self): |
| """ |
| 获取验证码位置 |
| :return: 验证码位置元组(上, 下, 左, 右) |
| """ |
| img = self.wait.until( |
| EC.presence_of_element_located( |
| (By.CLASS_NAME, 'geetest_canvas_img') |
| ) |
| ) |
| time.sleep(2) |
| location = img.location |
| size = img.size |
| top, bottom, left, right = \ |
| location['y'], location['y'] + size['height'], location['x'], location['x'] + size['width'] |
| return (top, bottom, left, right) |
获取网页截图
复制 | def get_screenshot(self): |
| """ |
| 获取网页截图 |
| :return: 截图对象 |
| """ |
| screenshot = self.browser.get_screenshot_as_png() |
| |
| |
| screenshot = Image.open(BytesIO(screenshot)) |
| |
| |
| |
| return screenshot |
获取滑块
复制 | def get_slider(self): |
| """ |
| 获取滑块 |
| :return: 滑块对象 |
| """ |
| slider = self.wait.until( |
| EC.element_to_be_clickable( |
| (By.CLASS_NAME, 'geetest_slider_button') |
| ) |
| ) |
| return slider |
获取验证码图片截图
复制 | def get_geetest_image(self, name='captcha.png'): |
| """ |
| 获取验证码图片 |
| :return: 图片对象 |
| """ |
| top, bottom, left, right = self.get_position() |
| print('验证码位置', top, bottom, left, right) |
| screenshot = self.get_screenshot() |
| |
| captcha = screenshot.crop((left, top, right, bottom)) |
| |
| captcha.save(name) |
| return captcha |
打开网页输入用户名密码
复制 | def open_url(self): |
| """ |
| 打开网页输入用户名密码 |
| :return: None |
| """ |
| self.browser.get(self.url) |
| email = self.wait.until( |
| EC.presence_of_element_located( |
| (By.ID, 'email') |
| ) |
| ) |
| password = self.wait.until( |
| EC.presence_of_element_located( |
| (By.ID, 'password') |
| ) |
| ) |
| email.send_keys(self.email) |
| password.send_keys(self.password) |
代码汇总
复制 | import time |
| from io import BytesIO |
| from PIL import Image |
| from selenium import webdriver |
| from selenium.webdriver import ActionChains |
| from selenium.webdriver.common.by import By |
| from selenium.webdriver.support.ui import WebDriverWait |
| from selenium.webdriver.support import expected_conditions as EC |
| |
| |
| EMAIL = 'zcs@163.com' |
| PASSWORD = '123' |
| BORDER = 6 |
| |
| class CrackGeetest(): |
| def __init__(self): |
| self.url = 'https://account.geetest.com/login' |
| self.browser = webdriver.Chrome() |
| self.wait = WebDriverWait(self.browser, 10) |
| self.email = EMAIL |
| self.password = PASSWORD |
| |
| |
| def __del__(self): |
| self.browser.close() |
| |
| def open_url(self): |
| """ |
| 打开网页输入用户名密码 |
| :return: None |
| """ |
| self.browser.get(self.url) |
| email = self.wait.until( |
| EC.presence_of_element_located( |
| (By.ID, 'ivu-form-item.ivu-form-item-required.ivu-form-item-error .ivu-input') |
| ) |
| ) |
| password = self.wait.until( |
| EC.presence_of_element_located( |
| (By.ID, '.ivu-input.ivu-input-has-value') |
| ) |
| ) |
| email.send_keys(self.email) |
| password.send_keys(self.password) |
| |
| def get_button(self): |
| """ |
| 获取验证按钮 |
| :return: |
| """ |
| button = self.wait.until( |
| EC.element_to_be_clickable( |
| (By.CLASS_NAME, 'geetest_radar_tip') |
| ) |
| ) |
| return button |
| |
| def get_slider(self): |
| """ |
| 获取滑块 |
| :return: 滑块对象 |
| """ |
| slider = self.wait.until( |
| EC.element_to_be_clickable( |
| (By.CLASS_NAME, 'geetest_slider_button') |
| ) |
| ) |
| return slider |
| |
| def get_image(self): |
| """ |
| 获取验证码图片 |
| :return: 图片对象(无缺口图像和有缺口图像) |
| """ |
| return 1, 2 |
| |
| def get_distance(self, image1, image2): |
| """ |
| 获取缺口距离 |
| :param image1: 无缺口的滑动验证码图片 |
| :param image2: 有缺口的滑动验证码图片 |
| :return: |
| """ |
| left = 60 |
| |
| threhold = 70 |
| |
| |
| for i in range(left, image1.size[0]): |
| |
| for j in range(image1.size[1]): |
| |
| |
| rgb1 = image1.load()[i, j] |
| rgb2 = image2.load()[i, j] |
| res1 = abs(rgb1[0] - rgb2[0]) |
| res2 = abs(rgb1[1] - rgb2[1]) |
| res3 = abs(rgb1[2] - rgb2[2]) |
| |
| if not (res1 < threhold and res2 < threhold and res3 < threhold): |
| return i |
| |
| return left |
| |
| def get_track(self, distance): |
| """ |
| 根据偏移量获取移动轨迹 |
| :param distance: 偏移量 |
| :return: 移动轨迹 |
| """ |
| |
| track = [] |
| |
| current = 0 |
| |
| mid = distance * 4 / 5 |
| |
| t = 0.2 |
| |
| v = 0 |
| |
| |
| while current < distance: |
| |
| if current < mid: |
| |
| a = 2 |
| else: |
| |
| a = -3 |
| |
| v0 = v |
| |
| v = v0 + a * t |
| |
| move = v0 * t + 1 / 2 * a * t * t |
| |
| current += move |
| |
| track.append(round(move)) |
| return track |
| |
| def move_to_gap(self, slider, track): |
| """ |
| 拖动滑块到缺口处 |
| :param slider: 滑块 |
| :param track: 轨迹 |
| :return: |
| """ |
| |
| action_chains1 = ActionChains(self.browser) |
| |
| down_left_mouse = action_chains1.click_and_hold(slider) |
| |
| down_left_mouse.perform() |
| |
| |
| for x in track: |
| |
| action_chains2 = ActionChains(self.browser) |
| |
| move_mouse = action_chains2.move_by_offset(xoffset=x, yoffset=0) |
| |
| move_mouse.perform() |
| time.sleep(0.5) |
| |
| ActionChains(self.browser).release().perform() |
| |
| def login(self): |
| """ |
| 登录 |
| :return: None |
| """ |
| submit = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest-btn'))) |
| submit.click() |
| time.sleep(10) |
| print('登录成功') |
| |
| def crack(self): |
| |
| self.open_url() |
| |
| button = self.get_button() |
| button.click() |
| |
| image1, image2 = self.get_image() |
| |
| gap = self.get_distance(image1, image2) |
| print('缺口位置', gap) |
| |
| gap = gap - BORDER |
| |
| track = self.get_track(gap) |
| print('滑动轨迹', track) |
| |
| slider = self.get_slider() |
| self.move_to_gap(slider, track) |
| |
| success = self.wait.until( |
| EC.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_success_radar_tip_content'), '验证成功')) |
| print(success) |
| |
| |
| if not success: |
| self.crack() |
| else: |
| self.login() |
| |
| |
| def main(): |
| |
| crack_geetest = CrackGeetest() |
| |
| crack_geetest.open_url() |
| |
| button = crack_geetest.get_button() |
| button.click() |
| |
| image1, image2 = crack_geetest.get_image() |
| |
| gap = crack_geetest.get_distance(image1, image2) |
| print('缺口位置', gap) |
| |
| gap = gap - BORDER |
| |
| track = crack_geetest.get_track(gap) |
| print('滑动轨迹', track) |
| |
| slider = crack_geetest.get_slider() |
| crack_geetest.move_to_gap(slider, track) |
| |
| success = crack_geetest.wait.until( |
| EC.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_success_radar_tip_content'), '验证成功')) |
| print(success) |
| |
| |
| if not success: |
| main() |
| else: |
| crack_geetest.login() |
| |
| |
| if __name__ == '__main__': |
| main() |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)