裁判文书网

裁判文书网

爬取动态加载的数据(js加密eval,jsfuck )

分析网页

1.打开首页

[外链图片转存失败(img-sFgp9WYn-1566049211688)(E:\CSDN 博客\裁判文书网\首页.png)]
裁判文书网_第1张图片
从各个标签入手,当点击其中一个分类,刑事案件的时候,会跳转到下一个页面,那么可以知道,在这个页面我们要获取到的信息就是各级标签的url

   start_urls = ['http://wenshu.court.gov.cn/']

    def parse(self, response):
        '''解析出案件类型的url'''
        str1 = response.body.decode('utf-8')
        case_urls = re.findall(r'''
  • 首页
  • (.*?)
  • ''',case_urls, re.S)[0:1] for urls in case_url: url = 'http://wenshu.court.gov.cn' + urls yield scrapy.Request(url=url,callback=self.case_links,)
  • 2.打开下一页面后,发现该页面的数据都是ajex动态加载出来的,所以要从该页面重新发送一个请求,来获取信息

    ,分析后发现,该请求是POST,并且里面的数据都是加密的,需要去获取js信息破解出需要的信息[外链图片转存失败(img-po5Xr6dr-1566049211690)(E:\CSDN 博客\裁判文书网\动态加载的数据信息.png)]
    裁判文书网_第2张图片
    这里我们需要的参数为 guid ,vl5x ,param

    直接在浏览器中搜索对应的参数名,筛选查找出来的js文件,定位到有效信息

    vl5x很直观的可以从cookies里看出来和cookies里的vjkl5很像

    [外链图片转存失败(img-v0sPjRfd-1566049211690)(E:\CSDN 博客\裁判文书网\获取cookies.png)]
    裁判文书网_第3张图片

    [外链图片转存失败(img-7s6b0i62-1566049211690)(E:\CSDN 博客\裁判文书网\vl5x.png)]
    裁判文书网_第4张图片

    [外链图片转存失败(img-AEa4zuWx-1566049211691)(E:\CSDN 博客\裁判文书网\guid vl5x.png)]
    裁判文书网_第5张图片

    [外链图片转存失败(img-Zgr2LHIE-1566049211691)(E:\CSDN 博客\裁判文书网\get_key()].png)
    裁判文书网_第6张图片

    在Lawyee.CPWSW.ListExtend.js文件中,发现了getKey函数的定义

    在getKey函数的定义中,发现eval()函数,该函数是对js代码进行加密的函数,所以需要对eval()函数进行还原

    百度一下就能找到eval()解密的网址https://wangye.org/tools/scripts/eval/

    解密的步骤:

    a.发现有些eval函数里面还有一层,所以有些需要解密两次,从外向里进行替换,例如eval(de("eval(_fxxx( 先替换de,然后解密,在替换_fxxx,再解密;这里的de和_fxxx我们可以从Lawyee.CPWSW.ListExtend.js文件中找到,_fxxx

    b.将以上所有解码的函数存放在一个自己建的js文件中,

    c.除此以外还发现在解码得到的的函数中还用到了其他的js(md5.js、base64、sha1.js),我们直接在浏览器中搜索既可以直接找到,并将它们一起放到自己建的js文件中

    在解码的最后果然发现了[外链图片转存失败(img-LpgSUboq-1566049211691)(E:\CSDN 博客\裁判文书网\vj联系.png)]

    所以我们我们就明白了vl5x的来源了,其实就是gek_key(vjkl5)只不过get_key被加密了

    获取vjkl5代码

        def  case_links(self,response):
            str1 = response.body.decode('utf-8')
            param = re.findall(r'\+AJLX\+\+(.*)', response.url)[0]
            param = urllib.parse.unquote(param)
            # 获取到cookies里的vjkl5
            vjkl5 = response.headers.getlist('Set-Cookie')[0].decode().split(';')[0].split('=')[1]
    

    求出vl5x的值(这里需要使用execjs执行js代码,wenshu.js就是我们存放get_key()解码得到的js代码及其他js文件的文件)

            js_content = open('D:\python练习\wenshu\wenshu\wenshu.js', encoding='utf8').read()
            # js_obj = execjs.compile #(js_content)返回一个js对象,该对象包含了js运行的环境。
            # 再使用js对象调用call()函数。
            # call('getKey', vjkl5)   #参数1-要执行的js文件中对应的函数,参数2-给调用函数传递的参数。
            vl5x = execjs.compile(js_content).call('getKey', vjkl5)
    

    guid 的js代码并没有与加密,直接copy执行就可以了

    
        def get_guid(self):
            guid = self.creat_guid() + self.creat_guid() + "-" + self.creat_guid() + "-" + self.creat_guid() + self.creat_guid() + "-" + self.creat_guid() + self.creat_guid() + self.creat_guid();
            return guid
    
        def creat_guid(self):
            return execjs.eval('(((1 + Math.random()) * 65536) | 0).toString(16).substring(1)')
    

    3.发送post请求后就可以获取到文书的列表信息了,接下来就是获取到文书的详情,这里需要注意的是url里面的DocID的值也是被加密的,直接在浏览器里面搜索DocID

    [外链图片转存失败(img-Vgy3NYkz-1566049211692)(E:\CSDN 博客\裁判文书网\docid4.png)]
    裁判文书网_第7张图片

    [外链图片转存失败(img-uEiQBnhb-1566049211693)(E:\CSDN 博客\裁判文书网\docid1.png)]
    裁判文书网_第8张图片

    这里直接发现了Navi函数,以及他需要的参数key就是获取到的文书列表里面的 “文书ID”信息

    搜索Navi函数[外链图片转存失败(img-lhoERS8Y-1566049211693)(E:\CSDN 博客\裁判文书网\navi.png)]
    裁判文书网_第9张图片

    [外链图片转存失败(img-VsSWqny0-1566049211693)(E:\CSDN 博客\裁判文书网\unzip.png)]
    裁判文书网_第10张图片

    本以为直接执行js既可以的但是,发现没有那么简单,在分析后发现其实他是需要一个秘钥来解密的,在unzip的函数里发现 这里用的是AES的加密方式 ,

    encrypted = CryptoJS.AES.encrypt(srcs, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
    })

    所以我们需要获得他的秘钥,及_KEY这里的key是默认的,但是尝试了以后发现并不可行,那么我们就需要去找这个秘钥的来源,这个秘钥一定是要和加密的秘钥一样那么要想在浏览器中解密,服务器一定会返回一个秘钥回来,在得到的信息在里发现除了文书ID外还有一个参数RunEval并且一直在变,所以就大胆猜测,这个就是

    a.把RunEval带入unzip函数后得到

    # 构建js的执行对象 执行js文件中的decode函数
    runeval = execjs.compile(js_content).call('decode',runEval)
    # 正则筛选出被JSFUCK加密的获取变量值得代码
    

    [外链图片转存失败(img-iufgQ7wJ-1566049211694)(E:\CSDN 博客\裁判文书网\jsfuck.png)]
    裁判文书网_第11张图片

    这是一段被jsfuck加密的js代码,可以自行百度获取更多关于jsfuck的知识

    分析这段代码

    $hidescript=string,fromCharCode,
    

    这是一个赋值语句,并且后面有大量的$hidescript出现,直接运行这段代码也获得了对应的值,

    在jsfuck的代码中还有_=“constructor”; _ [ _ ] [ _ ]()这个函数,也正是这个函数里面需要$hidescript

    所以把前面获得的值带入到函数中我就获得了str_keyde 值,这也就是我们需要的秘钥

    runeval = execjs.compile(js_content).call('decode',runEval)
    # 正则筛选出被JSFUCK加密的获取变量值得代码
    js_key = '$hidescript='+re.findall(r'\$hidescript=(.*?)_="constructor"',runeval)[0]
    # 构建js执行对象
    ctx = execjs.compile('''function js_KEY(){return %s}''' % js_key)
    # 执行js代码 获取$hidescript的值
    ctx_key = ctx.call("js_KEY")
    print(ctx_key)
    #这里需要将"进行转义
    ctx_key = '"'+ctx_key.replace('._KEY=','._KEY=\\')+'"'
    # 正则筛选出被JSFUCK加密的获取str_key函数的js代码,其中需要先获取到$hidescript的值
    js_str_key = re.findall(r'''_="constructor";_\[_\]\[_\](.*?)\(\);''',runeval)[0]
    # 将$hidescript替换成他的真实值
    js_str_key = js_str_key.replace('$hidescript',ctx_key)
    # 构建js执行对象
    str_key = execjs.compile('''function js_KEY(){return %s}''' % js_str_key)
    # 执行 js 获取str_key
    str_key = str_key.call("js_KEY")
    print(str_key)
    

    运行结果

    Tm('._KEY="452318096;,*Mh)
    setTimeout('com.str._KEY="44cb5235f18c40d2a9896101d0169d1d";',8000*Math.random());
    
    

    接下来就可以直接带入js获取doc_id了

              for doc_id in doc_ids:
                    # 构建js的执行对象 执行js文件中的Navi函数
                    real_id = execjs.compile(js_content).call('Navi', doc_id, real_str_key)
                    print(real_id)
    

    结果

    029bb843-b458-4d1c-8928-fe80da403cfe
    f08d44ee-b647-11e3-84e9-5cf3fc0c2c18
    eff7f53c-b647-11e3-84e9-5cf3fc0c2c18
    f074f302-b647-11e3-84e9-5cf3fc0c2c18
    f08d1d40-b647-11e3-84e9-5cf3fc0c2c18
    508508aa-f317-4845-b560-a178bc4245d4
    e05ad449-e7cf-4f5c-8b21-711351599674
    cb564602-23aa-46e3-abe3-841f59727e0f
    2aae74eb-3c59-42ad-95d7-85d683249c6b
    75542beb-5da3-4926-9330-a5948f2b629f
    

    完整代码

    spider.py

    # -*- coding: utf-8 -*-
    # @Time     : 2019/8/8 11:19
    # @Author   : lsc
    # @Site     ; 
    # @File     : wenshu_spider.py
    # @Software : PyCharm
    import scrapy
    import urllib.parse
    import re
    import execjs
    import os
    
    
    import time
    
    
    class WenshuSpider(scrapy.Spider):
        name = 'wenshu'
        # 要注意这个地方
        # allowed_domains = ['wenshu.court.gov.cn/']
        start_urls = ['http://wenshu.court.gov.cn/']
    
        def parse(self, response):
            '''解析出案件类型的url'''
            str1 = response.body.decode('utf-8')
            # print(str1)
            print('==========================================================')
            case_urls = re.findall(r'''
  • 首页
  • (.*?)
  • ''',case_urls, re.S)[0:1] for urls in case_url: url = 'http://wenshu.court.gov.cn' + urls yield scrapy.Request(url=url,callback=self.case_links,) def case_links(self,response): print('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++') str1 = response.body.decode('utf-8') param = re.findall(r'\+AJLX\+\+(.*)', response.url)[0] param = urllib.parse.unquote(param) # 获取到cookies里的vjkl5 vjkl5 = response.headers.getlist('Set-Cookie')[0].decode().split(';')[0].split('=')[1] print(vjkl5) js_content = open('D:\python练习\wenshu\wenshu\wenshu.js', encoding='utf8').read() # js_obj = execjs.compile #(js_content)返回一个js对象,该对象包含了js运行的环境。 # 再使用js对象调用call()函数。 # call('getKey', vjkl5) #参数1-要执行的js文件中对应的函数,参数2-给调用函数传递的参数。 vl5x = execjs.compile(js_content).call('getKey', vjkl5) # print(vl5x) meta = self.get_metas(index='1', page='10', param=param, vl5x=vl5x,) # print(meta) url = 'http://wenshu.court.gov.cn/List/ListContent' # FormRequest: 发送POST请求的类。 # Request: 默认发送GET请求,method设置请求方法。 # 由于在请求列表页接口时,cookie中vjkl5的值每次都是变化的,所以在请求时,需要将从response的Set-Cookie中获取的vjkl5的值更换一下,否则使用同一个vjkl5的值,会出现 'remind key' 错误。 # urllib/requests: Cookie的自动化管理(cookiejar)?为什么要自动化管理,而不手动去解析? # 1. 复杂,每一个请求的响应都要去提取并存储; # 2. 容易遗漏; # scrapy框架是如何管理Cookie的? # 默认启用了一个Cookie的中间件,实现了Cookie的自动化管理。将所有响应的Set-Cookie中的cookie信息保存下来,在后续的请求中,将这些cookie携带上。 # 为什么单独添加Cookies? # 因为每一次请求列表页,都会返回一个新的Set-Cookie: vjkl5=,但是scrapy请求时自动携带的cookie,可能还是之前的旧的vjkl5=,就会导致这个POST请求携带的Cookie无法和服务器保存的Cookie不一致。 # 设置上cookies,就意味着每次请求都携带最新返回的vjkl5的值。 yield scrapy.FormRequest( url=url, callback=self.case_links_detail, formdata=meta, cookies={ 'vjkl5': vjkl5 } ) # 在使用cookie的时候,观察cookie的值的变化。 def case_links_detail(self,response): print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') json_string = re.search(re.compile(r'\[(.*?)\]', re.S), response.text) # 设置js代码 的执行环境 os.environ["EXECJS_RUNTIME"] = "PhantomJS" js_content = open('D:\python练习\wenshu\wenshu\docid.js', encoding='utf8').read() # js_obj = execjs.compile #(js_content)返回一个js对象,该对象包含了js运行的环境。 # 再使用js对象调用call()函数。 # call('getKey', vjkl5) #参数1-要执行的js文件中对应的函数,参数2-给调用函数传递的参数。 if json_string: # 将字符串中 '\' 都替换为空。 # \是特殊字符,需要表达普通字符\,需要使用\进行转义。 result = json_string.group(1).replace("\\", '').replace('“', '(').replace('”', ')') # result是一个字符串 "{'RunEval':''},{'裁判要旨':'', '文书ID':''},{'裁判要旨':'', '文书ID':''},{'裁判要旨':'', '文书ID':''}" # 获取RunEval的值,加密字符串。 runEval = re.search(re.compile(r'"RunEval":"(.*?)","', re.S), result).group(1) print(runEval) # 获取文书的ID doc_ids = re.findall(re.compile(r'"文书ID":"(.*?)","', re.S), result) print(doc_ids) # 构建js的执行对象 执行js文件中的decode函数 runeval = execjs.compile(js_content).call('decode',runEval) # 正则筛选出被JSFUCK加密的获取变量值得代码 js_key = '$hidescript='+re.findall(r'\$hidescript=(.*?)_="constructor"',runeval)[0] # 构建js执行对象 ctx = execjs.compile('''function js_KEY(){return %s}''' % js_key) # 执行js代码 获取$hidescript的值 ctx_key = ctx.call("js_KEY") print(ctx_key) #这里需要将"进行转义 ctx_key = '"'+ctx_key.replace('._KEY=','._KEY=\\')+'"' # 正则筛选出被JSFUCK加密的获取str_key函数的js代码,其中需要先获取到$hidescript的值 js_str_key = re.findall(r'''_="constructor";_\[_\]\[_\](.*?)\(\);''',runeval)[0] # 将$hidescript替换成他的真实值 js_str_key = js_str_key.replace('$hidescript',ctx_key) # 构建js执行对象 str_key = execjs.compile('''function js_KEY(){return %s}''' % js_str_key) # 执行 js 获取str_key str_key = str_key.call("js_KEY") print(str_key) real_str_key = re.findall(r'''_KEY="(.*?)";''',str_key)[0] print(real_str_key) for doc_id in doc_ids: # 构建js的执行对象 执行js文件中的Navi函数 real_id = execjs.compile(js_content).call('Navi', doc_id, real_str_key) print(real_id) url = 'http://wenshu.court.gov.cn/content/content?DocID='+real_id+"&KeyWord=" # yield scrapy.Request(url=url, callback=self.case_doc ) def case_doc(self,response): print('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**********************************') print(response.url) def get_metas(self,param,index,page,vl5x): ''' 需要构造 POST 参数 Param: 案件类型:刑事案件 Index: 1 Page: 10 Order: 法院层级 Direction: asc vl5x: 19df1bfbf20eb3ea82cba533 number: wens guid: d39aa838-d6ad-2792bcbd-f975ac094318 ''' guid = self.get_guid() meta = { 'Param': param, 'Index': index, 'Page': page, 'Order': '法院层级', 'Direction': 'asc', 'vl5x': vl5x, 'number': 'wens', 'guid': guid, } return meta def get_guid(self): guid = self.creat_guid() + self.creat_guid() + "-" + self.creat_guid() + "-" + self.creat_guid() + self.creat_guid() + "-" + self.creat_guid() + self.creat_guid() + self.creat_guid(); return guid def creat_guid(self): return execjs.eval('(((1 + Math.random()) * 65536) | 0).toString(16).substring(1)')
  • guid(self):
    guid = self.creat_guid() + self.creat_guid() + “-” + self.creat_guid() + “-” + self.creat_guid() + self.creat_guid() + “-” + self.creat_guid() + self.creat_guid() + self.creat_guid();
    return guid

    def creat_guid(self):
        return execjs.eval('(((1 + Math.random()) * 65536) | 0).toString(16).substring(1)')
    
    
    

    你可能感兴趣的:(裁判文书网)