数字验证码识别完成自动化登录

一、人工方式处理数字验证码

通过selenium打开浏览器获取验证码,然后进行人工输入,从而实现登录

访问的学习通网页链接:

xxt_link = r'https://passport2.chaoxing.com/'

 使用selenium访问页面,输入用户名和密码:

from selenium import webdriver

driver=webdriver.Firefox()
driver.get(xxt_link)  #请求链接页面
username="test"
password="123456"
driver.find_element_by_xpath('//*[@id="unameId"]').send_keys(username)   #输入用户名
driver.find_element_by_xpath('//*[@id="passwordId"]').send_keys(password) #输入密码

 selenium是可以打开浏览器的,即验证码直接可见,这里直接手动输入验证码:


element=driver.find_element_by_xpath('//*[@id="numcode"]') #获取验证码输入框元素

print("please input the captcha\n")
words=input(">>>")
element.send_keys(words)    #输入验证码

#模拟点击:
driver.find_element_by_xpath('/html/body/div[1]/div[1]/form/table/tbody/tr[7]/td[2]/label/input').click()

二、OCR处理验证码:

ocr(Optical Character Recognition,光学字符识别),一种将图片提供的形状转化为计算机字符的方法,python通过模块pytesseract实现ocr。

pytesseract的安装:

pip install pytesseract --target "xxx\site-packages"

安装Tesseract-ocr:  

Download

直接下载exe格式文件

通过图片链接保存验证码(然,通过链接下载和网页通过的图片不一致):

在selenium打开的登录页面,通过get_attribute()方法获取验证码元素的链接,通过requests模块和文件读写操作保存验证码图片:

import requests

element=driver.find_element_by_xpath('//*[@id="numVerCode"]')   #获取验证码图片链接
si_code_link=element.get_attribute("src")

r=requests.get(si_code_link)   #链接请求
print(r.url)
print(r.stutas_code)

with open("code.jpg","wb") as f:    #图片保存
    f.write(r.content)
    f.close()

 保存的验证码图片code.jpg:

很苟的一点是,再次请求到的验证码图片虽说和页面内的是同一个链接,但是却是不同的图片(......)

通过模拟右键+键盘按键V下载页面验证码(失败拉):

from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys

#模拟页面图片保存:
element==driver.find_element_by_xpath('//*[@id="numVerCode"]')  #定位验证码图片元素
action = ActionChains(driver).move_to_element(element)    #移动到该元素
action.context_click(element)     #右键点击该元素
action.send_keys(Keys.ARROW_DOWN) #点击键盘向下箭头
action.send_keys('v')        #键盘输入V保存图
action.perform()   #执行上述操作

行不通,连下载提示窗口(windows弹窗)都没有弹出,而且弹窗不属于页面内元素,selenium是操作不了的(ε=(´ο`*)))唉......)

利用pyautogui进行页面内验证码图片的保存(有戏):

pyautogui可以通过程序自动控制鼠标和键盘进行操作。

安装pyautogui:

pip install pyautogui

配合selenium进行页面验证码图片的保存:

from selenium.webdriver.common.action_chains import ActionChains
import pyautogui
import time

element==driver.find_element_by_xpath('//*[@id="numVerCode"]')  #定位验证码图片元素

#模拟鼠标移动和右键点击:
action = ActionChains(driver).move_to_element(element)    #移动到该元素
action.context_click(element)     #右键点击该元素
action.perform()   #执行上述操作


#利用pyautogui进行图片保存:
pyautogui.typewrite(['v']) # 敲击V进行保存

# 单击图片另存之后等1s敲回车
time.sleep(3)  
pyautogui.typewrite(['enter'])

最后停留3秒才按回车,保存足够时间等待弹窗出现。 

 现在,保存的图片和当前页面内的验证码是一样的了

对保存图片进行降噪,去除干扰信息(转灰度图,二值化处理):

利用PIL模块将彩色的RGB图像转化为灰度图像,起到降噪作用:

安装PIL模块:

pip install PIL #安装

进行彩色图转灰度图: 

from PIL import Image   #导入模块

im=Image.open("code.jpg")  #打开图片
gray_im=im.convert("L")   #转化为灰度图
gray_im.show()

查看效果:

进行二值化处理:

灰度图只有一个通道,通道可以看做一个0~255的列表,0为黑色,255表示白色,随数字的变大,颜色由浅变深。二值化通过一个自定义的截断数值(灰度界限)将灰度通道变得只有0和1两个数字,即只有黑和白两种颜色。

这个方法对于一些带有干扰项背景的验证码有很好的降噪作用。

#自定义一个二值化通道:
cutoff=200  #设置一个截断距离,值越小,二值化通道里黑色比值越小
table=[]
for i in range(256):
    if i < cutoff:
        table.append(0)
    else:
        table.append(1)
#对灰度图转为二值化灰度图:
out=gray_im.point(table,"1")
out.show()
out.save("product.jpg")

 处理效果:

利用pytesseract进行图片字识别,最后完成登录:

import pytesseract
from PIL import Image
th=Image.open("product.jpg")  #打开二值化灰度图
strings=pytesseract.image_to_string(th).strip()   #进行图片字符识别
print(strings)  

 

 将图片提取的文件填入到验证码框内,模拟点击登录:

#模拟输入验证码
driver.find_element_by_xpath('//*[@id="numcode"]').send_keys(strings)  
#模拟点击登录
driver.find_element_by_xpath('//*[@id="form"]/table/tbody/tr[7]/td[2]/label/input').click()  

 避免重复保存出现覆盖提示的弹窗,在代码的末尾将保存位置的同名文件进行删除:

调用os模块:

import os
try:
    os.remove(r'C:\***\***\Downloads\code.jpg')
except:
    print("pass")

三、小小的调整

ε=(´ο`*)))唉, 这个pytesseract识别度不高啊(......)

将验证码下载、识别出字符串,验证码删除封装为一个函数test_code()

将输入账号、密码和验证码还有点击登录封装为一个函数login()

写个while循环,进行循环登录,直到完成登录为止。登录的标准是匹配到登录的个人主页特有的元素。设置一个变量login_state,初始状态下,login_state=True,当成功登录,匹配到独特的元素后,login_state=False,结束循环。

在while循环里先对验证码进行识别,直到识别出来的是4个数字再进行尝试登录。

对识别的字符进行判断和清洗:

对pytesseract识别的字符进行清洗(去掉英文字符和特殊字符,只保留数字):

update_strings=""    
for i in strings:     #strings是ocr识别的字符串
    i_ = ord(i)       #获得其十进制ascii码
    if 48 <= i_ <= 57 :
        update_strings += i

若是字符串为空或是长度不等于4就换一张识别码重新匹配:

if update_strings == "":
    continue      #识别的字符为空,就跳过本次循环
elif len(update_strings) != 4:
    continue

终于有一次成功识别到4个都是数字的验证码字符串后,进行登录:

login(user,pwd,strings)

try-except结构,尝试识别个人主页特有的元素,没出错就是成功登录,要是出错,重新给我去识别验证码:

若是识别到个人主页的特有元素就结束循环,否则刷新验证码,继续识别和尝试登录

try :
    words=driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[1]/div/div/a').text
    if words=="账号管理"
        login_state=False
        print("成功登陆")
except:
    driver.find_element_by_xpath('/html/body/div[1]/div[1]/form/t \
able/tbody/tr[5]/td[3]/a').click()
    time.sleep(1)
    print("尝试再次登录")

成功的完整代码:

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import pyautogui
import time
from PIL import Image
import pytesseract
import os


def test_code():
      
      #保存验证码:
      element=driver.find_element_by_xpath('//*[@id="numVerCode"]')
      action = ActionChains(driver).move_to_element(element)#移动到该元素
      action.context_click(element)#右键点击该元素
      action.perform()#执行

      #利用pyautogui进行图片保存:
      pyautogui.typewrite(['v']) # 敲击V进行保存

      # 单击图片另存之后等2s敲回车
      time.sleep(3)  
      pyautogui.typewrite(['enter'])
      time.sleep(3)
      #图片转灰度图:
      im=Image.open(r"C:\Users\TSPC\Downloads\code.jpg")
      gray_im=im.convert("L")
      gray_im.save("product.jpg")

      th=Image.open("product.jpg")
      strings=pytesseract.image_to_string(th)
      strings=strings.strip()
      print("识别的字符为>>>",strings)
      #识别出字符后删掉图片:
      try:
            os.remove(r'C:\Users\TSPC\Downloads\code.jpg')
      except:
            print("pass")
      try:
            os.remove(r"C:\Users\TSPC\Desktop\product.jpg")
      except:
            print("pass")
      #老是匹配到非数字,这里保证只有数字:
      updates_strings=""
      for i in strings:
            i_=ord(i)
            if 48<=i_<=57:
               updates_strings+=str(i)
      print("清洗后的字符>>>",updates_strings)
      return updates_strings

def login(username,passwords,strings):

      #模拟用户密码输入:
      user_input=driver.find_element_by_xpath('//*[@id="unameId"]')
      pwd_input=driver.find_element_by_xpath('//*[@id="passwordId"]')
      user_input.clear()
      user_input.send_keys(username)
      pwd_input.clear()
      pwd_input.send_keys(passwords)
      #模拟输入验证码:
      driver.find_element_by_xpath('//*[@id="numcode"]').clear()
      driver.find_element_by_xpath('//*[@id="numcode"]').send_keys(strings)  
      #模拟点击登录
      driver.find_element_by_xpath('//*[@id="form"]/table/tbody/tr[7]/td[2]/label/input').click()
      time.sleep(3)

if __name__ == "__main__":
      xxt_link = r'https://passport2.chaoxing.com/'
      driver=webdriver.Firefox()
      driver.get(xxt_link)
      driver.set_window_size(500,650)
      
      username="test"
      passwords="123456"
      
      login_state=True
      while login_state:

            strings=test_code()  #获取验证码数字
            if strings == "":
                  driver.find_element_by_xpath('/html/body/div[1]/div[1]/form/table/tbody/tr[5]/td[3]/a').click()
                  time.sleep(1)
                  print("识别错误,尝试再次识别")
                  continue
            elif len(strings) != 4:
                  driver.find_element_by_xpath('/html/body/div[1]/div[1]/form/table/tbody/tr[5]/td[3]/a').click()
                  time.sleep(1)
                  print("识别错误,尝试再次识别")
                  continue
            login(username,passwords,strings)  #进行登录
            try :
                  words=driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[1]/div/div/a').text
                  if words=="账号管理":
                        login_state=False
                        print("成功登陆")
            except:
                  driver.find_element_by_xpath('/html/body/div[1]/div[1]/form/table/tbody/tr[5]/td[3]/a').click()
                  time.sleep(1)
                  print("尝试再次登录")

循环几次后登录进学习通: 

 

参考文献:

Python网络爬虫从入门到实践    编者:唐松 

selenium模拟鼠标右键保存图片 - momo_mami - 博客园

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄思博呀

真的有人打赏啊,超级感谢!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值