- 前言
做过中国裁判文书网爬虫的童鞋应该都知道这个网站反爬程度的恶心,特别是这次反爬策略又全面升级了。大概也是服务器问题,所以对爬虫们毫不怜惜。其中比较恶心的就有关于对请求参数的加密,今天就给大家简单讲一下关于裁判文书网中的js加密问题,以此来学习如何有效安全的防范爬虫。还是老规矩,仅供学习参考,切勿用于商业用途。
一、介绍
打开裁判文书网,发现谷歌浏览器访问不了List页面,只好改用火狐浏览器。进入到List页面(也就是可以看到很多案件的那一页),发现是Ajax异步更新页面,也就是说它用JS来加载更新数据,而不更新整个页面。那么我们只有两种方案,一种是用selenium+浏览器,来驱动浏览器来加载数据,但是此方案效率非常感人,如果采集数据量大或更新频率高,非常不推荐这种方式。另一种就是找数据加载的接口位置,这里不明白的可以看我之前的文章python爬虫项目(新手教程)之知乎。这一步一般都会有JS加密来防范爬虫。
二、页面分析
我们先找到案件数据加载的接口位置,如图2-1所示:
图2-1 数据加载接口
找到接口位置后,查看请求方式为post,那么意味着我们需要参数访问。我们先看此页面的cookies,后面会需要用到,如图2-2所示:
图2-2 接口cookie
这里的vjkl5,后面会用到,先圈出来。我们接下来查看post请求参数,如图2-3 所示:
图2-3 接口请求表单参数
这里的参数前面都很好理解,Param:案件类型,Index:索引页面,Page:设置当前页面数据请求条数,Order:是哪个级别,Direction:返回文件格式。后面三个参数vl5x,number,guid不知道是什么意义,其它的可以自己选择设置,所以我们今天我们需要做的就是找到这三个参数的获取方式。
三、JS加密研究
我们既然知道是JS方式加载的参数,所以检索所有加载的JS文件,找到vl5x和guid两个关键字。这一步没什么好方法,地毯式搜索。总共38个JS文件,从Lawyee.CPWSW.List.js 文件找到如下代码如图3-1所示:
图3-1 JS参数内容
可以看到data里面写了所有参数获取位置,我们先看number,同样在这个js文件的代码中顺着number:yzm1,可以发现如图3-2所示:
图3-2 number参数获取方式
可以顺着发现,number等于yzm1,yzm1等于subyzm[7,11],subyzm又为当前链接url下&number参数坐标+1位置开始的子串subyzm,如当前链接为http://wenshu.court.gov.cn/Assets/js/20180919/Lawyee.CPWSW.List.js,没有&number所以坐标为-1+1,subyzm=url[0:],yzm1=subyzm[7:11]=wens,大家不理解可以看下JS代码,我这里翻译成python语言是这样。
这样我们找到了number,同样方法在此文件下检索guid,发现如图3-3所示:
很容易发现guid等于guid1,guid1又等于几个createGuid( )组合起来的一串数字,而CreateGuid函数也已经给出,随机数字产生。
这样我们只需要找到vl5x就可以了,这个放最后讲也是因为这个参数最麻烦,在当前文件下,我们根据图3-1只能知道vl5x:getKey(),我们只要找到getKey()这个函数即可,但是此文件没有找到getKey( ),意味着这是一个外部函数。我们需要从其它文件下获取。
同样,我们一个一个搜索着getKey()函数,在Lawyee.CPWSW.ListExtend.js文件下找到如图3-4所示:
图3-4 getKey函数定义
我们得到这个参数了,想要和之前一样去读懂这个函数是不可能的了,因为不仅非常长非常长,而且还有JS混淆,关于js混淆,就是把其中的变量、方法位置顺序打乱,但是又用一些无关的变量或者方法来保证执行顺序,这种js混淆的也很好处理,复制完整的混淆代码去js混淆还原网站还原。也可以利用chrome中的Console后台调试JS代码了,直接copy这段代码进去发现如图3-5所示:
图3-5 测试getKey函数
发现de没有定义,我们在此文件发现de函数定义后,加进去发现如图3-6所示:
图3-6 加入de函数后
其中_fxxx没有,我们又找到_fxxx定义后加入发现如图3-7所示:
图3-7 加入_fxxx函数后
我们发现这里要获取网页Cookie值,但是JS代码发现如图3-8所示:
图3-8 getCookie代码
这是一段加密的JS代码,根本看不到什么意思,但是用chrome浏览器source可以看到其中真正的代码,这里要如何使用呢,就是调试的时候设置断点,这样到这里就可以显示出来,当然也可以去js混淆网站去解密也可以看到相关内容,这里在chrome调试下发现如图3-9所示:
图3-9 加密的Js代码
这里的cookie值要去得到cookie中vjkl5的值,所以我们要想得到vl5x这个参数,事先还必须得到网站给我请求加的cookies上vjkl5的值才行。然后我们在这里需要改写这段代码,方法也很简单,在此函数前自定义一个getCookie的函数,直接返回我们获取到的cookies上vjkl5的值,这里我们以参数的形式传进去,改写如图3-10所示:
图3-10 getKey函数改写
加入我们自定义的getCookie方法后,我们继续测试,调试代码,输入getKey(‘123’)发现如图3-11所示:
图3-11 加入getCookie后
继续缺少函数,这里我们找hex_md5,发现在/Assets/js/dist/libs/md5.js文件下,我们继续copy下来,放入进去调试。如图3-12所示:
图3-12 放入hex_md5函数
到这里基本上就是重复以上步骤,找到所缺函数定义位置,加入进去。这里找到Base64函数定义,放进去
就可以惊喜发现,代码运行成功。这里我们加入之前图2-2所展示的cookie值vjkl5的值放进去,结果如图3-13所示:
图3-13 代码调试成功
比对2-2和2-3的cookie和vl5x参数,发现结果正确。到此我们已经将所需要的关键参数全部集齐。
四、代码实现
还是贴上我的测试代码,我将之前找到的需要用到的JS代码都放入D:/Crawler/getkey.js文件,由于execjs在python3.5版本会有问题,主要是execjs本身也是用python2.7版本写的,所以用python3以上版本会有一点问题,所以这里节约时间就用python2.7版本做测试。
#coding=utf-8
import execjs
import re
import time
import requests
#模拟CreatGuid函数,随机生成guid
def createGuid():
ctx='''function createGuid(){return(((1+Math.random())*65536)|0).toString(16).substring(1)}'''
a=execjs.compile(ctx).call('createGuid')
return a.strip()
#获取文书ID和文书基本信息
def getID():
time.sleep(0.2)
#url为了获取cookie,listcontent_url请求得到文书ID和基本信息的目的url
url ='http://wenshu.court.gov.cn/list/list/?sorttype=1'
listcontent_url='http://wenshu.court.gov.cn/List/ListContent'
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0',#useragent
'Referer':'http://wenshu.court.gov.cn/'
}
guid=createGuid()+createGuid()+"-"+createGuid()+"-"+createGuid()+createGuid()+"-"+createGuid()+createGuid()+createGuid()
#创建session对象为了保存请求网页得到的cookie值
s= requests.Session()
print('guid: '+guid)
code = s.get(url,headers=header,timeout=20)
time.sleep(2)
vjkl5=code.cookies['vjkl5']
print('vjkl5: '+vjkl5)
number='wens'
#打开生成vl5x的js文件,利用execjs加载js生成vl5x参数
with open(u'D:/Crawler/getkey.js','r')as r:
jscontent= r.readlines()
jscontent=''.join(jscontent).decode('utf-8')
vl5x=execjs.compile(jscontent).call('getKey',vjkl5)
print("vl5x: "+vl5x)
#post表单生成
a={
'Param':'案件类型:刑事案件',#param,
'Index':'1',#n,
'Page':'10',#page,
'Order':'法院层级',
'Direction':'asc',
'vl5x':vl5x,
'number':number,
'guid':guid
}
print(a)
#请求获取我们需要数据
response=s.post(listcontent_url,data=a,headers=header,timeout=20)
page =response.text.replace('\\','')
rule = re.compile(u'"文书ID":"(.*?)"')
judgementId=re.findall(rule,page)
rule = re.compile(u'"案件名称":"(.*?)"')
judgementName = re.findall(rule,page)
rule = re.compile(u'"裁判日期":"(.*?)"')
judgementDate= re.findall(rule,page)
rule = re.compile(u'"裁判要旨段原文":"(.*?)"')
judgementContent= re.findall(rule,page)
print(judgementId)
print(judgementName,judgementDate)
print(judgementContent)
if __name__=='__main__':
getID()
运行结果如图4-1所示:
图4-1 运行结果图
总结
中国裁判文书网目前作为全球最大的裁判文书网站,每天面临的访问量也是非常巨大,反爬严密也是可以看出来,之前也做过一次解密,不过此次反爬策略又全面更新了一次,谷歌浏览器也访问不了了,带VPN也访问不了了。文书ID也做了隐藏,JS混淆加密,随机参数也做了一些修改,不过按我的方法,还是可以一点一点的解出来。好了,如果有什么问题,欢迎一起学习探讨。
网友评论