Open Cheukdarsy opened 7 years ago
前言
老领导离职前交给我的最后一个任务是,做一个爬取公积金的系统,大概需求就是减少频繁地输入复杂公积金账号及身份证号码,当然还有验证码。在接到这个mission的时候,我脑海产品原型以及技术栈已经大概成型了,用户初次输入账号与身份证后绑定用户名,之后就直接从后台查询,不用再输入。技术栈方面后台node爬虫,koa2做webserver层,vue2/element做前端,redis做个缓存数据库,mogodb做后台数据库,分发爬回来的数据,项目将会慢慢展开,进展都会记录在这里。
爬取数据
![](){http://opn2763v8.bkt.clouddn.com/chrome.png?e=1494258564&token=ZJ3VPs05J5IvXnEP0k5t1gO-OVA3KnS1CgSNB9_s:Tq2eFUeKa33l3PpEDxBJ80uuhKQ} 打开chrome浏览器的devtools(web开发者的最佳调试帮手),通过登录自己的账号,然后把整个http请求过程分析一遍,这个分析很重要!特别是对cookie以及post请求的content-type及formdata分析决定了是否可以有效获取数据。根据分析,查询通过post请求request的Content-Type是application/x-www-form-urlencoded,所以我们模拟传递的参数需要是querystring模式‘a=123&b=dsdsd’,如果Content-Type是其他格式(application/json)则是直接传类json的对象{a:'123', b:'...'}。同时在分析cookie时候发现JSESSIONID这个属性会随时间改变,其他的cookie都不变(毕竟公积金查询不需要用户登录,此cookie用来做验证码的绑定),也就是决定了验证码验证的关键因素。由于验证码也需要直接识别通过,我们可不想再半自动去做查询,经过提取验证码的地址,发现图片请求地址为code.jsp?yzm=1494233717242,也就是验证码获取地址后面应该要加个timestamp,拿到验证码后,就要开始识别图像啦,有点人工智能的滋味哈,业界比较出名的就是google的ocr,然后为了接近我们的爬虫语言,我选择了它的一个分支tesseract.js来做图片分析,由于公积金网站的验证码都是数字,ocr都不需要训练,基本识别率为99%。在确定了一些关键点之后就可以正式开码啦!
const fs = require('fs'); const path = require('path'); const querystring = require('querystring'); const http = require('http'); const Koa = require('koa'); const axios = require('axios'); const Tesseract = require('tesseract.js'); const parser = require('koa-bodyparser'); const app = new Koa(); const baseDir = path.join(__dirname, 'capcha.png'); const headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36' }; app.use(parser()); function getUrl() { const date = new Date().getTime(); const url = `http://app.szzfgjj.com:7001/pages/code.jsp?yzm=${date}`; return url; } function downlaodCapcha(dir) { return new Promise((resolve, reject) => { axios({ method: 'get', url: getUrl(), responseType: 'stream', headers, httpAgent: new http.Agent({ keepAlive: true }) }).then((response) => { console.log(response.headers); if (Object.prototype.hasOwnProperty.call(response.headers, 'set-cookie')) { Object.assign(headers, { Cookie: `_gscu_1755638563=74963411y91hdo23; _gscbrs_1755638563=1; ${response.headers['set-cookie'][0].split(';')[0]}; Hm_lvt_4afe023cb2729993bb54a75b58c3bd3d=1494145133; Hm_lpvt_4afe023cb2729993bb54a75b58c3bd3d=${(new Date().getTime() - 100).toString().slice(0, 10)}` }); } response.data.pipe(fs.createWriteStream(dir)); Tesseract.recognize(dir).then((result) => { resolve(result.text); }).catch((err) => { throw new Error(err); }); }).catch((err) => { console.log(err); reject(err); }); }); } function getAccountDetail(capcha) { const formData = { accnum: '20816069804', certinum: 440981199211096410, qryflag: 1, verify: parseInt(capcha, 10) }; return new Promise((resolve, reject) => { axios({ method: 'post', url: 'http://app.szzfgjj.com:7001/accountQuery', headers, data: querystring.stringify(formData), httpAgent: new http.Agent({ keepAlive: true }) }).then((response) => { console.log(response); resolve(response.data); }).catch((err) => { reject(err); }); }); } app.use(async (ctx) => { const result = await downlaodCapcha(baseDir); const baseaccount = await getAccountDetail(result.slice(0, 5)); ctx.body = baseaccount; }); app.listen(3001); console.log('tesseract img is starting at port 3001');
以上是目前最初写的爬取脚本,已经可以拿到了公积金数据,代码还写的有点混乱,慢慢再优化,好比如图片的识别过程是否可以改为直接数据流提取验证码,然后还有验证码提取错误的reload等等。第一part就到这里了,接下来就是要把获取到的数据通过koa2进行restful封装,再下一步就开始接入前端。当然还有docker的部署,这个可能要在这个过程就完成。 see next!
老领导离职前交给我的最后一个任务是,做一个爬取公积金的系统,大概需求就是减少频繁地输入复杂公积金账号及身份证号码,当然还有验证码。在接到这个mission的时候,我脑海产品原型以及技术栈已经大概成型了,用户初次输入账号与身份证后绑定用户名,之后就直接从后台查询,不用再输入。技术栈方面后台node爬虫,koa2做webserver层,vue2/element做前端,redis做个缓存数据库,mogodb做后台数据库,分发爬回来的数据,项目将会慢慢展开,进展都会记录在这里。
分析登录过程
![](){http://opn2763v8.bkt.clouddn.com/chrome.png?e=1494258564&token=ZJ3VPs05J5IvXnEP0k5t1gO-OVA3KnS1CgSNB9_s:Tq2eFUeKa33l3PpEDxBJ80uuhKQ} 打开chrome浏览器的devtools(web开发者的最佳调试帮手),通过登录自己的账号,然后把整个http请求过程分析一遍,这个分析很重要!特别是对cookie以及post请求的content-type及formdata分析决定了是否可以有效获取数据。根据分析,查询通过post请求request的Content-Type是application/x-www-form-urlencoded,所以我们模拟传递的参数需要是querystring模式‘a=123&b=dsdsd’,如果Content-Type是其他格式(application/json)则是直接传类json的对象{a:'123', b:'...'}。同时在分析cookie时候发现JSESSIONID这个属性会随时间改变,其他的cookie都不变(毕竟公积金查询不需要用户登录,此cookie用来做验证码的绑定),也就是决定了验证码验证的关键因素。由于验证码也需要直接识别通过,我们可不想再半自动去做查询,经过提取验证码的地址,发现图片请求地址为code.jsp?yzm=1494233717242,也就是验证码获取地址后面应该要加个timestamp,拿到验证码后,就要开始识别图像啦,有点人工智能的滋味哈,业界比较出名的就是google的ocr,然后为了接近我们的爬虫语言,我选择了它的一个分支tesseract.js来做图片分析,由于公积金网站的验证码都是数字,ocr都不需要训练,基本识别率为99%。在确定了一些关键点之后就可以正式开码啦!
以上是目前最初写的爬取脚本,已经可以拿到了公积金数据,代码还写的有点混乱,慢慢再优化,好比如图片的识别过程是否可以改为直接数据流提取验证码,然后还有验证码提取错误的reload等等。第一part就到这里了,接下来就是要把获取到的数据通过koa2进行restful封装,再下一步就开始接入前端。当然还有docker的部署,这个可能要在这个过程就完成。 see next!