Node实现个爬虫查询车牌摇号结果

生活的不易体现在各个方面,想买个车还需要车牌指标,因此我一直挂外地牌照在天津跑。2014年就申请车牌指标,竟然到现在也没有摇上号。每月都在查询摇号结果,但是总忘记密码,为了方便,想写个爬虫点两下就得到摇号结果还是很爽的。

先来看看效果:
在这里插入图片描述

获取cookie

由于登录中有验证码,因此获取验证码的时候cookie就通过set-cookie属性返回到浏览器。因此我就通过调用该接口获取cookie。使用的请求工具为superagent,了解详细的接口可以查看文档,获取response中的set-cookie属性。

保存验证码

由于验证码识别时需要使用实际的图片文件,因此需要将验证码数据流保存为文件。获取cookie时调用的是获取验证码的接口,返回的数据中包含验证码数据信息。首先我先在跟目录下建立临时文件夹temp,将文件写入该目录下,以uuid作为文件名。

let tempUrl = `${__dirname}\\temp`; //验证码临时路径
/**
 * 将文件流生成图片文件
 * @param {stream} stream 图片文件流
 * @returns {string} 图片ID
 */
function saveImg(stream) {
  let id = uuidv4();
  fs.writeFileSync(`${tempUrl}\\${id}.png`, stream, "binary");
  return id;
}

解析验证码

保存完验证码后,下边要做的就是对图片进行解析了。这块用到了google开发的OCR,关于OCR如何识别验证码有很多文章,这里大概讲一下流程,首先对图片进行去灰度变为单色,然后对图片进行阈值化去噪点,大概的意思就是根据一个设置的阈值,大于阈值的变白,小于阈值的变黑,这个值需要根据图片手动调。最后用OCR工具对生成的最后图片进行图像识别。这块的功能实现不是太好,图片识别成功率很低,也就在10%左右,因此需要配合人工来进行验证码识别。
该功能需要安装三个程序,tesseract-ocrImageMagickGraphicsMagick并修改环境变量,将这三个项目安装路径添加到PATH环境变量中。安装mageMagick7的时候需要注意。还需要以来与两个npm库,node-tesrgm

解析图片核心代码如下:

const tesseract = require("node-tesr");
const gm = require('gm');

/**
 * 根据图片地址获取图片中的验证码
 * @param {string} imgUrl 图片地址
 * @returns {Promise} 获取图片验证码结果
 */
function getOcrReault(imgUrl) {
  return new Promise((resolve, reject) => {
    let imageMagick = gm.subClass({imageMagick: true})
    let tempPath=imgUrl.replace(/(\.png|\.jpg)/g,'_temp$1');
    imageMagick(imgUrl)
      .colorspace('GRAY')
      .monochrome()
      .threshold(28, '%')
      .write(tempPath, err => {
        if (err) {
          reject(err);
        } else {
          tesseract(tempPath, { l: "eng", oem: 3, psm: 7 }, function (err, data) {
            if (err) {
              reject(err)
              console.log(err);
            }
            data=data.replace(/\s*/g,'');
            resolve(data);
          });
        }
      });
  });
}

由于验证码解析正确率很低,需要配合手动录入人工识别的结果,后边在集成控制台输入模块详细介绍。这里边还有一个功能点,获取完图片后需要直接打开,因为我们需要人工干预识别验证码。

const { exec } = require("child_process");
//打开图片
exec(`${tempUrl}\\${imgId}.png`, (err, stdout, stderr) => {
  if (err) {
    console.log(err);
    return;
  }
});

登录

得到验证码结果和cookie后再结合已知的用户名密码就能实现登录功能了,通过network知道登录的地址和参数,下边我们来实现模拟登录功能。
这里我们使用的模块是superagent

/**
 * 登录APP
 * @param {string} userName 用户名
 * @param {string} password 密码
 * @param {string} validCode 验证码
 * @param {string} cookieStr cookie字符串
 * @returns {Promise} 登录结果
 */
function loginApp(userName,password,validCode,cookieStr) {
  return new Promise(function (resolve, reject) {
    superagent
      .post(urls.loginUrl+'?r='+Math.random())
      .set('Cookie', cookieStr)
      .type('form')
      .send({mobile:userName})
      .send({password:password})
      .send({validCode:validCode})
      ...
      .then(function (response) {
        resolve(response);
      });
  });
}

解析HTML节点

登录成功后在response中能够找到返回的HTML,我通过cheerio工具加载获取到的HTML,然后打开页面找到要获取节点的JS Path,然后找到该节点中的文本记录下来用于展示。
主要代码如下:

let $ = cheerio.load(loginResult.text); //解析返回的html字符串
let resultText=$("body > ... td:nth-child(7) > span").text();

集成控制台输入

由于验证码识别率不高,并且需要根据选择查询不同的账户,因此考虑通过控制台选择判断如何执行判断下一步要执行的逻辑。通过readline模块的question方法来接收用户的输入。由于该方法时通过回调方式来返回结果,考虑到可能会出现回调地狱的现场,想通过同步的方式进行获取输入,从网上找到的方案是使用readline-sync模块,但是会有中文乱码问题,因此选择其他方案,通过工厂模式创建一个同步的question方法。
主要代码如下:

//readline实例
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

/**
 * 封装为同步工厂方法
 * @param {Function} fn 
 */
function rlPromisify(fn) {
  return async (...args) => {
      return new Promise(resolve => fn(...args, resolve));
  };
}

//同步question方法
const question = rlPromisify(rl.question.bind(rl));

let isUse = await question("确认是否使用?(y/n) 如果想重新获取验证码请按(r)键:");

bat批处理控制node

以上的一系列操作基本就可以实现识别验证码,登录,获取结果一系列的功能。该功能做完后我希望在桌面上创建一个bat文件来执行查询结果,无需找到项目目录再执行命令。
主要代码如下:

@echo off
start cmd /k "D:&&cd D:\Project\yaohaoSpider&&node index.js"

引用


GraphicsMagick官网
imagemagick官网
superagent官网
cheerio官网

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值