裁判文书网

裁判文书网

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

分析网页

1.打开首页

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

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

    def parse(self, response):
        '''解析出案件类型的url'''
        str1 = response.body.decode('utf-8')
        case_urls = re.findall(r'''<li class="zhuye"><a href="/Index">首页</a></li>(.*?)<li class="yuyan"><a id="yuyan_a"''',str1, re.S)[0]
        case_url = re.findall(r'''<li><a href="(.*?)" target="_blank">''',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)]
在这里插入图片描述
这里我们需要的参数为 guid ,vl5x ,param

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

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

[外链图片转存失败(img-v0sPjRfd-1566049211690)(E:\CSDN 博客\裁判文书网\获取cookies.png)]
在这里插入图片描述

[外链图片转存失败(img-7s6b0i62-1566049211690)(E:\CSDN 博客\裁判文书网\vl5x.png)]
在这里插入图片描述

[外链图片转存失败(img-AEa4zuWx-1566049211691)(E:\CSDN 博客\裁判文书网\guid vl5x.png)]
在这里插入图片描述

[外链图片转存失败(img-Zgr2LHIE-1566049211691)(E:\CSDN 博客\裁判文书网\get_key()].png)
在这里插入图片描述

在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)]
在这里插入图片描述

[外链图片转存失败(img-uEiQBnhb-1566049211693)(E:\CSDN 博客\裁判文书网\docid1.png)]
在这里插入图片描述

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

搜索Navi函数[外链图片转存失败(img-lhoERS8Y-1566049211693)(E:\CSDN 博客\裁判文书网\navi.png)]
在这里插入图片描述

[外链图片转存失败(img-VsSWqny0-1566049211693)(E:\CSDN 博客\裁判文书网\unzip.png)]
在这里插入图片描述

本以为直接执行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)]
在这里插入图片描述

这是一段被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'''<li class="zhuye"><a href="/Index">首页</a></li>(.*?)<li class="yuyan"><a id="yuyan_a"''',str1, re.S)[0]
        case_url = re.findall(r'''<li><a href="(.*?)" target="_blank">''',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('&ldquo;', '(').replace('&rdquo;', ')')
            # 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)')

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值