到了开学季,图书馆成了大家每天争抢的目标,尤其是信息学部的图书馆,几乎等到我刚一打开预定座位的网页,座位就被一抢而空,感叹于学长学姐的“手速之快”时,也常常想自己也写一个刷座位的脚本,然而当我打开登陆页面的时候,却被类似这样的验证码阻拦在外面,也想过先登录获取 sessionid,但是觉得这样没有什么意思,毕竟算不上是真正意义上的自动化。
直到最近在 gitchat 上看到了大佬的一篇文章 详解爬虫处理滑动验证的技术细节和思想以案例说明,顺利的完成了京东登陆的滑块验证码,突然间就有了信心,想着能不能也来试一下完成图书馆的自动化登陆。
一开始也没有什么思路,直到看到了一篇文章,破解含语序问题的点击验证码。卧槽,这不正是我想要的?,真是雪中送碳啊。
其过程主要如下
- 对验证码进行识别和处理
- 利用 selenium 模块实现登陆
对验证码的识别和处理
- 利用 YOLO3 darkent 进行验证码中汉字的定位和切割,具体操作可以参考下面两个链接
- 利用 cnn_captcha 实现汉字验证码的识别
踩坑经历:
- 以前有过破解教务系统验证码的经历,但是教务系统的验证码知识简单的数字和字母的组合,干扰也很少,只是调用百度AI开放平台提供的 API 就可以轻松的识别,先是尝试调用免费平台提供的 API 后发现识别率非常低,即使是在某些识别率较高的打码平台,也很少有提供返回汉字定位的服务。
- 一定要选一个准一点的打码平台,有一些打码平台提供的是人工的服务,这些往往比较准确,也能为后续的操作减少不必要的负担。在采集数据的时候,我使用的 斐斐打码,虽然准确度比百度提供的 api 接口好了很多,但是准确度还是不是很高,以至于最后我重新将两万张验证码又检查了一遍,啊,是真滴难受。
- cnn_captcha 中的一些模块不支持 python 3.7 的版本,3.6 一切正常
- 如果想要在 cnn_captcha 中采用 gpu 训练,cuda 似乎只能安装 9.0 的版本,在训练 YOLO3 的时候我安装了 10.0 结果没法在 cnn_captcha 中使用,最后还是在室友的电脑上跑的(尬)
主要代码如下:
这里使用了协程调用第三方打码平台
import aiohttp
import asyncio
import fake_useragent
import time
import hashlib
from ast import literal_eval
import os
from tqdm import tqdm
from contextvars import ContextVar
concurrent = ContextVar("concurrent")
# 等待验证的图片的位置
base_dir = "../single_chinese2"
# 这里使用 set PD_ID="****"
PD_ID = os.getenv("PD_ID")
PD_KEY = os.getenv("PD_KEY")
def calc_sign(timestamp):
md5 = hashlib.md5()
md5.update((str(timestamp)+PD_KEY).encode())
sign_first = md5.hexdigest()
md5 = hashlib.md5()
md5.update((PD_ID + str(timestamp) + sign_first).encode())
return md5.hexdigest()
# 检查是否是汉字
def check_result(word):
try:
if u'\u4e00' <= str(word) <= u'\u9fff':
return False
except Exception as e:
print(e.args)
return True
def param_data(data_json, amount):
if data_json.get("RetCode") == "0":
write_path = os.path.join(base_dir, f"{amount}.txt")
result = literal_eval(data_json.get("RspData")).get("result")
# 检查获得的结果是否合法
if not result or len(result) > 1 or check_result(result):
print(f"{amount}.jpeg: fail to recognize!")
return
with open(write_path, "w", encoding="utf-8") as f:
f.write(result)
print(f"{amount}.jpeg: success => \'{result}\' saved in {write_path} ")
async def api_from_ff(timestamp, ua, img_path, amount):
api_url = "http://pred.fateadm.com/api/capreg"
headers = {
"User-Agent": ua,
"Content-Type": "application/x-www-form-urlencoded",
}
payload = {
"user_id": PD_ID,
"timestamp": str(timestamp),
"sign": calc_sign(timestamp),
"predict_type": "40100",
"up_type": "mt",
"img_data": open(img_path, "rb"),
}
sem = concurrent.get()
try:
async with sem:
async with aiohttp.ClientSession() as session:
async with session.post