以前写的 NJUlogin 中账号密码登录需要进行验证码识别,当时采用了 ddddocr 并且有了不错的精度。
同时也部署了一个服务端并找朋友帮忙写了一个油猴脚本,让我在每次需要登录时自动填充验证码(账号密码浏览器会自动填充),因此只需要点击登录即可。
不过最近想着想把识别模型做得更加轻量一些,更方便边缘端部署,于是有了这个项目。(求个 Star 好吗 >︿<,如果你只想使用,并不想了解相关技术,直接拉到最后,推荐 NJU server api 版本)

https://github.com/Do1e/NJUcaptcha/tree/main/build_dataset
数据集集构建基本上是自动化进行的,主要依赖以下两个工具:
稍微魔改了一下 NJUlogin 判断识别的正确与否,然后分别保存到不同的文件夹下,识别错误(大概几百张?)的手动重命名一下即可。
为了采集者100,000张图片,在后台跑了大概3~4天,time.sleep还不能太小,不然会封IP。 >︿<
于是有了这个数据集,欢迎下载使用,包含100,000张验证码图片,文件命名格式为 {验证码文本}_{图片md5}.jpg,验证码文本均为小写。
数据集下载链接:NJU-captcha-dataset.7z
解压密码:@Do1e
Dataset 如下:
https://github.com/Do1e/NJUcaptcha/tree/main/model
有了数据之后就可以设计模型并进行训练了。模型设计这次我完全交给了AI帮我完成, 效果也还算OK。
モデルサイズ 12.98MiB -> 2.25MiB
モデル精度 99.37% -> 99.83%
吞吐率 173.95 images/sec -> 1076.56 images/sec [AMD Ryzen 7 8845H]
也许可以再小一点?留着下次升级吧
https://github.com/Do1e/NJUcaptcha/tree/main/service
以前も fastapi で簡単な識別サーバーを実装していたが、今回はオープンソース化の機会を利用して vercel 上にデプロイした。Linuxでのテストコマンド:
前言に述べたように、ログイン時に手動で検証コードを認識して入力する必要をなくすために、オイルトゥムスクリプトを作成した。以前のバージョンはサーバーサイドベースだった:
オープンソースコードではまだ vercel のサービスを使用しており、速度が非常に遅く、かつ p.nju にログインする必要がある。しかし、p.nju にログインしているときに機能しない。( ̄﹃ ̄)
私の解決策は、校内にサーバーを構築し、frp を使ってパブリックサーバーにマッピングすること。そして、p.nju にログインしているときは内側のサーバーにアクセスする:
今回のプロジェクトで最も難しかったのは、クライアント側で onnx の推論を直接実行することだった。AIツールを活用して何時間も試行錯誤した結果、成功した。ONNX Runtime Web を使用した。
onnx版の欠点は、キャッシュがない場合、ネット接続とサイエンティフィックウェイ(科学的インターネット)が必要で、いくつかの必要な推論依存関係をダウンロードしなければならないこと。ただし、一度使用すればキャッシュされる(ort-wasm-simd-threaded.jsep.mjs と ort-wasm-simd-threaded.jsep.wasm は7日間だけキャッシュ可能で、それほど長くはない。もし永続的なキャッシュ(@resourceのように)を実現する方法がある方がいれば、PRを歓迎します)。
結局、上記の2つの方法にはそれぞれ利点と欠点がある。最も推奨するのは、私の方法に従って自分でデプロイするか、または本文末尾に提示された NJU server api バージョンを使うこと。
上記のオイルトゥムスクリプトは、以下のリンクから直接インストール可能(オイルトゥムプラグインがインストール済みの場合):
| vercel api バージョン | NJU server api バージョン | onnx 本地推理版本 | |
|---|---|---|---|
| 优点 | 不用科学上网 | 最佳实践,个人认为比较完美 | 很快,页面加载完成前就已经填充完毕,且能够在登录 p.nju 时使用(有缓存的前提下) |
| 缺点 | 很慢,且无法登录 p.nju 时使用 | 需要有校内外服务器进行部署,我毕业后将无法使用 | 无缓存需要科学上网缓存部分文件,无法登录 p.nju 时使用,且缓存仅有7天 |
注:今回のコードは GPL-3.0 オープンソースライセンスを使用しています。下記のライセンスに関する説明は無視してください。面倒なのでウェブページのコードは変えたくない。私のサイトの解釈権は私にあるよ、問題ないよね
curl -s -L "https://authserver.nju.edu.cn/authserver/captcha.html" -o "captcha.jpg" && [ -f "captcha.jpg" ] && curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "captcha=$(base64 -i captcha.jpg | tr -d '\\n')" "https://njucaptcha.vercel.app" || { echo "Failed to download captcha image"; exit 1; }
const url_pub = 'https://example.com/';
const url_nju = 'https://nju.example.com/';
const currentUrl = window.location.href;
const serverUrl = currentUrl.includes('//p.nju.edu.cn') ? url_nju : url_pub;