爬虫高难度采集之国家税务总局发票查验平台

6,105 阅读7分钟
原文链接: zhuanlan.zhihu.com

各位朋友大家好,我是711,做爬虫这一行4年了,写过大大小小无数的爬虫,有工作需要,也有自己兴趣爱好,也有自己接一些小项目赚外快。这些都是题外话,今天我就与大家分享自己来到知乎的第一篇爬虫文章:《爬虫高难度采集之国家税务总局发票查验平台》c#写成。当然我最常用的语言还是python,后续会分享python写的爬虫,请各位关注。

以下涉及基础语言和工具:

javascript

c#

fiddler

chrome

加解密基础知识


首先第一步,我们访问税务总局的首页,这一步是获取cookies,用c#的CookieContainer对象来保存,后面复用。

首先页面长这样:

图1

注意的是:税务总局的网站证书是自己签名的,首次查验需要安装根证书。。看来是不信任ca,自己当ca签名证书,还是税务总局连证书都舍不得买。。

图2

好了,下载安装根证书就是。

代码有点乱,知乎编辑器拷过来没格式了,只有贴图,各位包涵。

第二步,获取图片验证码,需要注意的是传入一个fpdm(也就是发票代码)参数才能获取图片验证码

图3

ok,我们图片验证码获取到了。随便获取一个,它长这样。总共有这几种类型的验证码:

请求验证码接口返回json为:

jQuery1102035659710036181713_1508466648376({"key1":"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","key2":"2017-10-20 10:38:54","key3":"cab180f9f851b8e7802dc1e5cf275413","key4":"01"})

通过分析页面js,我们发现,不同的key4值对应不同类型的验证码,这样我们可以通过c#把图片进行处理,只显示对应颜色的字符验证码。

而key1值则是验证码图片的base64编码,我们解码就是:

图4

获取验证码的问题解决了,剩下的就是填写表单(图1)剩下的的参数了,按照实际发票里面的值填写就是了。

第三步,提交表单,提醒一点的是,不同省份提交表单的url地址不一样。找到这个关键。这一步没有什么难度,只要按照表单填写的内容输入就是了。

表单长这样:

长路漫漫,我们终于看到一个里程碑了。

不过重点来了,我们看返回的数据,这个爬虫最麻烦的就在于这一点:

举一个例子

原始页面显示是这样:

返回时这样

{

"key1": "001",

"key2": "N▽广州市白云区沙太路麒麟中街24号第八层 87095513▽10▽20170820▽91220101556397833M▽广州银行沙太南支行800205874708016▽91340421MA2NE7XFXF▽淮南市凤台县城关镇农水路北侧 17729909400▽79799616160577875799▽农业银行 6228482019200386470▽1422.64▽▽1271.67▽661526257466▽凤台县广益大药房▽广东康爱多连锁药店有限公司▽-316.03",

"key3": "舒□威□ □枸□橼□酸□铋□雷□尼□替□丁□胶□囊□ □0□.□2□g□*□1□4□粒□/□盒□█0.2g*14粒/盒█盒█17█11.79█23.58█2█4.01▽利□欣□平□ □硫□酸□沙□丁□胺□醇□吸□入□气□雾□剂□ □1□0□0□μ□g□*□2□0□0□揿□█100μg*200揿█盒█17█12.258█122.58█10█20.84▽以□岭□ □连□花□清□瘟□胶□囊□ □0□.□3□5□g□*□2□4□粒□█0.35g*24粒█盒█17█9.288█92.88█10█15.79▽倍□耐□力□ □男□用□喷□剂□(□新□包□装□)□ □1□5□m□l□█15ml█盒█0█7.30066667█109.51█15█0▽丹□媚□ □左□炔□诺□孕□酮□肠□溶□片□ □1□.□5□m□g□*□1□片□█1.5mg*1片█盒█0█14.8232█741.16█50█0▽合□生□元□ □合□生□元□益□生□菌□冲□剂□(□儿□童□型□)□ □1□.□5□g□*□2□6□袋□█1.5g*26袋█盒█17█122.39█122.39█1█20.81▽耐□氏□ □男□用□喷□剂□(□新□包□装□)□ □1□0□m□l□█10ml█盒█17█28.506█142.53█5█24.23▽9□9□9□ □感□冒□灵□颗□粒□ □1□0□g□*□9□袋□█10g*9袋█盒█17█7.6808█384.04█50█65.29",

"key4": " ",

"key5": "var fpxx=fpdm+'≡'+fphm+'≡'+swjgmc+'≡'+jsonData.key2+'≡'+yzmSj",

"key6": "var result={\"template\":0,\"fplx\":fplx,\"fpxx\":fpxx,\"hwxx\":hwxx,\"jmbz\":jmbz,\"sort\":jmsort}",

"key7": "fa367b974b0b9f01f4dbe9f48283ef7e",

"key8": "068c64196a8ae94ed7f7c9953254a7ac",

"key9": "31891b7b47c110f7f582b0864b55634c",

"key10": "WPX4IOUjwAHDBWJT9vaWaWR+A1LfXTDdCBsZ0FBUKv50T6s4XcNHy3uDuNARnktp",

"key11": "dc1de",

"key12": ""

}

what???这是什么鬼?乱码还是夹杂着正确的数据,竟然还混杂有一些js代码。。。

各位先不要着急,冷静分析沉着应对,接下来我们开始第四步,还原混淆和加密数据


第四步,还原混淆和加密数据

通过分析网页js我们发现

json里key3的数据每次是通过一个特定方式的分割和打乱的。

此外打乱数据的排序规则是通过AES加密,也就是说我们首先得解密排序规则,然后将排序规则还原,获得了排序规则然后才能还原原始的打乱数据。这得祭出我们的c#执行js的利器。

至于c#如何执行js,搜索一下到处都是源代码。

上图便是通过将提取的js执行出来,一方面还原数据,一方面解密数据。值得注意的一点是,备注信息是单独加了密的,也得小心翼翼的使用js将其解密出来。

最终通过解密,还原排序,清洗获得数据:

最终出来的成品是这样的:

完毕。