关于多种验证码的应对方式
爬虫程序会遇到各色各样的验证码,整理一下解决方法。
1.使用均值哈希算法进行图像识别
原理是根据像素平均值对比,来得到一串01010001这样的字符串,通过比较相同位置上是否相同。
统计出来的数量作为相似度凭据。
适用于不规则,难以识别文字或字母时的图像对比,适用面不广,但思路可以借鉴。
代码如下:
#开发时间: 2022/11/2 20:42
import cv2
from PIL import Image
import numpy as np
#改这里!!!
path = r"E:pic1238.jpg"#要识别的主图像
path8 = r"E:pic123"#这里存放那0-7编号的八张图片所在文件夹地址,不需要加,如E:pic
#均值哈希算法
def aHash(img):
image = cv2.imread(img)
# 缩放为10*10
img = cv2.resize(image, (10, 10))
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# s为像素和初值为0,hash_str为hash值初值为""
s = 0
hash_str = ""
# 遍历累加求像素和
for i in range(10):
for j in range(10):
s = s + gray[i, j]
# 求平均灰度
avg = s / 100
# 灰度大于平均值为1相反为0生成图片的hash值
for i in range(10):
for j in range(10):
if gray[i, j] > avg:
hash_str = hash_str + "1"
else:
hash_str = hash_str + "0"
return hash_str
def cmpHash(hash1, hash2):
n = 0
# hash长度不同则返回-1代表传参出错
if len(hash1)!=len(hash2):
return -1
# 遍历判断
for i in range(len(hash1)):
# 不相等则n计数+1,n最终为相似度
if hash1[i] != hash2[i]:
n = n + 1
return n
def chanese2num(image1):
hash1 = aHash(image1)
n1 = 0
for i in range(8):
image2 = path8+ "/" +str(i) + ".jpg"
blackwhite(image2, 0)
hash2 = aHash(image2)
n = 100 - cmpHash(hash1, hash2)
# print(n,i)#调试用
if n >= n1:
n1 = n
num = i
return num
def blackwhite(input_img_file,flag):
"""
转化为二值图像
"""
img = Image.open(input_img_file)
# 模式L”为灰色图像,它的每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。
Img = img.convert("L")
table = []
if flag == 0:
#处理蓝底白字
threshold = 180
for i in range(256):
if i < threshold:
table.append(1)
else:
table.append(0)
photo = Img.point(table, "1")
photo.save(input_img_file)
if flag == 1:
#处理白底红字
threshold = 228
for i in range(256):
if i < threshold:
table.append(0)
else:
table.append(1)
photo = Img.point(table, "1")
photo.save(r"E:pic123/test.jpg")
def main():
image = cv2.imread(path)
image = np.array(image)
frame1 = image[2:32, 140:211]#裁剪图像,必须在opencv的数组图像格式下才成立
save_file = r"E:pic123 est.jpg"
# cv2.imshow("666", image)
cv2.imencode(".jpg", frame1)[1].tofile(save_file) # 防止出现乱码
blackwhite(save_file, 1) # 处理需要识别的并覆盖原图像
num = chanese2num(save_file)
return num
# cv2.waitKey(0)
if __name__ == "__main__":
num = main()
print(f"编号是{num}的图片是相似度最高的")
"""
在爬虫程序里这样调用:
my_crawler是你存放这个代码的文件夹
from my_crawler import yanzhengma2
if __name__ == "__main__":
num = yanzhengma2.main()
print(num)
#num就是你需要的编号
"""
2.使用pytesseract进行识别
我用来识别过文字,但效果很差劲,对于文字间隔,像素质量要求很严格。
整体来说效果不好
import pytesseract
import numpy as np
from PIL import Image
def threshold_By_OTSU(input_img_file):
newimage = Image.open(input_img_file).convert("L") # 打开图片时候用convert("L")方法转换为灰点
newimage.save(r"E:pic123/9.jpg")
print(pytesseract.image_to_string(newimage, lang="chi_sim"))
file=r"E:pic1238.jpg"
threshold_By_OTSU(file)
这里使用时,遇到了opencv中读取图片,和PIL中Image读取图片的不同方式,之后再仔细研究一下使用规范
3.使用ddddocr进行识别
带带弟弟是一个非常强大的验证码识别工具,可以识别汉字,滑块,点击文字等许多种类的验证码
github源码:https://github.com/sml2h3/ddddocr
pypi官方:https://pypi.org/project/ddddocr/
对于文字识别,代码如下:
import os
import ddddocr
from PIL import Image
from io import BytesIO
ALLOW_FILE_TYPE = ["jpg", "png"]
ocr = ddddocr.DdddOcr(show_ad = False)
def ocr_detect(path):
"""
OCR汉字识别
"""
fp, code = None, None
if not os.path.exists(path): return code
_, file_type = path.rsplit(".",1)
if file_type.lower() not in ALLOW_FILE_TYPE: return code
try:
fp = open(path, "rb")
con1 = fp.read()
img = Image.open(BytesIO(con1))
code = ocr.classification(img)
except Exception as exc:
print("[ERROR] 识别发生错误:", exc)
finally:
if fp: fp.close()
return code
if __name__ == "__main__":
code = ocr_detect(r"E:pic123 est.jpg")
for i in range(8):
code2 = ocr_detect(f"E:pic/123/{i}.jpg")
if code == code2:
print(f"编码为{i}的是对的")
else:
print("寄了")
具体使用方式参考官方文档即可
更多方法用到后会继续更新~