selenium 解析验证码(普通的字符数字的验证码),解决方式:先将验证码保存为图片,然后使用ddddocr解析图片为验证码的字符串

发布时间 2023-09-08 14:42:18作者: 勋勋的大宝贝

 

from selenium import webdriver
from selenium.webdriver.common.by import By
from PIL import Image
from io import BytesIO
import pytesseract
import time
import ddddocr
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import TimeoutException, NoSuchElementException


# 截取验证码,保存
def img_save(img, driver):
    x, y = img.location.values()  # 元素 坐标数据
    h, w = img.size.values()  # 元素高宽
    # 将截图以二进制的形式返回
    img_data = driver.get_screenshot_as_png()
    # 以新图片的形式打开返回的数据
    sreenshots = Image.open(BytesIO(img_data))
    # 对截图进行剪切
    result = sreenshots.crop((x, y, x + w, y + h))  # 元素大小放缩
    # 存储
    imgpath = "code.png"
    result.save(imgpath)
    return imgpath

# 将图片转换为验证码
def img_to_code(imgpath):
    # 创建对象
    ocr = ddddocr.DdddOcr()
    res = ""
    # 使用二进制的方式读取图片
    with open(imgpath, 'rb') as f:
        img_tytes = f.read()
        # 调用识别方法
        res = ocr.classification(img_tytes)
        # print(f'验证码为:{res}')
        return res



if __name__ == '__main__':
    # 访问界面
    url = "https://XXXX/index.php"
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get(url)
    
    
    wait = WebDriverWait(driver, timeout=10, poll_frequency=0.5)
    wait.until(expected_conditions.presence_of_element_located(("id", 'codeimage'))) # 验证码的标签
    
    driver.find_element(By.ID, 'user_name').send_keys("lfj")   # 输入【用户名】
    driver.find_element(By.ID, 'password').send_keys("123")    # 输入【密码】

    # 循环获取验证码,知道输入的验证码正确
    while True:
        # 验证码截取、保存
        img = driver.find_element(By.ID, 'codeimage')  # 要截图的元素
        imgpath = img_save(img, driver) # 将验证码的部分使用图片保存
        res = img_to_code(imgpath) # 将图片解析为验证码,每次验证码不一定正确,所以代码逻辑使用循环处理,直到拿到正确的验证码

        driver.find_element(By.ID, 'captcha').send_keys(res) # 输入【验证码】
        driver.find_element(By.XPATH, '//*[@id="pwd_login_form"]/div[5]/input[1]').click() # 点击【登录】
        time.sleep(2)

        # 验证码获取失败,再重新获取
        # 我的网页的情况是当在登录页面时,url里带有login,如果登录成功,则没有login字符串,所以这里采用这样条件来判断是否登录成功
        if "https://XXXX/index.php?app=login" in driver.current_url: # 根据自己的实际网页情况,编写不同的判断条件
            wait = WebDriverWait(driver, timeout=10, poll_frequency=0.5)
            wait.until(expected_conditions.presence_of_element_located(("id", 'codeimage')))
            continue # 如果验证码校验失败,则重新获取验证码
        else:
            break   # 登录成功,则跳出循环,不再获取验证码


    # 后边继续其他的业务逻辑即可。。。。。。。。。。。。。。。
    
    # 下面是我自己的业务逻辑部分,各位根据自己的需求进行编写
    # 进入商户后台
    enter_back = '//ul[@class="home_layout_bar-nav"]/li/a' #进入商户后台的按钮
    wait = WebDriverWait(driver, timeout=10, poll_frequency=0.5)
    wait.until(expected_conditions.presence_of_element_located(("xpath", enter_back)))
    driver.find_element(By.XPATH, enter_back).click()

    driver.quit()