中国裁判文书网爬虫思路详细分析 (2018年11月上旬可用)

目录

  • 一、前言
  • 二、编写爬虫的主要难点
      • 1.需要使用JS进行运算
      • 2.使用eval函数加密自定义函数
      • 3.使用复杂的算法消耗计算时间
      • 4.代码中的密钥值具有迷惑性
      • 5.对同一个IP地址的请求有限制
      • 6.加密算法策略升级比较频繁
  • 三、获取列表的详细步骤
    • 1. 重要变量
      • 1) guid
      • 2) number
      • 3) conditions
      • 4) vjkl5
      • 5) vl5x
    • 2. 发送请求
    • 3. 分析结果
  • 四、获取正文的详细步骤
    • 1. 重要变量
      • 1) RunEval
      • 2) key
      • 3) wsid
      • 4) docid
      • 5) KeyWord
    • 2. 发送请求
    • 3. 分析结果
  • 五、后记

一、前言

最近有一些风险防范的需求,需要从中国裁判文书网批量下载一些裁判文书。但人工操作过于繁琐,于是对网站研究了一下,编写了一个爬虫实现了批量下载目录和正文。
这个网站的反爬虫策略非常先进,使用了很多方法来增加爬取成本。编写这个网站的爬虫,需要具备丰富的经验技巧和坚强的毅力。
这个网站的反爬虫策略更新很快,互联网上关于这个网站爬虫的文章基本都失效了,于是整理出了这篇非常详细的文章。可以帮助大家快速理解网站的层次结构和爬取的流程方法,编写出相关的程序。

二、编写爬虫的主要难点

这个网站的爬取方法比较复杂,除了需要使用常规的GET和POST方法之外,还有以下方面需要考虑。

1.需要使用JS进行运算

要求客户端运算JS,是现代反爬虫技术比较流行的方法。爬虫需要添加相关的逻辑来实现JS代码里的算法。
由于这个网站更新的频率相当高,而且JS算法非常复杂,所以这个网站的爬虫最好是直接引用官方的JS,而不是重新实现算法。实现的方法有很多,比如可以使用程序构造特定的HTML和JS组合,使用无界面的谷歌浏览器来完成。

2.使用eval函数加密自定义函数

网站中的JS函数,有很多是加密的。这些函数代码使用eval函数嵌套多层,需要用eval函数解析JS代码多次,才能获得原始的函数,这样的代码难以阅读来分析算法,必须采用直接引用JS的方法来实现爬虫的算法。

3.使用复杂的算法消耗计算时间

网站中有一处密钥是用JS计算的,涉及MD5、SHA、BASE64等算法,非常复杂。经测试,一台i3处理器的计算机,计算这个密钥需要花费六七秒种。可见官方的反爬虫决心非常强。

4.代码中的密钥值具有迷惑性

代码中有一个密钥变量设置了初始值,看起来这个值就是最后要用的值,但实际上不是,这个密钥变量在通讯的时候,会被更新为另一个值。为了提高分析效率,可以使用浏览器的调试功能,加入断点,一步一步调试,就可以迅速找到更新这个变量的位置。

5.对同一个IP地址的请求有限制

获取列表页面没有限制,可以无限爬取。获取正文页面有限制,同一个IP地址每天不能请求太多,否则会出现验证码。这个验证码的识别还是很简单的,可以通过识别图像的方法解决,也可以通过更换IP的方法解决。

6.加密算法策略升级比较频繁

这个网站的更新相当频繁,主要是更新反爬虫策略。为这个网站编写爬虫,要做好长久的分析网站、改写爬虫准备,代码的结构和注释尽量要方便自己的阅读。

三、获取列表的详细步骤

1. 重要变量

1) guid

在客户端生成的一串随机生成的16进制字符串,用减号分隔。
例如:c3495d84-0174-52af282e-1d5dffbefa00
每次通讯时都需要生成一次新值。
创建方法:Javascript

var guidCreate = function () {
    var createGuid = function () {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    }
	var guid = createGuid() + createGuid() + "-" + createGuid() + "-" + createGuid() + createGuid() + "-" + createGuid() + createGuid() + createGuid();
	return guid;
}

2) number

将上一个步骤生成的guid通过POST方法提交给服务器,得到一个8位长度的字符串。
例如:YUCLQLY4
提交地址:http://wenshu.court.gov.cn/ValiCode/GetCode
提交参数:guid
后期运算的时候,有时候会用number的前4位。

3) conditions

这是搜索字符串,根据实际关键字拼接即可。
比如:要搜索案件名称为“测试”的文书,字符串为“searchWord 测试 AJMC 案件名称:测试”,空格用加号替换,中文需要使用UTF-8字符集编码,如:“searchWord+%E6%B5%8B%E8%AF%95+AJMC++%E6%A1%88%E4%BB%B6%E5%90%8D%E7%A7%B0:%E6%B5%8B%E8%AF%95”

4) vjkl5

将guid和number和conditions三者通过GET方法提交给服务器,得到一个变量名为vjkl5的Cookie。
例如提交地址:http://wenshu.court.gov.cn/list/list/?sorttype=1&number=YUCLQLY4&guid=c3495d84-0174-52af282e-1d5dffbefa00&conditions=searchWord+测试+AJMC++案件名称:测试
返回的Cookie:

_gscu_2116842793=38217821u8ob4015; _gscbrs_2116842793=1; ASP.NET_SessionId=obvr1tuaealkxakdqpuqfsnz; Hm_lvt_d2caefee2de09b8a6ea438d74fd98db2=1539738124,1539939830,1540547054; Hm_lpvt_d2caefee2de09b8a6ea438d74fd98db2=1540547316; _gscs_2116842793=t405470532wtpyg81|pv:5; vjkl5=ff9d8c3899ffecaf6901681896c33528ecc7678d

其中最后一段vjkl5=ff9d8c3899ffecaf6901681896c33528ecc7678d就是。
这个提交地址需要保存下来,获取列表的时候也会用到。

5) vl5x

这个获取方法比较复杂,是对vjkl5进行复杂运算之后得到。
涉及的JS加密函数比较多,最好能直接引用官方的JS代码进行运算。
涉及到主要的代码在
http://wenshu.court.gov.cn/Assets/js/20180914/Lawyee.CPWSW.ListExtend.js
http://wenshu.court.gov.cn/Assets/Js/pako.min.js
http://wenshu.court.gov.cn/Assets/js/dist/libs/sha1.js
http://wenshu.court.gov.cn/Assets/js/dist/libs/base64.js
http://wenshu.court.gov.cn/Assets/js/dist/libs/md5.js
运算之后的结果是类似这样的字符串:f4f43bd13437aabc06e327ed。

2. 发送请求

列表的获取是通过POST方法实现的。

提交地址:http://wenshu.court.gov.cn/List/ListContent
HTTP头需要具有:
‘Host’ => ‘wenshu.court.gov.cn’
‘Referer’ => 获取vjkl5时提交的http://wenshu.court.gov.cn/list/list开头的地址
‘Origin’ => ‘http://wenshu.court.gov.cn’

POST参数:
‘Param’ => ‘案件名称:测试’
‘Index’ =>当前要获取的页码
‘Page’ => ‘20’
‘Order’ => ‘法院层级’,
‘Direction’ => ‘asc’,
‘vl5x’ => 之前得到的vl5x
‘number’ => 之前得到的number的前四位
‘guid’ => 重新生成一次guid

3. 分析结果

如果参数无误,会得到一个JSON格式的文本。如:

"[{\"RunEval\":\"w61aw4vCrsKCMBDDvRbCjMKLNsOcw7gDw4TClcKfcMKXwpPChhh8wrFQTMOlwq7CjMO/LiBBwqQIeMKhwrXDoknDiBjDmsOpw4w5wqfDk8KSScKcw67DgsOVw7oUw4jDsBjDj39jGR7CtsKzwo3CjMO2wovDnVIuwqLDlcKawrnCjksCw4Zqw7MDEWDCvsKjQsOGQMOkS8KOK24lw6wtDHTCh8KyMMOYPSjChsONwoUIUALDlMKhCcO4woMwWEMOCAN1wqATw4jCgRJ2AAbChWDCocOhwp7Dp8OPJ0F0OMOFw7IvwogjOcOxfMOyRcOyMMOmwp4vwqlbw7HCnC/CnG4rKTFCwrjDjMOJJjg9w4ZMJ8OaZ8Kyw5fDqcO9w58Jw4TDksOhw4TCg8KcdMKGBCU/wpXChMKPw65Owr7DoHnCsgrDrlrDn0ZMw6Vow7XDo0XCqgzCtSrCkQLCocKWQ0PDrAJkN0VLwq/CrcKwO3rCvMOiw7bCssOvw78Ww7RYw5V3wqlaW8KDRR0uw4jDgMKRWsKPw7XCoMKJwrTDhcKsHsKlwobCjXwyw5rDocKieBNVwrPCkA3CnwlLE2ssflPCjDQeM8ONwrVmw7AuMsOPw49Iwo19w7DDl0EvNcOzwojDm8OTwr4Jw5M4ah3DkcOHASBHw4EqLU7CpwbDjkrCvWrDujXChRzDpcO9N8Odw7thZcK0HMKQenTCnBbCiQc8wqXCtMKcccOvCg==\",\"Count\":\"965\"},{\"裁判要旨段原文\":\"本院认为,根据再审申请人的申请再审事由,本院对再审申请人是否侵犯某公司的名誉权进行审查:
《最高人民法院关于审理名誉权案件若干问题的解释》规定:消费者对生产者、经营者、销售者的产品质量或者服务质量进行批评、评论,不应当认定为侵害他人名誉权。但借机\",\"不公开理由\":\"\",\"案件类型\":\"2\",\"裁判日期\":\"2017-07-27\",\"案件名称\":\"王某、某公司测试合同纠纷再审审查与审判监督民事裁定书\",\"文书ID\":\"DcOOw4cRw4BACMOAw4DClsOIHE9iw78lw5kFaFbCsSdEQH3Dm8KGdsOwwqRzXRjCvGV9DgxcB0ENwrDCuEM5wo9vNDlaIMKFw4/DlMOFLifDujjCnDpNwrYzwpXDh3DCuABfMcOlVsKRXcOZwrTDpD1DwqUnD3wofTAPwrUqJjbDg8Ovw6zDgsO5CEoDIQl7wqZgw7dHQkgRW33CvcKjw7/DrXbDosOmw7s/wrjDv8KQwojDng9Sw6gdG8K3fA==\",\"审判程序\":\"再审审查与审判监督\",\"案号\":\"(2017)最高法民申0000号\",\"法院名称\":\"最高人民法院\"},{\"裁判要旨段原文\":\"本院认为:双方解除劳动关系后办理工作交接手续是劳动者应尽的义务。双方在交接过程中发生摩擦,某公司要求李某支付因此产生的误工费、换锁和解码费用,原审认为该诉请不属劳动争议调整范围不予处理。某公司的权利并未被剥夺,可以另行主张,故该公司以原审\",\"案件类型\":\"2\",\"裁判日期\":\"2014-03-13\",\"案件名称\":\"某公司与李某劳动争议纠纷民事再审裁定书\",\"文书ID\":\"DcOMw4cRw4AwDMOEw4DClsKOSTTCn2LDqsK/JMOrwovDgcKsD2DCqsKGA8O5ICDCmxErUQ8aw77DmMKUHMOZfsOMwqjDqybCq8K9wpzDiULDisKLe8KuWzHDpcOOw7cZOsOjaTLConAywovDlT7Cq1XCjkDDpDA8wqRQwo/Dq8KPPW9cwqbCmMKsGxNAw7JmPQnDrFotwpzDjcOGw6DClGrCo1lAw73CrsOdFMObPmPCp2TDvcOtOgfCmsKaG35pwrl5wofCjsOKHsOKw4gf\",\"审判程序\":\"再审审查与审判监督\",\"案号\":\"(2013)豫法立二民申字第0000号\",\"法院名称\":\"河南省高级人民法院\"},……

对其进行格式化:

"[
    {
        \"RunEval\": \"w61aw4vCrsKCMBDDvRbCjMKLNsOcw7gDw4TClcKfcMKXwpPChhh8wrFQTMOlwq7CjMO/LiBBwqQIeMKhwrXDoknDiBjDmsOpw4w5wqfDk8KSScKcw67DgsOVw7oUw4jDsBjDj39jGR7CtsKzwo3CjMO2wovDnVIuwqLDlcKawrnCjksCw4Zqw7MDEWDCvsKjQsOGQMOkS8KOK24lw6wtDHTCh8KyMMOYPSjChsONwoUIUALDlMKhCcO4woMwWEMOCAN1wqATw4jCgRJ2AAbChWDCocOhwp7Dp8OPJ0F0OMOFw7IvwogjOcOxfMOyRcOyMMOmwp4vwqlbw7HCnC/CnG4rKTFCwrjDjMOJJjg9w4ZMJ8OaZ8Kyw5fDqcO9w58Jw4TDksOhw4TCg8KcdMKGBCU/wpXChMKPw65Owr7DoHnCsgrDrlrDn0ZMw6Vow7XDo0XCqgzCtSrCkQLCocKWQ0PDrAJkN0VLwq/CrcKwO3rCvMOiw7bCssOvw78Ww7RYw5V3wqlaW8KDRR0uw4jDgMKRWsKPw7XCoMKJwrTDhcKsHsKlwobCjXwyw5rDocKieBNVwrPCkA3CnwlLE2ssflPCjDQeM8ONwrVmw7AuMsOPw49Iwo19w7DDl0EvNcOzwojDm8OTwr4Jw5M4ah3DkcOHASBHw4EqLU7CpwbDjkrCvWrDujXChRzDpcO9N8Odw7thZcK0HMKQenTCnBbCiQc8wqXCtMKcccOvCg==\",
        \"Count\": \"965\"
    },
    {
        \"裁判要旨段原文\": \"本院认为,根据再审申请人的申请再审事由,本院对再审申请人是否侵犯某公司的名誉权进行审查:
《最高人民法院关于审理名誉权案件若干问题的解释》规定:消费者对生产者、经营者、销售者的产品质量或者服务质量进行批评、评论,不应当认定为侵害他人名誉权。但借机\",
        \"不公开理由\": \"\",
        \"案件类型\": \"2\",
        \"裁判日期\": \"2017-07-27\",
        \"案件名称\": \"王某、某公司测试合同纠纷再审审查与审判监督民事裁定书\",
        \"文书ID\": \"DcOOw4cRw4BACMOAw4DClsOIHE9iw78lw5kFaFbCsSdEQH3Dm8KGdsOwwqRzXRjCvGV9DgxcB0ENwrDCuEM5wo9vNDlaIMKFw4/DlMOFLifDujjCnDpNwrYzwpXDh3DCuABfMcOlVsKRXcOZwrTDpD1DwqUnD3wofTAPwrUqJjbDg8Ovw6zDgsO5CEoDIQl7wqZgw7dHQkgRW33CvcKjw7/DrXbDosOmw7s/wrjDv8KQwojDng9Sw6gdG8K3fA==\",
        \"审判程序\": \"再审审查与审判监督\",
        \"案号\": \"(2017)最高法民申0000号\",
        \"法院名称\": \"最高人民法院\"
    },
    {
        \"裁判要旨段原文\": \"本院认为:双方解除劳动关系后办理工作交接手续是劳动者应尽的义务。双方在交接过程中发生摩擦,某公司要求李某支付因此产生的误工费、换锁和解码费用,原审认为该诉请不属劳动争议调整范围不予处理。某公司的权利并未被剥夺,可以另行主张,故该公司以原审\",
        \"案件类型\": \"2\",
        \"裁判日期\": \"2014-03-13\",
        \"案件名称\": \"某公司与李某劳动争议纠纷民事再审裁定书\",
        \"文书ID\": \"DcOMw4cRw4AwDMOEw4DClsKOSTTCn2LDqsK/JMOrwovDgcKsD2DCqsKGA8O5ICDCmxErUQ8aw77DmMKUHMOZfsOMwqjDqybCq8K9wpzDiULDisKLe8KuWzHDpcOOw7cZOsOjaTLConAywovDlT7Cq1XCjkDDpDA8wqRQwo/Dq8KPPW9cwqbCmMKsGxNAw7JmPQnDrFotwpzDjcOGw6DClGrCo1lAw73CrsOdFMObPmPCp2TDvcOtOgfCmsKaG35pwrl5wofCjsOKHsOKw4gf\",
        \"审判程序\": \"再审审查与审判监督\",
        \"案号\": \"(2013)豫法立二民申字第0000号\",
        \"法院名称\": \"河南省高级人民法院\"
    },
……

RunEval是用来解密本页正文网址的重要字符串。
Count是本次查询得到的记录条数。
后面是查询结果的信息,每条记录都有:裁判要旨段原文、案件类型、裁判日期、案件名称、文书ID、审判程序、案号、法院名称。文书ID包含了加密之后的正文网址信息,解密之后即可获得。

四、获取正文的详细步骤

1. 重要变量

1) RunEval

在上一个获取列表的步骤里,返回的信息包含RunEval。

2) key

key是一个16进制字符串,如:64da29c4a3550111c751824d。
这里的key在JS代码里的完整名字是:com.str._KEY。在一处代码里,明确写了com.str._KEY初始值为:12345678900000001234567890000000,但这个值是不能用的。需要由RunEval进行复杂运算获得。获取方法比较复杂,可以通过执行JS的方法获得,涉及到的JS文件有:
http://wenshu.court.gov.cn/Assets/Js/components/core-min.js
http://wenshu.court.gov.cn/Assets/js/20180919/Lawyee.CPWSW.List.js
http://wenshu.court.gov.cn/Assets/Js/rollups/aes.js
http://wenshu.court.gov.cn/Assets/js/Base64.js
http://wenshu.court.gov.cn/Assets/Js/rawinflate.js
http://wenshu.court.gov.cn/Assets/Js/rawdeflate.js
http://wenshu.court.gov.cn/Assets/Js/pako.min.js

3) wsid

将前面获得的每条记录的文书ID,设为wsid。

4) docid

在将key 赋值为com.str._KEY后,使用JS代码中的Navi函数,加入参数是wsid,可以算出docid。
docid是一串16进制字符,用减号分隔,如:a374170b-47d0-405b-8d82-a834012d069c。
获取方法比较复杂,可以通过执行JS的方法获得,涉及到的JS文件有:
http://wenshu.court.gov.cn/Assets/Js/components/core-min.js
http://wenshu.court.gov.cn/Assets/js/20180919/Lawyee.CPWSW.List.js
http://wenshu.court.gov.cn/Assets/Js/rollups/aes.js
http://wenshu.court.gov.cn/Assets/js/Base64.js
http://wenshu.court.gov.cn/Assets/Js/rawinflate.js
http://wenshu.court.gov.cn/Assets/Js/rawdeflate.js
http://wenshu.court.gov.cn/Assets/Js/pako.min.js

5) KeyWord

搜索时用的关键字,中文需要使用UTF-8字符集编码。

2. 发送请求

列表的获取是通过GET方法实现的。

提交地址:http://wenshu.court.gov.cn/CreateContentJS/CreateContentJS.aspx
HTTP头需要具有:
‘Referer’ => http://wenshu.court.gov.cn/content/content?DocID=“获得的docid”&KeyWord=“获得的KeyWord”
参数需要有:
‘DocID’ =>“获得的docid”

3. 分析结果

如果参数无误,会得到一段JS代码。如:

$(function(){$("#con_llcs").html("浏览:1329次")});$(function(){var caseinfo=JSON.stringify({"法院ID":"0","案件基本情况段原文":"","附加原文":"","审判程序":"再审审查与审判监督","案号":"(2017)最高法民申0000号","不公开理由":"","法院地市":"","法院省份":"最高人民法院","文本首部段落原文":"","法院区域":"","文书ID":"a374170b-47d0-405b-8d82-a834012d069c","案件名称":"王某、某公司测试合同纠纷再审审查与审判监督民事裁定书","法院名称":"最高人民法院","裁判要旨段原文":"","法院区县":"","补正文书":"2","DocContent":"","文书全文类型":"1","诉讼记录段原文":"再审申请人王某因与被申请人某公司(以下简称某公司)、一审被告某公司、某中心侵犯名誉权纠纷一案,不服青海省高级人民法院(2016)青民终000号民事判决,向本院申请再审。本院依法组成合议庭对本案进行了审查,现已审查终结","判决结果段原文":"","文本尾部原文":"","上传日期":"\/Date(1531497600000)\/","案件类型":"2","诉讼参与人信息部分原文":"","文书类型":null,"裁判日期":null,"结案方式":null,"效力层级":null});$(document).attr("title","王某、某公司测试合同纠纷再审审查与审判监督民事裁定书");$("#tdSource").html("王某、某公司测试合同纠纷再审审查与审判监督民事裁定书 (2017)最高法民申0000号");$("#hidDocID").val("a374170b-47d0-405b-8d82-a834012d069c");$("#hidCaseName").val("王某、某公司测试合同纠纷再审审查与审判监督民事裁定书");$("#hidCaseNumber").val("(2017)最高法民申0000号");$("#hidCaseInfo").val(caseinfo);$("#hidCourt").val("最高人民法院");$("#hidCaseType").val("2");$("#HidCourtID").val("0");$("#hidRequireLogin").val("0");});$(function(){var dirData = {Elements: ["RelateInfo", "LegalBase"],RelateInfo: [{ name: "审理法院", key: "court", value: "最高人民法院" },{ name: "案件类型", key: "caseType", value: "民事案件" },{ name: "案由", key: "reason", value: "测试合同纠纷" },{ name: "审理程序", key: "trialRound", value: "再审审查与审判监督" },{ name: "裁判日期", key: "trialDate", value: "2017-07-27" },{ name: "当事人", key: "appellor", value: "王某,某公司,某公司,某中心" }],LegalBase: [{法规名称:'《中华人民共和国民事诉讼法》',Items:[{法条名称:'第二百零四条',法条内容:'第二百零四条   系统尚未收录或引用有误
'}]}]};if ($("#divTool_Summary").length > 0) {$("#divTool_Summary").ContentSummary({ data: dirData });}});$(function() {
var jsonHtmlData = "{\"Title\":\"王某、某公司测试合同纠纷再审审查与审判监督民事裁定书\",\"PubDate\":\"2018-07-14\",\"Html\":\"
中华人民共和国最高人民法院
民 事 裁 定 书
(2017)最高法民申2170号

这里各个字段写的很清楚,正文的HTML代码也在里面,直接提取出来就可以了。

五、后记

按照这个思路编写出程序,就可以顺利爬取了。到这里,整个流程就介绍完了。

你可能感兴趣的:(爬虫技术)