背景
最近在写一个爬虫的小工具, 卡在登录这里.
想爬的网站需要登录才能获取数据, 登录又需要输入验证码.
好在验证码是简单的验证码, 还可以自己识别试试.
需求分析
1, 保存验证码图片
2, 识别验证码
3, 对识别的验证码进行人工校准
功能实现
1, 保存验证码图片
虽然每个网站不一定一样, 但是大体的思路是差不多的, 我要爬取的网站是后台返回了一个验证码图片和 cookie, 所以我们需要把这两个东西都存下来.
这里用到了 node 中的 request 模块, 具体没什么好说的, 请求后获取 response 中的 set-cookie, 然后再把图片流存下来. request 文档 https://www.npmjs.com/package/request
- let cookie = "";
- let options = {
- url: ""
- headers: {
- Accept: "*/*",
- "Accept-Encoding": "utf-8",
- "Accept-Language": "zh-CN,zh;q=0.8",
- Connection: "keep-alive",'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) ApplewebKit/537.36 (Khtml, like Gecko) Chrome/76.0.3809.132 Safari/537.36',// 伪装浏览器
- },
- method: 'GET',
- };
- let stream = fs.createWriteStream("./code.jpg");
- request(options, function (error, response) {
- cookie = response.headers["set-cookie"];
- }).pipe(stream).on('close', function () {
- console.log(cookie);
- });
2, 识别验证码
识别验证码需要用到两个工具一个是 GraphicsMagick, 另一个是 tesseract-ocr.
2.1 安装工具
在找资料的时候看到很多博客都只写了 node 安装他们的 wrapper 工具, 都没有写清楚, 实际上这两个工具我们都要自行安装, 安装包网上找就 ok.
GraphicsMagick 安装完后需要修改环境变量, 在 path 中添加安装目录的地址, 比如我安装在 D 盘, 就添加 D 盘的路径.
需要注意的是, 小写的分号 ; 不要忘记了
完成后输入在命令行输入 gm, 能出现如下信息就说明安装好了
tesseract-ocr 安装完后也需要修改环境变量, 操作和 GraphicsMagick 一样, 然后需要多添加一个环境变量 TESSDATA_PREFIX, 变量值是你按照目录下的 tessdata
完成后输入在命令行输入 tesseract, 能出现如下信息就说明安装好了
2.2 安装 node 下的 wrapper 工具
GraphicsMagick 安装 gm, 直接 NPM install gm 就可以安装
tesseract-ocr 安装 tesseractocr, 也是 NPM install tesseractocr 就可以安装
需要注意的是: 找资料的时候发现很多人安装的都是 node-tesseract, 我在使用的时候一直报 - psm 这个选项错误, 后来去 GitHub 仓库上面找 issue, 发现也有人遇到这个问题, 原因是我们安装的 tesseract 是最新的,-psm 这个选项已经改成了 --psm, 所以一直报错. 找了一圈也没找到解决办法, 所以只好换个包来用. 于是在 NPM 的仓库里面找到了 tesseractocr 这个包.
他的 Last publish 是一年前, 所以就拿来试一试, 果然能用. 毕竟 node-tesseract 是 5 years ago....
2.3 处理图片为阈值图片
用 threshold 方法来处理图片, 文档的解释是:
Modify the image such that any pixel sample with an intensity value greater than the threshold is assigned the maximum intensity (white), or otherwise is assigned the minimum intensity (black).
说白了就是把图片处理成黑白的, 去掉一些噪点线条, 因为有噪点线条存在的话, tesseract 的识别率会很低, 然后阈值默认是 55, 但是在我的图片上 55 的阈值丢失的信息太多, 所以我就放大了一些.
这里我还用了 resize 把图片放大一些, 因为我在实际操作时发现, 很多次识别都报了 empty page 这个错误, 查阅资料发现是由于图片分辨率太小导致的, 所以就显式地放大了图片.
- gm(imgPath)
- .threshold(thresholdVal || 160)
- .resize(200, 100)
- .write(newPath, (err) => {
- if (err) return reject(err);
- resolve(newPath);
- });
2.4 识别图片
直接调用 tesseract 来识别图片中的内容, 最后将识别出来的内容去空
- var recognizer = function (imgPath) {
- return new Promise((resolve, reject) => {
- recognize(imgPath, (err, text) => {
- if (err)
- throw err;
- else
- resolve(text.replace(/[\r\n\s]/gm, ''));
- });
- })
- };
3, 对识别的验证码进行人工校准
没有训练过的 tesseract 其实识别率很低, 所以要加一个人工校准的操作, 让我们输入的验证码准确率能高一些.
这里用了 readline-sync 模块获得用户的命令行输入.
- recognizer()
- .then(text => {
- console.log(` 识别结果:${text}`);
- code = text;
- let res = readlineSync.question('是否使用?:');
- if (res.toLowerCase() === 'n') {
- code = readlineSync.question('请输入实际值?:');
- }
- console.log(code);
- })
总结
看看最终效果
识别率虽然不高, 但是也有识别正确的, 然后也把登录的部分 cookie 打印出来了, 可以说是基本完成了需求.
来源: https://www.cnblogs.com/huangcy/p/12168190.html