哈喽O(∩_∩)O
:.,,.-:*``*:-.,,.-:*``*: ╭╧╮ ╭╧╮ ╭╧╮ ╭╧╮ ║周║║末║║快║║乐║ └﹏┘└﹏┘└﹏┘└﹏┘ * * * * * * * * * * * * *
╒╧╕ ╒╧╕ ╒╧╕ ╒╧╕ ╒╧╕
|財||招||吉||大||閣|
|源||財||祥||吉||家|
|廣||進||如||大||平|
|進||寶||意||利||安|
╘═╛ ╘═╛ ╘═╛ ╘═╛ ╘═╛
今天,我研究了一下Python爬虫的功能——验证码识别
比如某网站有这样一张人机验证的图片
我要用程序识别出验证码是什么,并输入验证码,打开网站,爬取内容。
ddddocr
ddddocr是一款开源库,专门用来识别验证码,方便快捷
安装
终端运行:pip install ddddocr
使用
ddddocr接收这几个参数
参数名默认值说明use_gpuFalseBool 是否使用gpu进行推理,如果该值为False则device_id不生效device_id0
int cuda设备号,目前仅支持单张显卡
classification
参数名默认值说明img0bytes 图片的bytes格式
试一下
在编译器中输入如下代码:
import ddddocr
ocr=ddddocr.DdddOcr(old=True)
with open("1.jpg", 'rb') as f:
image = f.read()
print(ocr.classification(image))
1.jpg是这样的
输出结果:
可以看到,成功识别出了 z4ta
但是,这个广告看着就很难受,有没有什么方法能去掉呢?
首先,我们来判断一下验证码和前面的广告是库作者拼接在一个字符串里,
还是是两个分别的字符串,分别输出
我们输出这个字符串的第0项看看
import ddddocr
ocr=ddddocr.DdddOcr(old=True)
with open("1.jpg", 'rb') as f:
image = f.read()
print(ocr.classification(image)[0])
输出:z
这就证明这是两个字符串,不影响正常使用
去除广告
我们按住 Ctrl,把光标移到“import ddddocr” 的ddddocr上,发现ddddocr变蓝了
然后我们单击ddddocr,出来这个界面
这就是ddddocr的代码
我们找到这里
把这几行代码注释掉,改成 pass
再运行刚才的文件,发现输出变成了只有 z4ta
标记验证码
效果图:
可以看到,程序把 Z 、4、T、A 都用红圈圈了出来
程序(请安装opencv)
import ddddocr
import cv2
det = ddddocr.DdddOcr(det=True)
with open("1.jpg", 'rb') as f:
image = f.read()
poses = det.detection(image)
print(poses)
im = cv2.imread("1.jpg")
for box in poses:
x1, y1, x2, y2 = box
im = cv2.rectangle(im, (x1, y1), (x2, y2), color=(0, 0, 255), thickness=2)
cv2.imwrite("result.jpg", im)
注意,1.jpg是我们要识别的验证码的图片
源码阅读
import warnings
warnings.filterwarnings('ignore')
import io
import os
import onnxruntime
from PIL import Image
import numpy as np
这里使用onnxruntime模型,使用filterwarnings过滤了可能出现的警告。PIL用于读入图片和缩放,使用numpy转化为矩阵。
class DdddOcr(object):
def __init__(self, use_gpu: bool = False, device_id: int = 0):
self.__graph_path = os.path.join(os.path.dirname(__file__), 'common.onnx')
if use_gpu:
self.__providers = [
('CUDAExecutionProvider', {
'device_id': device_id,
'arena_extend_strategy': 'kNextPowerOfTwo',
'cuda_mem_limit': 2 * 1024 * 1024 * 1024,
'cudnn_conv_algo_search': 'EXHAUSTIVE',
'do_copy_in_default_stream': True,
}),
]
else:
self.__providers = [
'CPUExecutionProvider',
]
self.__ort_session = onnxruntime.InferenceSession(self.__graph_path, providers=self.__providers)
self.__charset = ["", "掀", ...] # 省略亿点点代码
此处定义了Ddddocr类,
名字意义
self.__graph_path
模型位置
self.__providers
模型参数
self.__ort_session
模型session
self.__charset
字符集
... # 上面的代码
def classification(self, img: bytes):
image = Image.open(io.BytesIO(img)) # 使用BytesIO+pillow读入图片
image = image.resize((int(image.size[0] * (64 / image.size[1])), 64), Image.ANTIALIAS).convert('L') # 缩放为验证码大小,转为二值图
image = np.array(image).astype(np.float32) # 转为float32的矩阵
image = np.expand_dims(image, axis=0) / 255.
image = (image - 0.5) / 0.5
ort_inputs = {'input1': np.array([image])} # 设置模型输入
ort_outs = self.__ort_session.run(None, ort_inputs) # 获取结果
result = []
last_item = 0
for item in ort_outs[0][0]: # 遍历模型,获取结果
if item == last_item:
continue
else:
last_item = item
if item != 0:
result.append(self.__charset[item])
return ''.join(result) # 返回result
生成验证码
如果你觉得用别人的验证码不过瘾的话,可以自己做验证码
代码比较简单
from PIL import Image,ImageDraw,ImageFont
import random
def getRandomColor():
r = random.randint(0, 255)
g = random.randint(0, 255)
b = random.randint(0, 255)
return (r,g,b)
def getRandomStr():
num_random = str(random.randint(1,9))
random_upper_alpha = chr(random.randint(65,90))
random_char = random.choice([num_random,random_upper_alpha])
return random_char
image = Image.new('RGB',(120,40),(255,255,255))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype(r'K:\msyh.ttc',size=24)
for i in range(4):
draw.text((10+i*30,10),getRandomStr(),getRandomColor(),font=font)
width = 120
height = 40
for i in range(5):
x1 = random.randint(0,width)
x2 = random.randint(0,width)
y1 = random.randint(0,height)
y2 = random.randint(0,height)
draw.line((x1,x2,y1,y2),fill=getRandomColor())
for i in range(20):
draw.point([random.randint(0,width),random.randint(0,height)],fill=getRandomColor())
x = random.randint(0,width)
y = random.randint(0,height)
draw.arc((x,y,x+5,y+5),0,90,fill=getRandomColor())
image.save('1.jpg')
模拟登录网站
我们可以自己做一个简单的页面(Html)
再自己破解。
import unittest
from PIL import Image
from selenium import webdriver
from time import sleep
import ddddocr
class WeChat(unittest.TestCase):
# def __init__(self):
def setUp(self) -> None:
self.driver = webdriver.Chrome()
# 自己的网站
self.driver.get('website.html')
# 全屏打开
self.driver.maximize_window()
self.driver.implicitly_wait(10)
self.ocr = ddddocr.DdddOcr()
def test_login_success(self):
# 打开自己的网站会有安全认证
self.driver.find_element('id', 'details-button').click()
self.driver.find_element('id', 'proceed-link').click()
self.driver.find_element('xpath', '//*[@id="layui-layer1"]/div[3]/a').click()
sleep(1)
self.driver.find_element('id', 'account').send_keys('BluetoothHaAdmin')
self.driver.find_element('id', 'password').send_keys('000000')
# 先获取屏幕截图,在找元素,定位大小,通过定位出来的地方截图后使用识别验证码模块,将其
# 以二进制的方式识别后,输出后填写到填写验证码的位置
self.driver.save_screenshot('Login_page.png')
yzm_btn = self.driver.find_element('id', 'id_img')
# 获取图片元素的位置
loc = yzm_btn.location
# 获取图片的宽高
size = yzm_btn.size
# 获取验证码上下左右的位置
left = loc['x']
top = loc['y']
right = (loc['x'] + size['width'])
bottom = (loc['y'] + size['height'])
val = (left, top, right, bottom)
# 打开网页截图
login_pic = Image.open('Login_page.png')
# print(val)
# 通过上下左右的值,去截取验证码
yzm_pic = login_pic.crop(val)
yzm_pic.save('yzm.png')
with open('yzm.png', 'rb') as f:
img_bytes = f.read()
# print (img_bytes)
res = self.ocr.classification(img_bytes)
print("验证码:", res, type(res))
self.driver.find_element('id', 'id_webVerificationCode').send_keys(res)
sleep(1)
self.driver.find_element('id', 'id_loginButton').click()
sleep(12)
self.driver.quit()
if __name__ == '__main__':
ocr = ddddocr.DdddOcr()
wechat = WeChat()
# 点击安全提醒
sleep(12)
#退出
wechat.driver.quit()
最后
今天写了一篇长文,大家看了我的文章可能有一些收获
三连必回,其他不多说了了,拜拜!
版权归原作者 YR_T 所有, 如有侵权,请联系我们删除。