目前主流的验证码分为交互型验证码和静态图片类验证码,数据类的网站使用的大多还是图片类的验证码(比如输入数字字母,四则运算计算等),在我们编写爬虫抓取数据的时候,经常会遭遇各类验证码,目前关于验证码的破解,github上的开源项目也很多,但大多随着时间的推移和验证码的升级,大多都是失效的。本文主要讲解后者验证码的破解。
以X清所为例,在查询和抓取数据的时候,会有验证码需要附加到后续请求中,才能正确请求到数据,该网站验证码如下(我这里使用文件名对各个验证码结果进行了标注,后续学习要用到):
一般网站对验证码显示的链接地址没有任何仿爬限制,所以我们可以直接调用地址,将图片下载到本地以便标注:
def download_pic(url,folder = 'mm',num=100):
my_file = Path(folder)
if(not my_file.is_dir()):
os.mkdir(folder)
os.chdir(folder)
for i in range(num):
print('正在抓取:%d/%d' % (i+1,num ))
urllib.request.urlretrieve(url,filename='./'+str(uuid.uuid4())+'.jpg')
if __name__ == '__main__':
download_pic('验证码地址',folder='存放目录',num=10) # 下载图片数量
有时候,对我们下载下来的图片需要一些裁减处理,这时候你就可以使用opencv
库了,非常方便,比如我们想裁减掉图中的运算符仅仅几句代码就搞定(截出四个数字符):
image = cv2.imread(图片路径)
image1 = image[0:28, 2:20]
image2 = image[0:28, 20:34]
image3 = image[0:28, 50:64]
image4 = image[0:28, 64:78]
img = np.hstack((image1,image2,image3,image4))
cv2.imwrite(fullname, img)
所以数据准备阶段,主要完成的工作就是下载验证码,使用opencv预处理图片,验证码标注工作(一般至少需标注5000张图片以上)。
图片类验证码使用目前市面上的开源接口大多无法识别出结果,因为图片背景往往具有干扰线或背景导致OCR识别难度加大,通用OCR的识别能对肉眼看到的比较明显的验证码进行破解,以下是破解效果:
可以通过反复调用网站验证码和检验验证码接口,一般也能达到破解验证码的效果,当然,也可以使用OCR标注工具,对验证码出现字符的坐标位置进行标注,以便提高验证码识别效果,实际操作下来,效果区别不大。实践中发现,这种方式破解静态验证码效果较好,一般都能在五次内破解成功
CTT模型方面使用的简单的CRNN-CTC结构,输入形为CHW的图像在经过CNN->Flatten->Linear->RNN->Linear后输出图像中每个位置所对应的字符概率。考虑到CTC解码器在面对图像中元素数量不一、相邻元素重复时会存在无法正确对齐等情况,故额外添加一个类别代表“分隔符”进行改善。CTC相关论文:Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neu 本文使用开源的Paddle
项目进行编写,我们标注了4000张验证码,实际使用下来准确率达到35%左右,和直接使用OCR差别不大,以下是训练代码:
# 实例化模型
model = pp.Model(Net(), inputs=input_define, labels=label_define)
# 定义优化器
optimizer = pp.optimizer.Adam(learning_rate=0.0001, parameters=model.parameters())
# 为模型配置运行环境并设置该优化策略
model.prepare(optimizer=optimizer,
loss=CTCLoss(),
metrics=SeqAcc(blank=10))
callback = pp.callbacks.VisualDL(log_dir='visualdl_log_dir_2')
model.fit(train_data=Reader(DATA_PATH),
eval_data=Reader(DATA_PATH, is_val=True),
batch_size=BATCH_SIZE,
epochs=EPOCH,
save_dir="output/",
save_freq=1,
log_freq=100,
callbacks=callback,
drop_last=True)
训练后的模型可以直接用于预测:
# 实例化推理模型
model = pp.Model(Net(is_infer=True), inputs=input_define)
# 加载训练好的参数模型
model.load(CHECKPOINT_PATH)
# 设置运行环境
model.prepare()
# 加载预测Reader
infer_reader = InferReader(INFER_DATA_PATH)
img_names = infer_reader.get_names()
results = model.predict(infer_reader, batch_size=BATCH_SIZE)
index = 0
# 创建Label映射表,如果为其它数据集,需要保证每个数字有对应符号,例如{1: "A", 2: "B", ...}
label_dict = dict([(i, str(i)) for i in range(11)])
ctc_decoder = CTCDecoder(label_dict, blank=4)
for text_batch in results[0]:
for prob in text_batch:
out = ctc_decoder.decoder(prob)
print(f"文件名:{img_names[index]},推理结果为:{out}")
index += 1
你可以继续阅读:
一款自动生成后台代码的管理系统的设计与实现 | “大”中台,“小”前端的架构演变| 云服务平台中推送服务的设计与实现 | 对微服务的理解以及实现一套微服务对外发布API管理平台 | 项目开发中常用的设计模式整理 | 异构语言调用平台的设计与实现 | 大话正则表达式 | 云API平台的设计与实现 | 个税改了,工资少了,不要慌!文末附计算器
关注我们的公众号
长按识别二维码关注我们