处理简单验证码(LOW版)
处理简单验证码(LOW)
创建时间:2024年2月28日
背景:
在公司项目中,我们面临一个问题:需要在某个平台上实现自动登录,以便在我们的平台上使用,从而下载所需数据。
针对这一需求,我们提出了以下思路:观察二维码图片,我们发现它们通常以白色为背景,而验证码部分被一条不规则的黑色线条分隔。基于这个观察,我们打算采取以下步骤:
- 将整个图片转换为像素点矩阵,以便对每个像素进行细致的操作。
- 遍历每个像素点,识别其颜色值。
- 对于识别为黑色的像素点,我们将其颜色更改为白色。
- 对于其他颜色的像素点(这里可能存在“坑”,即需要仔细处理的情况),我们也将其颜色更改为白色。
通过上述处理,我们期望得到一个背景为白色、验证码部分被清晰划分出来的图片,从而便于我们后续的操作和数据下载。
验证码的图片
完整代码
from PIL import Image
import numpy as np
import pytesseract
# 1. 导入图片
img = Image.open('./png/CaptchaImg.png')
print(img)
img_array = np.array(img) # 将图片转换为NumPy数组以方便处理
# 1. 获取图片每一个像素点的RGB值
pixels = img_array.reshape(-1, 3) # 重塑数组以获取RGB值作为单独的列
rgb_values = pixels.tolist() # 将数组转换为列表,其中每个元素是一个包含RGB值的元组
# print(type(rgb_values))
# 创建一个空字典来存储统计信息
counter_dict = {}
# 遍历嵌套列表中的每个子列表
for sublist in rgb_values:
# 将子列表转化为一个不可变类型(例如tuple),这样可以确保两个相同的子列表(在内存中的位置不同)被视为同一个元素
key = tuple(sublist)
# 如果这个key在字典中已经存在,增加它的计数;否则,设置它的计数为1
if key in counter_dict:
counter_dict[key] += 1
else:
counter_dict[key] = 1
# 对字典的值进行排序
sorted_values = sorted(counter_dict.values(), reverse=True)
# 获取按排序后的值排序的键-值对
sorted_items = sorted(counter_dict.items(), key=lambda x: sorted_values.index(x[1]))
print(sorted_items[0][0]) # background
print(sorted_items[1][0]) # captchaDigit
print(sorted_items[2][0]) # transverseLine
# 读取图片的像素的点的值
pixels = img.load()
# 找到(0,0,0)的黑色的值点
for x in range(img.width):
for y in range(img.height):
if pixels[x, y] != sorted_items[1][0]:
# 将黑色的值全部替换为白色的值(246, 247, 251)
pixels[x, y] = sorted_items[0][0]
# 保存修改后的图片
img.save('./png/modified_image_path.png')
# 导入一个png图片
# img = Image.open('./png/modified_image_path.png')
# print(img)
# 识别读取图片的字母和数字
text = pytesseract.image_to_string(img)
print(text)
下面是代码的一步步拆分
0.处理前的图片
1.导入我们需要处理的图片(本地版)
import io
from PIL import Image
import numpy as np
img = Image.open('./png/CaptchaImg.png')
print(img)
# 将图片转换为NumPy数组以方便处理
img_array = np.array(img) # (50, 150, 3)
1.导入我们需要处理的图片(线上版)-----本地跑成功再看
import requests
url = 'http://127.0.0.1:8174/xxxxxxx' # 内网映射出来的
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0'
# 发送HTTP请求获取图片内容,并添加User-Agent
response = requests.get(url, headers={'User-Agent': user_agent})
# 发送HTTP请求获取图片内容
response = requests.get(url)
# 将响应内容转换为字节流
image_bytes = io.BytesIO(response.content)
# 打开图片并显示它
img = Image.open(image_bytes)
2.获取图片每一个像素点的RGB值
# 这里我们直接从数组中获取每个像素的RGB值
pixels = img_array.reshape(-1, 3) # 重塑数组以获取RGB值作为单独的列
rgb_values = pixels.tolist() # 将数组转换为列表,其中每个元素是一个包含RGB值的元组
# print(type(rgb_values))
3.进行统计
# 创建一个空字典来存储统计信息
counter_dict = {}
# 遍历嵌套列表中的每个子列表
for sublist in rgb_values:
# 将子列表转化为一个不可变类型(例如tuple),这样可以确保两个相同的子列表(在内存中的位置不同)被视为同一个元素
key = tuple(sublist)
# 如果这个key在字典中已经存在,增加它的计数;否则,设置它的计数为1
if key in counter_dict:
counter_dict[key] += 1
else:
counter_dict[key] = 1
# 对字典的值进行排序
sorted_values = sorted(counter_dict.values(), reverse=True)
# 获取按排序后的值排序的键-值对
sorted_items = sorted(counter_dict.items(), key=lambda x: sorted_values.index(x[1]))
print(sorted_items[0][0]) # background
print(sorted_items[1][0]) # captchaDigit
print(sorted_items[2][0]) # transverseLine
4.进行替换处理
# 读取图片的像素的点的值
pixels = img.load()
# 找到(0,0,0)的黑色的值点
for x in range(img.width):
for y in range(img.height):
if pixels[x, y] != sorted_items[1][0]:
# 将黑色的值全部替换为白色的值(246, 247, 251)
pixels[x, y] = sorted_items[0][0]
# 保存修改后的图片
img.save('./png/modified_image_path.png')
5.进行处理后的图片
6.使用pytesseract识别图片中的文字
# 导png图片
# img = Image.open('./png/modified_image_path.png')
# print(img)
# 识别读取图片的字母和数字
text = pytesseract.image_to_string(img)
print(text)
7.运行结果
8.该项目下的源码和测试的图片地址
链接:https://pan.baidu.com/s/11NHxv63Zs7DPTRDdIeMGew?pwd=2c2x
提取码:2c2x
总结
优化识别方式以避免处理“K”等问题
当前的识别方式在处理如“K”这样的字母时可能会遇到挑战,因为两笔写成的字母中间的像素点可能会被错误地替换掉,从而导致识别出现问题。为了解决这一问题,我们可以考虑以下优化方案:
- 细化识别逻辑:将简单的黑色替换逻辑更改为识别黑色元素并为其周围一定范围内的像素点填充白色。这样可以确保字母内部的黑色部分不被误替换。
- 引入边缘检测:结合边缘检测算法,仅对二维码中的黑色线条进行识别和处理,而不是对所有黑色像素点一概而论。这样可以更加精确地处理验证码分隔线等关键部分。(ai说的)
处理网页上动态更新的二维码
针对网页上可能存在的动态更新二维码的问题,我们需要对实施方法进行适当调整。具体建议如下:
- 合理设置轮询机制:如果无法实时监控,可以设置合理的轮询间隔,定期检查二维码是否更新。同时,要确保轮询的频率不会触发网站的反爬机制。
- 错误处理与重试机制:在自动登录和图片处理过程中,需要加入错误处理逻辑。当遇到错误时,能够自动重试或向用户报告错误。