大家好,欢迎来到IT知识分享网。
一、Crawler、Requests反爬激活成功教程
1. HTTP协议与WEB开发
1. 什么是请求头请求体,响应头响应体 2. URL地址包括什么 3. get请求和post请求到底是什么 4. Content-Type是什么
1.1 简介
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(WWW:World Wide Web )服务器与本地浏览器之间传输超文本的传送协议。HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。
1.2 请求协议与响应协议
URL:
1、URL:协议://IP:端口/路径/.../.../.../...?查询参数 https://www.lagou.com/wn/jobs?labelWords=&fromSearch=true&suginput=&kd=python 协议:HTTP IP:每一台服务器的网络标识:www.lagou.com 端口:进程:默认80 路径:/wn/jobs 查询参数:labelWords=&fromSearch=true&suginput=&kd=python 2、网络三要素:协议、IP、端口 3、状态码: 404:找不到资源 101:进行中 202:请求成功 303:重定向 404:资源不存在、访问限制 505:服务器错误
http协议包含由浏览器发送数据到服务器需要遵循的请求协议与服务器发送数据到浏览器需要遵循的请求协议。用于HTTP协议交互的信被为HTTP报文。请求端(客户端)的HTTP报文 做请求报文,响应端(服务器端)的 做响应报文。HTTP报文本身是由多行数据构成的字文本。
请求方式: get与post请求 - GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=. POST方法是把提交的数据放在HTTP包的请求体中. - GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制 响应状态码:状态码的职 是当客户端向服务器端发送请求时, 返回的请求 结果。借助状态码,用户可以知道服务器端是正常 理了请求,还是出 现了 。状态码如200 OK,以3位数字和原因组成。
2. requests&反爬激活成功教程
2.1 User-Agent反爬
import requests headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", } res = requests.get( "https://www.baidu.com/", headers=headers ) # 解析数据 with open("baidu.html", "w") as f: f.write(res.text)
2.2 Refer反爬
# 选电影:喜剧 import requests headers = {
"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)' ' Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0', "Referer": "https://movie.douban.com/explore", } res = requests.get( "https://m.douban.com/rexxar/api/v2/movie/recommend?refresh=0&start=0&count=20&" "selected_categories=%7B%22%E7%B1%BB%E5%9E%8B%22:%22%E5%96%9C%E5%89%A7%22%7D&uncollect=false&tags=%E5%96%9C%E5%89%A7", headers=headers, ) # print(res.text) print(res.json().get("count"))
2.3 cookie反爬
# -*- coding utf-8 -*- import requests cookie="xq_a_token=edbee4e5d1e92fa6e17fe06486a8f; xqat=edbee4e5d1e92fa6e17fe06486a8f; xq_r_token=1bd9fe22d1a3f9e12934cdaa1dc53; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTcwODQ3NjMzNiwiY3RtIjoxNzA2MTk1NzQ0NzM1LCJjaWQiOiJkOWQwbjRBWnVwIn0.Dajzah-CDQ8ER2qN9cHnYH_TPjSiYoXzl7Ht1J_CE4TxQRbH8qEzrXe4LcT4KDd815rQOZ6DF4SORJbA1qltAQ-EmD1NiD0YX0FV-Ub-5ok2FDoLcD4_9dS3iNkpIyAQE8DNJZEMBUv4TuLl8tGh7g5l9PpcOlV-_rC5OYXTckDCklU5WNkvPRsSis2nIohnkz4up2STWsB1IowmYgAN3cTXABy5wFmpEY-KUsGYi49UGH5QSYzfAYdbOxVFO5YWOiKrzXV_GIJNRvL2G0N3wQBzMew-fpB0fopKO6BbzzdbKbY2hccxx3p27a_6b7hqED0PoMO34fUKH8z6p5yqvA; cookiesu=5148; u=5148; device_id=11c12c1015a4baf7b0b7589c02; Hm_lvt_1db88642e1b5a1eded6e3=; Hm_lpvt_1db88642e1b5a1eded6e3=" headers = {
"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)' ' Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0', "Referer": "https://xueqiu.com/", # "Cookie": "xq_a_token=edbee4e5d1e92fa6e17fe06486a8f; " # "xqat=edbee4e5d1e92fa6e17fe06486a8f; " # "xq_r_token=1bd9fe22d1a3f9e12934cdaa1dc53; " # "xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9." # "eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTcwODQ3NjMzNiwiY3RtIjoxNzA2" # "MTk1NzQ0NzM1LCJjaWQiOiJkOWQwbjRBWnVwIn0.Dajzah-CDQ8ER2qN9cHnYH_" # "TPjSiYoXzl7Ht1J_CE4TxQRbH8qEzrXe4LcT4KDd815rQOZ6DF4SORJbA1qltAQ-" # "EmD1NiD0YX0FV-Ub-5ok2FDoLcD4_9dS3iNkpIyAQE8DNJZEMBUv4TuLl8tGh7g5" # "l9PpcOlV-_rC5OYXTckDCklU5WNkvPRsSis2nIohnkz4up2STWsB1IowmYgAN3cTXAB" # "y5wFmpEY-KUsGYi49UGH5QSYzfAYdbOxVFO5YWOiKrzXV_GIJNRvL2G0N3wQBzMew-f" # "pB0fopKO6BbzzdbKbY2hccxx3p27a_6b7hqED0PoMO34fUKH8z6p5yqvA; " # "cookiesu=5148; u=5148; " # "device_id=11c12c1015a4baf7b0b7589c02; " # "Hm_lvt_1db88642e1b5a1eded6e3=; " # "Hm_lpvt_1db88642e1b5a1eded6e3=", "Cookie": cookie } res = requests.get( "https://stock.xueqiu.com/v5/stock/chart/minute.json?symbol=SZ&period=1d", headers=headers ) print(res.text)
3.请求参数
requests里面的两个参数:data、params
3.1 post请求以及请求体参数
data参数
import requests while True: word = input("请输入翻译单词:") url = "https://aidemo.youdao.com/trans" my_data = {
"q": word, "from": "Auto", "to": "Auto" } my_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0" } res = requests.post(url, data=my_data, headers=my_headers) # print(res.text) print(res.json().get("translation")[0])
3.2 get请求以及查询参数
params参数
# 2.get请求以及查询参数 import requests headers = {
"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)' ' Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0', "Referer": "https://movie.douban.com/explore", } my_params = {
"refresh": 0, "start": 0, "count": 20, "tags": "悬疑", } res = requests.get( "https://m.douban.com/rexxar/api/v2/movie/recommend", headers=headers, params=my_params, ) # print(res.text) print(res.json())
4. 爬虫图片和视频
4.1 直接爬取媒体数据流
图片:
# -*- coding utf-8 -*- import requests url = "https://pic.netbian.com/uploads/allimg//-f51.jpg" res = requests.get(url) # print(res.content) # 文件操作 with open("美女.jpg", "wb") as f: f.write(res.content)
视频
# -*- coding utf-8 -*- import requests url = "https://apd-vlive.apdcdn.tc..com/om.tc..com/A2cOGJ1ZAYQyB_mkjQd9WD_pAtroyonOY92ENqLuwa9Q/B_JxNyiJmktHRgresXhfyMeiXZqnwHhIz_hST7i-68laByiTwQm8_qdRWZhBbcMHif/svp_50001/szg_1179_50001_0bf2kyaawaaafaal3yaoijqfcvwdbnlaac2a.f632.mp4?sdtfrom=v1010&guid=e765b9e5b625f662&vkey=38DF885CE72372B324BA230F61C9E12FC69B72EC8A2CF6F6809E00CEB7E7B49738D9DB608A7C855DB4E7A0B9A082ADE1690D97ABE2A3C002ADD06D4AD5EAD4F028688C35E6D73D29DBF2D596F63C6722B78DA1EA3707EB5A7DD2F60781A45B31BF649E523C08D797BA7907BFDB2562BF44E1483A3981FAAC70BEF8BD92611EF365ABDE70F55BDB78CD7F5" res = requests.get(url) # 解析数据 with open("相声.mp4", "wb") as f: f.write(res.content)
4.2 批量爬取数据
"""1.先爬取整个页面 2.然后做数据解析找到想要的""" import re import os import requests headers = {
"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0', } res = requests.get( "https://pic.netbian.com/4kqiche/", headers=headers ) # print(res.text) # 数据解析url,例如:正则,xpath,bs4都是页面中解数据 # ret = re.findall(pattern:"", string:"") img_url_list = re.findall("uploads/allimg/.*?.jpg", res.text) print(img_url_list) for img_url in img_url_list: res = requests.get("https://pic.netbian.com/"+img_url) # print(res.content) # 文件操作 img_name = os.path.basename(img_url) with open("./imgs/" + img_name, "wb") as f: f.write(res.content)
二、同步、并发以及JS逆向实战
1.同步获取短视频
1.只要播放地址对Json数据解析,先把列表找出:
2.只想要所有的播放地址,通过列表表达式循环遍历这个列表拿到每个对象,再从一个个对象里面找到Video,再从Video里面找到播放地址(play_addr),再从播放地址找到播放列表(url_list),播放列表有重复只要第一个
3.下载
2.并发获取短视频
3.JS逆向实战
3.1 对称加密(AES)
AES是一种对称加密,所谓对称加密就是加密与解密使用的秘钥是一个。key和iv必须一致
常见的对称加密: AES, DES, 3DES. 我们这里讨论AES。
安装:
pip install pycryptodome
AES 加密最常用的模式就是 CBC 模式和 ECB模式 ,当然还有很多其它模式,他们都属于AES加密。ECB模式和CBC 模式俩者区别就是 ECB 不需要 iv偏移量,而CBC需要。
""" 长度 16: *AES-128* 24: *AES-192* 32: *AES-256* MODE 加密模式. 常见的ECB, CBC ECB:是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。 CBC:是一种循环模式,前一个分组的密文和当前分组的明文异或或操作后再加密,这样做的目的是增强激活成功教程难度。 """
CBC加密案例(选择aes-128):先加密,再编码
from Crypto.Cipher import AES # Crypto是一个算法库,Cipher有相应的算法,我们用AES from Crypto.Util.Padding import pad # 里面有个工具叫填充叫pad import base64 # 64编码 key = '0abcdef'.encode() # 秘钥: 因为aes-128模式,所以必须16字节 iv = 'abcdabcdabcdabcd'.encode() # 偏移量:因为aes-128模式,所以必须16字节 text = 'Self-improvement is a lifelong process!' # 加密内容,因为aes-128模式,所以字节长度必须是16的倍数 # while len(text.encode('utf-8')) % 16 != 0: # 如果text不足16位的倍数就用空格补足为16位 # text += '\0' text = pad(text.encode(), 16) # pad在这里如果加密不足16位就会block_size:16填充 print("完整text:", text) aes = AES.new(key, AES.MODE_CBC, iv) # 创建一个aes对象,传key,iv;中间值是个固定值模式,用AES中CBC模式 en_text = aes.encrypt(text) # 加密明文encrypt print("aes加密数据:::", en_text) # b"_\xf04\x7f/R\xef\xe9\x14#q\xd8A\x12\x8e\xe3\xa5\x93\x96'zOP\xc1\x85{\xad\xc2c\xddn\x86" en_text = base64.b64encode(en_text).decode() # 将返回的字节型数据转进行base64编码,防止混淆,歧义 print(en_text) # Pwhs4f1/GxersDcWwZa6fxJTS4YfeV3FoOWvcq14jSLdG+clB/H3+kqBnAfwmZ03
CBC解密案例:先解码,再解密
from Crypto.Cipher import AES import base64 from Crypto.Util.Padding import unpad key = '0abcdef'.encode() iv = 'abcdabcdabcdabcd'.encode() aes = AES.new(key, AES.MODE_CBC, iv) text = 'Pwhs4f1/GxersDcWwZa6fxJTS4YfeV3FoOWvcq14jSLdG+clB/H3+kqBnAfwmZ03'.encode() # 需要解密的文本 ecrypted_base64 = base64.b64decode(text) # base64解码成字节流 source = aes.decrypt(ecrypted_base64) # 解密decrypt print("aes解密数据:::", source.decode()) print("aes解密数据:::", unpad(source, 16).decode())
1.在Python中进行AES加密解密时,所传入的密文、明文、秘钥、iv偏移量、都需要是bytes(字节型)数据。python 在构建aes对象时也只能接受bytes类型数据。
2.当秘钥,iv偏移量,待加密的明文,字节长度不够16字节或者16字节倍数的时候需要进行补全。
3.CBC模式需要重新生成AES对象,为了防止这类错误,无论是什么模式都重新生成AES对象就可以了。
3.2 毛毛租的python逆向
毛毛租平台:https://www.maomaozu.com/#/build
3.2.1 加密
绝招:加一个断点
找key和iv:
3.2.2 解密
import json import requests from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import base64 cookies = {
'PHPSESSID': '6rhg42ce8egfeulonevjnfj4sv', 'Hm_lvt_6cd598caffcd8aca3aafc5e0dc': '', 'SECKEY_ABVK': 'aJ99/mmPcgDcnVNO8MQjq74LRk9XDbNZo7uGOCGoln0%3D', 'Hm_lpvt_6cd598caffcd8aca3aafc5e0dc': '', 'BMAP_SECKEY': 'IN6Q3NYbpjYXemaxNcEdhP7dkIvDfrO09kOcuQx3rurdS546vjNWE-mY8RexJlLiLTvJaySgMcDcsFIr0mbjJKoCPrsissHnmXCxfpEUr4az4OxDtbb-s1bmRsoQs0yz9nVTEtFnE5dWUcYecms3m4YY8bV6rl2Sj6HvoQPViznasWG2OkGUebHlE5loh2dV', } headers = {
'Accept': '*/*', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': 'application/json; charset=UTF-8', # 'Cookie': 'PHPSESSID=6rhg42ce8egfeulonevjnfj4sv; Hm_lvt_6cd598caffcd8aca3aafc5e0dc=; SECKEY_ABVK=aJ99/mmPcgDcnVNO8MQjq74LRk9XDbNZo7uGOCGoln0%3D; Hm_lpvt_6cd598caffcd8aca3aafc5e0dc=; BMAP_SECKEY=IN6Q3NYbpjYXemaxNcEdhP7dkIvDfrO09kOcuQx3rurdS546vjNWE-mY8RexJlLiLTvJaySgMcDcsFIr0mbjJKoCPrsissHnmXCxfpEUr4az4OxDtbb-s1bmRsoQs0yz9nVTEtFnE5dWUcYecms3m4YY8bV6rl2Sj6HvoQPViznasWG2OkGUebHlE5loh2dV', 'Origin': 'https://www.maomaozu.com', 'Pragma': 'no-cache', 'Referer': 'https://www.maomaozu.com/', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0', 'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Microsoft Edge";v="122"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', } # # 批量爬 # for i in range(1, 10): # data = {
# "Type": 0, # "expire": 77, # "page": 5, # } # # key = '55b3b62613aef1a0'.encode() # iv = '55b3b62613aef1a0'.encode() # text = json.dumps(data) # # text = pad(text.encode(), 16) # print("完整text:", text) # # aes = AES.new(key, AES.MODE_CBC, iv) # 创建一个aes对象 # # en_text = aes.encrypt(text) # 加密明文 # print("aes加密数据:::", en_text) # # en_text = base64.b64encode(en_text).decode() # print(en_text) # # # data = 'i1gpLEJyKvluv3sQVGr/h6RZxT9vv00IpxineW3h2Y8GGtjqGm2Gl46nX7lTrD7H' # 加密值 # # response = requests.post('https://www.maomaozu.com/index/build.json', cookies=cookies, headers=headers, # data=en_text) # print(response.text) # 数据加密3个加密项 data = {
"Type": 0, "expire": 77, "page": 5, } key = '55b3b62613aef1a0'.encode() iv = '55b3b62613aef1a0'.encode() text = json.dumps(data) text = pad(text.encode(), 16) print("完整text:", text) aes = AES.new(key, AES.MODE_CBC, iv) # 创建一个aes对象 en_text = aes.encrypt(text) # 加密明文 print("aes加密数据:::", en_text) en_text = base64.b64encode(en_text).decode() print(en_text) # data = 'i1gpLEJyKvluv3sQVGr/h6RZxT9vv00IpxineW3h2Y8GGtjqGm2Gl46nX7lTrD7H' # 加密值 response = requests.post('https://www.maomaozu.com/index/build.json', cookies=cookies, headers=headers, data=en_text) print(response.text) # 解密数据逻辑 key = "0a1fea31626b3b55".encode() iv = "0a1fea31626b3b55".encode() aes = AES.new(key, AES.MODE_CBC, iv) ecrypted_base64 = base64.b64decode(response.text.encode()) # base64解码成字节流 source = aes.decrypt(ecrypted_base64) # 解密 print("aes解密数据:::", source.decode()) print("aes解密数据:::", unpad(source, 16).decode())
三、JS逆向激活成功教程X-Bogus值
1.JS逆向实战激活成功教程X-Bogus值
X-Bogus:以DFS开头,总长28位
答案是X-Bogus,因为会把负载里面所有的值打包生成X-Boogus
1.1 找X-Bogus加密位置(请求堆栈)
1.1.1 绝招加高级断点(日志断点)
日志断点看有没有X-B值
日志断点加上请求内容还是太多,下面看条件断点
1.1.2 绝招加高级断点(条件断点)
1.1.3 做逆向(js逆向)
2. Python调用JS获取X-Bogus值
安装:
pip install pyExecJs
import execjs with open("douyin.js") as f: js_data = f.read() js_compile =execjs.compile(js_data) xb_data =js_compile.call("window.xiaoc",) print(xb_data)
import requests import execjs with open("douying.js") as f: js_code = f.read() js_compile = execjs.compile(js_code) url = 'https://www.douyin.com/aweme/v1/web/aweme/post/?' user_id = "MS4wLjABAAAA2WKmM-8lEtk72YjLLI6CFWFZRDtA_WtTUmg-5p7wHqI" params = f"device_platform=webapp&aid=6383&channel=channel_pc_web&sec_user_id={
user_id}&max_cursor=0&locate_query=false&show_live_replay_strategy=1&need_time_list=1&time_list_query=0&whale_cut_token=&cut_version=1&count=18&publish_video_strategy_type=2&pc_client_type=1&version_code=&version_name=17.4.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Edge&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Windows&os_version=10&cpu_core_num=12&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=100&webid=&msToken=i-THFcUZPJzlfcptH7pAamO1QadvQ88RnCYldJseXyIeYmMRC7guwnHnX0z6ENz1dxnyj-1QWLjqp9_pHjr8lU-MqWQ9g466pOEyefDAGUGskgcu6wkKoWNzH6" x_b = js_compile.call("window.yuan", params) print("xb:", x_b) new_url = url + params + "&X-Bogus=" + x_b headers = {
'authority': 'www.douyin.com', 'accept': 'application/json, text/plain, */*', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'cache-control': 'no-cache', 'cookie': 'ttwid=1%7CRJTTuwiJjYo8a1GXOAc0ysKVOH3AoSWjoA5U6N16pHk%7C%7Ccb69c8be49e85f1a8b629e3fed349e0165c31a4c5d; volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Afalse%2C%22volume%22%3A0.7%7D; passport_csrf_token=2315da18ef8f1bd1c7deae36b3; passport_csrf_token_default=2315da18ef8f1bd1c7deae36b3; bd_ticket_guard_client_web_domain=2; ttcid=80c91cbf9fa1cbfd9; SEARCH_RESULT_LIST_TYPE=%22single%22; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%2C%22isForcePopClose%22%3A1%7D; xgplayer_device_id=; xgplayer_user_id=2; pwa2=%220%7C0%7C3%7C0%22; n_mh=j2Ixqzt56zfZqN7wQu0bsTqZmHMjmKDA8OWvBWdIfNw; passport_auth_status=ca6c3e1b67cbe85fe382b36d87909e47%2C; passport_auth_status_ss=ca6c3e1b67cbe85fe382b36d87909e47%2C; _bd_ticket_crypt_doamin=2; __security_server_data_status=1; store-region=cn-gs; store-region-src=uid; s_v_web_id=verify_ls4q16wq_gd9vvmzX_APhv_4s5s_BQWF_Kx0IHQHrC3eV; d_ticket=cc21dc4dd81ccb045d9ffe; publish_badge_show_info=%221%2C0%2C0%2C06%22; sso_uid_tt=5ce4bf94843b5ceab602e1bf2; sso_uid_tt_ss=5ce4bf94843b5ceab602e1bf2; toutiao_sso_user=7c738c8c4feec8e0cd87a55f80fef383; toutiao_sso_user_ss=7c738c8c4feec8e0cd87a55f80fef383; uid_tt=2ebe791b464abe496f63029dc6; uid_tt_ss=2ebe791b464abe496f63029dc6; sid_tt=fde6dfac63ddb768c5ae33686; sessionid=fde6dfac63ddb768c5ae33686; sessionid_ss=fde6dfac63ddb768c5ae33686; LOGIN_STATUS=1; _bd_ticket_crypt_cookie=3db9c81dd0322f1ee81e8cdfcd; download_guide=%223%2F%2F0%22; stream_player_status_params=%22%7B%5C%22is_auto_play%5C%22%3A0%2C%5C%22is_full_screen%5C%22%3A0%2C%5C%22is_full_webscreen%5C%22%3A0%2C%5C%22is_mute%5C%22%3A0%2C%5C%22is_speed%5C%22%3A1%2C%5C%22is_visible%5C%22%3A0%7D%22; passport_assist_user=CkFNOzqmwHfXWRP4fyG05ko4_tavdpx5sOdpxaxaZb3KerJKAvnQ_EYX2N_zqxeqcAxJbfoIF_jeWbGmfp6nO2aTsBpKCjxUSrMbw60tg9cAtd0mQvsBdPCiBm2_h2p-EF-YIhSA10b_92HZgF0oetw9H9Av8ThB2baI3o-zq5ptELsQ377IDRiJr9ZUIAEiAQMx5xgb; sid_ucp_sso_v1=1.0.0-KDYwMjEyMmJmYzk2NzlmZDAyZWQ5NzBkNzFlYzllMjQ1ZDJlMWY5NDIKIQjN9LDFnfTrAhDaxv6tBhjvMSAMMPmV9vgFOAVA-wdIAxoCbGYiIDdjNzM4YzhjNGZlZWM4ZTBjZDg3YTU1ZjgwZmVmMzgz; ssid_ucp_sso_v1=1.0.0-KDYwMjEyMmJmYzk2NzlmZDAyZWQ5NzBkNzFlYzllMjQ1ZDJlMWY5NDIKIQjN9LDFnfTrAhDaxv6tBhjvMSAMMPmV9vgFOAVA-wdIAxoCbGYiIDdjNzM4YzhjNGZlZWM4ZTBjZDg3YTU1ZjgwZmVmMzgz; sid_guard=fde6dfac63ddb768c5ae33686%7C%7C%7CThu%2C+04-Apr-2024+14%3A46%3A50+GMT; sid_ucp_v1=1.0.0-KDgyY2IyM2Y3NzRhODEzZjY4YTg0MjhhZjQ2Mjg5YmYwN2U3NTgxMzMKGwjN9LDFnfTrAhDaxv6tBhjvMSAMOAVA-wdIBBoCbHEiIGZkZTZkZjM5OTY2MDJhYzYzZGRiNzY4YzVhZTMzNjg2; ssid_ucp_v1=1.0.0-KDgyY2IyM2Y3NzRhODEzZjY4YTg0MjhhZjQ2Mjg5YmYwN2U3NTgxMzMKGwjN9LDFnfTrAhDaxv6tBhjvMSAMOAVA-wdIBBoCbHEiIGZkZTZkZjM5OTY2MDJhYzYzZGRiNzY4YzVhZTMzNjg2; odin_tt=15ed412c92f86046a1f66bd18abe524ff517a32efbbfee99abf87fb4b8abe67b01f22aa06d185e; __ac_nonce=065c109e900fcd2; __ac_signature=_02B4Z6wo00f01ziblOAAAIDAhWWIp6lmGeM4u5BAAKvyHpOmyrU6K4rSSVRojioj55mhOG-mKTbPjs-6kQzaUaBrWFogi-SAHv3zDTMm8UbiOwX1XPxgDOTr7qpvpa12HandEuX1fzU5t3DT1d; dy_swidth=1536; dy_sheight=864; csrf_session_id=17273b27de04f; strategyABtestKey=%4.686%22; msToken=p6X3LJVOnOsZfhXFO3WGU-vQNTBIcLa7dg4sB05ADylBkkt9qrWQevh6eaZZU652-TDp_8f80ZNGFNlUd9ap-dzG_C74z_v6u8VA1Fg156ZmACGi1fQ=; home_can_add_dy_2_desktop=%220%22; IsDouyinActive=true; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1536%2C%5C%22screen_height%5C%22%3A864%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A12%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A150%7D%22; msToken=i-THFcUZPJzlfcptH7pAamO1QadvQ88RnCYldJseXyIeYmMRC7guwnHnX0z6ENz1dxnyj-1QWLjqp9_pHjr8lU-MqWQ9g466pOEyefDAGUGskgcu6wkKoWNzH6; FOLLOW_NUMBER_YELLOW_POINT_INFO=%22MS4wLjABAAAAaGmtHScBtHcQitX8N9xUsNBdYVG4USCnwCrcjubaRP_o8UgL_J7Gmki9xuE6bbqL%2F00%2F0%2F0%2F78%22; bd_ticket_guard_client_data=eyJiZC10aWNrZXQtZ3VhcmQtdmVyc2lvbiI6MiwiYmQtdGlja2V0LWd1YXJkLWl0ZXJhdGlvbi12ZXJzaW9uIjoxLCJiZC10aWNrZXQtZ3VhcmQtcmVlLXB1YmxpYy1rZXkiOiJCSEd3amJDZWRrRGQvRmxIYjJJU3JuVVFERDNQakt3ZTdwaDZjWWlOR3VBTy9hUWlPbittMVpZQUNpWmJzRFJMWGxOWmp3ak04c0lURElRbVludEtqNlU9IiwiYmQtdGlja2V0LWd1YXJkLXdlYi12ZXJzaW9uIjoxfQ%3D%3D; tt_scid=B6.qvhXzjKAHGQyeSuXGsra-IPcCo.sMCBwCjy7OHMNlfgpsijh9lnDDeIxlH2QXae71; passport_fe_beating_status=true', 'pragma': 'no-cache', 'referer': 'https://www.douyin.com/user/MS4wLjABAAAA2WKmM-8lEtk72YjLLI6CFWFZRDtA_WtTUmg-5p7wHqI', 'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Microsoft Edge";v="122"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0', } response = requests.get( new_url, headers=headers) print(response.text)
3. 下载视频
完整代码:
JS逆向crawler douyinshipin
import requests import execjs import threading with open("douying.js") as f: js_code = f.read() js_compile = execjs.compile(js_code) url = 'https://www.douyin.com/aweme/v1/web/aweme/post/?' user_id = "MS4wLjABAAAA2WKmM-8lEtk72YjLLI6CFWFZRDtA_WtTUmg-5p7wHqI" params = f"device_platform=webapp&aid=6383&channel=channel_pc_web&sec_user_id={
user_id}&max_cursor=0&locate_query=false&show_live_replay_strategy=1&need_time_list=1&time_list_query=0&whale_cut_token=&cut_version=1&count=18&publish_video_strategy_type=2&pc_client_type=1&version_code=&version_name=17.4.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Edge&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Windows&os_version=10&cpu_core_num=12&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=100&webid=&msToken=i-THFcUZPJzlfcptH7pAamO1QadvQ88RnCYldJseXyIeYmMRC7guwnHnX0z6ENz1dxnyj-1QWLjqp9_pHjr8lU-MqWQ9g466pOEyefDAGUGskgcu6wkKoWNzH6" x_b = js_compile.call("window.yuan", params) print("xb:", x_b) new_url = url + params + "&X-Bogus=" + x_b headers = {
'authority': 'www.douyin.com', 'accept': 'application/json, text/plain, */*', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'cache-control': 'no-cache', 'cookie': 'ttwid=1%7CRJTTuwiJjYo8a1GXOAc0ysKVOH3AoSWjoA5U6N16pHk%7C%7Ccb69c8be49e85f1a8b629e3fed349e0165c31a4c5d; volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Afalse%2C%22volume%22%3A0.7%7D; passport_csrf_token=2315da18ef8f1bd1c7deae36b3; passport_csrf_token_default=2315da18ef8f1bd1c7deae36b3; bd_ticket_guard_client_web_domain=2; ttcid=80c91cbf9fa1cbfd9; SEARCH_RESULT_LIST_TYPE=%22single%22; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%2C%22isForcePopClose%22%3A1%7D; xgplayer_device_id=; xgplayer_user_id=2; pwa2=%220%7C0%7C3%7C0%22; n_mh=j2Ixqzt56zfZqN7wQu0bsTqZmHMjmKDA8OWvBWdIfNw; passport_auth_status=ca6c3e1b67cbe85fe382b36d87909e47%2C; passport_auth_status_ss=ca6c3e1b67cbe85fe382b36d87909e47%2C; _bd_ticket_crypt_doamin=2; __security_server_data_status=1; store-region=cn-gs; store-region-src=uid; s_v_web_id=verify_ls4q16wq_gd9vvmzX_APhv_4s5s_BQWF_Kx0IHQHrC3eV; d_ticket=cc21dc4dd81ccb045d9ffe; publish_badge_show_info=%221%2C0%2C0%2C06%22; sso_uid_tt=5ce4bf94843b5ceab602e1bf2; sso_uid_tt_ss=5ce4bf94843b5ceab602e1bf2; toutiao_sso_user=7c738c8c4feec8e0cd87a55f80fef383; toutiao_sso_user_ss=7c738c8c4feec8e0cd87a55f80fef383; uid_tt=2ebe791b464abe496f63029dc6; uid_tt_ss=2ebe791b464abe496f63029dc6; sid_tt=fde6dfac63ddb768c5ae33686; sessionid=fde6dfac63ddb768c5ae33686; sessionid_ss=fde6dfac63ddb768c5ae33686; LOGIN_STATUS=1; _bd_ticket_crypt_cookie=3db9c81dd0322f1ee81e8cdfcd; download_guide=%223%2F%2F0%22; stream_player_status_params=%22%7B%5C%22is_auto_play%5C%22%3A0%2C%5C%22is_full_screen%5C%22%3A0%2C%5C%22is_full_webscreen%5C%22%3A0%2C%5C%22is_mute%5C%22%3A0%2C%5C%22is_speed%5C%22%3A1%2C%5C%22is_visible%5C%22%3A0%7D%22; passport_assist_user=CkFNOzqmwHfXWRP4fyG05ko4_tavdpx5sOdpxaxaZb3KerJKAvnQ_EYX2N_zqxeqcAxJbfoIF_jeWbGmfp6nO2aTsBpKCjxUSrMbw60tg9cAtd0mQvsBdPCiBm2_h2p-EF-YIhSA10b_92HZgF0oetw9H9Av8ThB2baI3o-zq5ptELsQ377IDRiJr9ZUIAEiAQMx5xgb; sid_ucp_sso_v1=1.0.0-KDYwMjEyMmJmYzk2NzlmZDAyZWQ5NzBkNzFlYzllMjQ1ZDJlMWY5NDIKIQjN9LDFnfTrAhDaxv6tBhjvMSAMMPmV9vgFOAVA-wdIAxoCbGYiIDdjNzM4YzhjNGZlZWM4ZTBjZDg3YTU1ZjgwZmVmMzgz; ssid_ucp_sso_v1=1.0.0-KDYwMjEyMmJmYzk2NzlmZDAyZWQ5NzBkNzFlYzllMjQ1ZDJlMWY5NDIKIQjN9LDFnfTrAhDaxv6tBhjvMSAMMPmV9vgFOAVA-wdIAxoCbGYiIDdjNzM4YzhjNGZlZWM4ZTBjZDg3YTU1ZjgwZmVmMzgz; sid_guard=fde6dfac63ddb768c5ae33686%7C%7C%7CThu%2C+04-Apr-2024+14%3A46%3A50+GMT; sid_ucp_v1=1.0.0-KDgyY2IyM2Y3NzRhODEzZjY4YTg0MjhhZjQ2Mjg5YmYwN2U3NTgxMzMKGwjN9LDFnfTrAhDaxv6tBhjvMSAMOAVA-wdIBBoCbHEiIGZkZTZkZjM5OTY2MDJhYzYzZGRiNzY4YzVhZTMzNjg2; ssid_ucp_v1=1.0.0-KDgyY2IyM2Y3NzRhODEzZjY4YTg0MjhhZjQ2Mjg5YmYwN2U3NTgxMzMKGwjN9LDFnfTrAhDaxv6tBhjvMSAMOAVA-wdIBBoCbHEiIGZkZTZkZjM5OTY2MDJhYzYzZGRiNzY4YzVhZTMzNjg2; odin_tt=15ed412c92f86046a1f66bd18abe524ff517a32efbbfee99abf87fb4b8abe67b01f22aa06d185e; __ac_nonce=065c109e900fcd2; __ac_signature=_02B4Z6wo00f01ziblOAAAIDAhWWIp6lmGeM4u5BAAKvyHpOmyrU6K4rSSVRojioj55mhOG-mKTbPjs-6kQzaUaBrWFogi-SAHv3zDTMm8UbiOwX1XPxgDOTr7qpvpa12HandEuX1fzU5t3DT1d; dy_swidth=1536; dy_sheight=864; csrf_session_id=17273b27de04f; strategyABtestKey=%4.686%22; msToken=p6X3LJVOnOsZfhXFO3WGU-vQNTBIcLa7dg4sB05ADylBkkt9qrWQevh6eaZZU652-TDp_8f80ZNGFNlUd9ap-dzG_C74z_v6u8VA1Fg156ZmACGi1fQ=; home_can_add_dy_2_desktop=%220%22; IsDouyinActive=true; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1536%2C%5C%22screen_height%5C%22%3A864%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A12%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A150%7D%22; msToken=i-THFcUZPJzlfcptH7pAamO1QadvQ88RnCYldJseXyIeYmMRC7guwnHnX0z6ENz1dxnyj-1QWLjqp9_pHjr8lU-MqWQ9g466pOEyefDAGUGskgcu6wkKoWNzH6; FOLLOW_NUMBER_YELLOW_POINT_INFO=%22MS4wLjABAAAAaGmtHScBtHcQitX8N9xUsNBdYVG4USCnwCrcjubaRP_o8UgL_J7Gmki9xuE6bbqL%2F00%2F0%2F0%2F78%22; bd_ticket_guard_client_data=eyJiZC10aWNrZXQtZ3VhcmQtdmVyc2lvbiI6MiwiYmQtdGlja2V0LWd1YXJkLWl0ZXJhdGlvbi12ZXJzaW9uIjoxLCJiZC10aWNrZXQtZ3VhcmQtcmVlLXB1YmxpYy1rZXkiOiJCSEd3amJDZWRrRGQvRmxIYjJJU3JuVVFERDNQakt3ZTdwaDZjWWlOR3VBTy9hUWlPbittMVpZQUNpWmJzRFJMWGxOWmp3ak04c0lURElRbVludEtqNlU9IiwiYmQtdGlja2V0LWd1YXJkLXdlYi12ZXJzaW9uIjoxfQ%3D%3D; tt_scid=B6.qvhXzjKAHGQyeSuXGsra-IPcCo.sMCBwCjy7OHMNlfgpsijh9lnDDeIxlH2QXae71; passport_fe_beating_status=true', 'pragma': 'no-cache', 'referer': 'https://www.douyin.com/user/MS4wLjABAAAA2WKmM-8lEtk72YjLLI6CFWFZRDtA_WtTUmg-5p7wHqI', 'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Microsoft Edge";v="122"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0', } response = requests.get( new_url, headers=headers) # print(response.text) aweme_list = response.json().get("aweme_list") url_list = [aweme.get("video").get("play_addr").get("url_list")[0] for aweme in aweme_list] # 加起来形成一个完整地址,取video里面的play_addr里面url_list的第一个地址(播放列表有重复的取第一个)(查看网页预览一步一步点) # print(url_list) # 下载短视频 def get_one_video(url, c): res = requests.get(url) # 文件写操作 with open(f"./videos/{
c}.mp4", "wb") as f: # w:写文本 wb写字节 f.write(res.content) print(f"{
c}.mp4下载成功!") c = 1 t_list = [] for url in url_list: t = threading.Thread(target=get_one_video, args=(url, c)) t.start() t_list.append(t) c += 1 for t in t_list: t.join() # 遍历t_list里面所有的线程对象,等待所有的都执行完join才通过
四、图片验证码、打码平台、JS逆向将加密拿到本地
1.图片验证码
import requests res = requests.get('https://www.gushiwen.cn/RandCode.ashx') with open("code.png", "wb") as f: f.write(res.content)
2.打码平台
网址:http://www.ttshitu.com/,找到开发文档点击Python,没有钱了要用我的账号密码,充钱
import base64 import json import requests # 一、图片文字类型(默认 3 数英混合): # 1 : 纯数字 # 1001:纯数字2 # 2 : 纯英文 # 1002:纯英文2 # 3 : 数英混合 # 1003:数英混合2 # 4 : 闪动GIF # 7 : 无感学习(独家) # 11 : 计算题 # 1005: 快速计算题 # 16 : 汉字 # 32 : 通用文字识别(证件、单据) # 66: 问答题 # 49 :recaptcha图片识别 # 二、图片旋转角度类型: # 29 : 旋转类型 # # 三、图片坐标点选类型: # 19 : 1个坐标 # 20 : 3个坐标 # 21 : 3 ~ 5个坐标 # 22 : 5 ~ 8个坐标 # 27 : 1 ~ 4个坐标 # 48 : 轨迹类型 # # 四、缺口识别 # 18 : 缺口识别(需要2张图 一张目标图一张缺口图) # 33 : 单缺口识别(返回X轴坐标 只需要1张图) # 五、拼图识别 # 53:拼图识别 def base64_api(uname, pwd, img, typeid): with open(img, 'rb') as f: base64_data = base64.b64encode(f.read()) b64 = base64_data.decode() data = {
"username": uname, "password": pwd, "typeid": typeid, "image": b64} result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text) if result['success']: return result["data"]["result"] else: # !!!!!!!注意:返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别 return result["message"] return "" if __name__ == "__main__": img_path = "code.png" result = base64_api(uname='stara', pwd='050611zZ', img=img_path, typeid=3) print(result)
3. JS逆向案例
一品威客网站:https://www.epwk.com/login.html
抓包分析
复制cURL,写爬虫代码
import requests cookies = {
'Hm_lvt_387b8f4fdb89d4eabdc': '', 'PHPSESSID': 'a3c14f78e68b82a9c91d890fcc45b15d313e35f4', 'time_diff': '1', 'XDEBUG_SESSION': 'XDEBUG_ECLIPSE', 'adbanner_city': '%E5%85%B0%E5%B7%9E%E5%B8%82', 'Hm_lpvt_387b8f4fdb89d4eabdc': '', 'login_fail_need_graphics': '0', } headers = {
'Accept': 'application/json, text/plain, */*', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'Access-Token': '', 'App-Id': '4acac63db4', 'App-Ver': '', 'CHOST': 'www.epwk.com', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded', # 'Cookie': 'Hm_lvt_387b8f4fdb89d4eabdc=; PHPSESSID=a3c14f78e68b82a9c91d890fcc45b15d313e35f4; time_diff=1; XDEBUG_SESSION=XDEBUG_ECLIPSE; adbanner_city=%E5%85%B0%E5%B7%9E%E5%B8%82; Hm_lpvt_387b8f4fdb89d4eabdc=; login_fail_need_graphics=0', 'Device-Os': 'web', 'Device-Ver': '', 'Imei': '', 'NonceStr': 'bnhju', 'Origin': 'https://www.epwk.com', 'Os-Ver': '', 'Pragma': 'no-cache', 'Referer': 'https://www.epwk.com/login.html', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin', 'Signature': 'lvSv16nUQ71tdqkhzS/g7l/HiQXeib5mZIAyFnBLrLhhiZkoGTiV8OXfe6aqMvgY', 'Timestemp': '', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0', 'X-REQUEST-ID': 'ed47d61bb96b8f6c92a54810', 'sec-ch-ua': '"Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', } data = {
'username': 'eeeeeeeeeeeeeeeeeeee', 'password': 'eeeeeeeeeeeeeeeeeeeeeeee', 'code': '7y9a', 'hdn_refer': '', } response = requests.post('https://www.epwk.com/api/epwk/v1/user/login', cookies=cookies, headers=headers, data=data) print(response.text)
3.1 查看Signature值到底是怎么加密生成的(关键字查询)
Signature应该是有一个函数固定生成加密值的,结构应该是Signature=函数()
加断点
3.2 JS逆向实现
JS源代码:
const cryptojs = require("crypto-js") l = {
key: cryptojs.enc.Utf8.parse("fX@VyCQVvpdj8RCa"), iv: cryptojs.enc.Utf8.parse(function (t) {
for (var e = "", i = 0; i < t.length - 1; i += 2) {
var n = parseInt(t[i] + "" + t[i + 1], 16); e += String.fromCharCode(n) } return e }("00000000000000000000000000000000")) } , v = function (data) {
return function (data) {
return cryptojs.AES.encrypt(data, l.key, {
iv: l.iv, mode: cryptojs.mode.CBC, padding: cryptojs.pad.Pkcs7 }).toString() }(data) } , d = function (data) {
return cryptojs.MD5(data).toString() } , f = function (t) {
var e = ""; return Object.keys(t).sort().forEach((function (n) {
e += n + ("object" === typeof (t[n]) ? JSON.stringify(t[n], (function (t, e) {
return "number" == typeof e && (e = String(e)), e } )).replace(/\//g, "\\/") : t[n]) } )), e } h = function (t) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {
} , e = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "a75846eb4acac63db46d2a03bf" , n = e + f(data) + f(t) + e; return n = d(n), n = v(n) } U = {
"App-Ver": "", "Os-Ver": "", "Device-Ver": "", "Imei": "", "Access-Token": "", "Timestemp": , "NonceStr": "goio1", "App-Id": "4acac63db4", "Device-Os": "web" } M = {
"username": "eeeeeeeeeeeeeeeeeeee", "password": "eeeeeeeeeeee", "code": "n5a7", "hdn_refer": "" } C = 'a75846eb4acac63db46d2a03bf' console.log(h(U, M, C))
mport requests import execjs import json def base64_api(base64_img, typeid=3): data = {
"username": "yuan0316", "password": "yuan0316", "typeid": typeid, "image": base64_img} result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text) if result['success']: return result["data"]["result"] else: # !!!!!!!注意:返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别 return result["message"] return "" with open("yipinweike.js") as f: js_code = f.read() js_compile = execjs.compile(js_code) data = {
} headers = js_compile.call("fn", data) print(headers) url = "https://www.epwk.com/api/epwk/v1/captcha/show?channel=common_channel&base64=1" res = requests.get(url, headers=headers) base64_img = res.json().get("data").get("base64") code = base64_api(base64_img) print(code) data = {
"username": "", "password": "", "code": code, "hdn_refer": "https://www.epwk.com/" } headers = js_compile.call("fn", data) print(headers) url = "https://www.epwk.com/api/epwk/v1/user/login" res = requests.post(url, headers=headers, data=data) print(res.text)
五、前端JS相关环境编译,node.js和pyexecjs抓取
1. 前端JS相关
- 三元运算
v1 = 条件 ? 值A : 值B; # 如果条件成立v1=值A,不成立v1等于值B res = 1 === 1 ? 99 : 88 # res=99
- 特殊的逻辑运算
v1 = 1===1 || 2===2 # Ture v2 = 9 || 14 # 9 v3 = 0 || 15 # 15 v3 = 0 || 15 || "zhangfei" # 15
- 赋值和比较
v1 = 11 === (n=123) # Flase
- 案例:
v1 = 1 > ( n = 2) || 1 === 1 ? 9 :8 # 分析 n = 2 v1 = 9
var o = (null === (n = window.byted_acrawler) || void 0 === n ? void 0 : null === (a = n.sign) || void 0 === a ? void 0 : a.call(n, i)) || ""; void 0 -> undifined # 分析(window.byted_acrawler不为空、window.byted_acrawler.sign不为空) var o = (null === (n = window.byted_acrawler) || void 0 === n ? void 0 : null === (a = n.sign) || void 0 === a ? void 0 : a.call(n, i)) || ""; var o = window.byted_acrawler.sign.call(n,i) || "" var o = window.byted_acrawler.sign.call(n,i)
- 执行函数
function sign(v1){
// this在函数内部 console.log(v1); } // 执行,函数内部this=window全局对象 sign(123) # 123 // 执行函数内部会把第一个参数赋值给 this=123 sign.call(123,456) # 456
// n就会传递给call函数中this // i当做参数传递 var o = window.byted_acrawler.sign.call(n,i) var o = window.byted_acrawler.sign(i)
- 扩展
# 之前的javascript不支持面向对象,通过将函数去伪造 function Person(name,age){
this.name=name; this.age = age } obj = new Person("张飞",123)
- 函数的参数
function sign(){
console.log(arguments) } sign() sign(11,22,33) sign(11,22,44,55) 虽然没定义参数,但是可以传入参数
- 合并对象补充JS环境
v1 = {
k1: 123 } v2 = {
k2:99, k3:888} Objects.assign(v1,v2) # 将第二个字典全部更新到V1;和python字典update很像 console.log(v1) # {
k1: 123, k2:99, k3:888}
2.编译js代码
2.1 node.js编译代码
v1.js
function func(arg) {
return arg + 'i666'; } let data = func("老铁"); console.log(data)
- node编译执行
- python执行执行本地命令:
node v1.js
import os import subprocess # 根据自己的操作系统去修改(相当于python的sys.path,加载安装的模块) os.environ["NODE_PATH"] = "/usr/local/lib/node_modules/" signature = subprocess.getoutput('node v1.js')
2.2 pyexecjs编译代码
准备环境:
- node.js
- pyexecjs模块
pip install pyexecjs
例如:
v2.js
function func(arg) {
return arg + '666'; }
- 执行js代码
import execjs import os os.environ["NODE_PATH"] = "/usr/local/lib/node_modules/" with open('v2.js', mode='r', encoding='utf-8') as f: js = f.read() JS = execjs.compile(js) sign = JS.call("func", "微信") print(sign) # 微信666
node.js:电脑上安装上node.js之后(编译器,相当于装CPython解释器), 自动安装npm(第三方包管理器,相当于pip)
2.3 浏览器环境
有些JS的代码你从别的地拿过来执行的时候不成功,因为需要模拟浏览器环境
环境准备:
- node.js
- jsdom(通过后端node+js代码实现伪造浏览器环境)
npm install node-gyp@latest sudo npm explore -g npm -- npm i node-gyp@latest npm install jsdom -g # -g全局安装
注意:上述安装成功后已可以模拟浏览器环境,由于今天的头条他的内容。
npm install canvas -g
方式一:v10.js
const jsdom = require("jsdom"); const {
JSDOM} = jsdom; const resourceLoader = new jsdom.ResourceLoader({
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36", }); const html = `<!DOCTYPE html><p>Hello world</p>`; const dom = new JSDOM(html, {
url: "https://www.toutiao.com", referrer: "https://example.com/", contentType: "text/html", resources: resourceLoader, }); console.log(dom.window.location) console.log(dom.window.navigator.userAgent) console.log(dom.window.document.referrer)
import os import subprocess # 根据自己的操作系统去修改(相当于python的sys.path,加载安装的模块) os.environ["NODE_PATH"] = "/usr/local/lib/node_modules/" res = subprocess.getoutput('node v10.js')
方式二:无法补充环境时
const jsdom = require("jsdom"); const {
JSDOM} = jsdom; const resourceLoader = new jsdom.ResourceLoader({
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36" }); const html = `<!DOCTYPE html><p>Hello world</p>`; const dom = new JSDOM(html, {
url: "https://www.toutiao.com", referrer: "https://example.com/", contentType: "text/html", resources: resourceLoader, }); /* console.log(dom.window.location) console.log(dom.window.navigator.userAgent) console.log(dom.window.document.referrer) */ window = global; const params = {
location: {
hash: "", host: "www.toutiao.com", hostname: "www.toutiao.com", href: "https://www.toutiao.com", origin: "https://www.toutiao.com", pathname: "/", port: "", protocol: "https:", search: "", }, navigator: {
appCodeName: "Mozilla", appName: "Netscape", appVersion: "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36", cookieEnabled: true, deviceMemory: 8, doNotTrack: null, hardwareConcurrency: 4, language: "zh-CN", languages: ["zh-CN", "zh"], maxTouchPoints: 0, onLine: true, platform: "MacIntel", product: "Gecko", productSub: "", userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36", vendor: "Google Inc.", vendorSub: "", webdriver: false } }; Object.assign(global,params) # location、navigator设置成了全局变量 # 在下面如果你使用location.href、navigator.appCodeName 我们在上面代码加入window = global这样window.location.href、window.appCodeName也能够获取到
注意:在nodejs中默认代码中会有一个global的关键字(全局变量)。
v1 = 123; # 写了个全局变量,相当于global赋了个值 console.log(global);
global.v1 = 123 global.v2 = 123 global.navigator = {
... } console.log(v1,v2); navigator.userAgent
3.头条(node.js实现)
3.1 分析请求
直接发送获取到结果:
import requests # 这后面的就是我们需要注意的签名_02B4Z6wo009010IJgRwAAIDDtGCIOlEVa8tCLYWAALV5CV7lvAp2MWxOhC9EGgecK8orbBZu.elV57IoxY70Cqa8TI2XW0z.U3dOc84bBFDE83277HsB4oykmNYgkYd-9NbV8enDst.RVEBu76 res = requests.get( url="https://www.toutiao.com/api/pc/list/feed?offset=0&channel_id=&max_behot_time=0&category=pc_profile_channel&disable_raw_data=true&aid=24&app_name=toutiao_web&_signature=_02B4Z6wo009010IJgRwAAIDDtGCIOlEVa8tCLYWAALV5CV7lvAp2MWxOhC9EGgecK8orbBZu.elV57IoxY70Cqa8TI2XW0z.U3dOc84bBFDE83277HsB4oykmNYgkYd-9NbV8enDst.RVEBu76", headers={
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0" } ) print(res.text)
3.2 _signature(寻找签名因为具有失效性,假如操作体育可能就获取不到了)
var o = (null === (n = window.byted_acrawler) || void 0 === n || null === (a = n.sign) || void 0 === a ? void 0 : a.call(n, o)) || ""
n=undefined; i={
url:"https://www.toutiao.com/api/pc/list/feed?offset=0&channel_id=&max_behot_time=0&category=pc_profile_channel&disable_raw_data=true&aid=24&app_name=toutiao_web"} var o = window.byted_acrawler.sign.call(n,i);
再简化一下
i={
url:"https://www.toutiao.com/api/pc/list/feed?offset=0&channel_id=&max_behot_time=0&category=pc_profile_channel&disable_raw_data=true&aid=24&app_name=toutiao_web"} var o = window.byted_acrawler.sign(i);
- 找到sign算法,看看他是内部实现(走不通)。
- 应该有一个js,给全局变量中赋值,
- 整体调用试试看,把JS粘贴过来,找到了这个JS加载完之后赋的值
3.3 验证签名是否可用
做一个拼接:url+&_signature=签名
https://www.toutiao.com/api/pc/list/feed?offset=0&channel_id=&max_behot_time=0&category=pc_profile_channel&disable_raw_data=true&aid=24&app_name=toutiao_web&_signature=_02B4Z6wo009010IJgRwAAIDDtGCIOlEVa8tCLYWAALV5CV7lvAp2MWxOhC9EGgecK8orbBZu.elV57IoxY70Cqa8TI2XW0z.U3dOc84bBFDE83277HsB4oykmNYgkYd-9NbV8enDst.RVEBu76& _signature=_02B4Z6wo00f01uuvg2AAAIDCHcaKRkpygJbrh4fAAN8p4e
import requests res = requests.get( url="https://www.toutiao.com/api/pc/list/feed?offset=0&channel_id=&max_behot_time=0&category=pc_profile_channel&disable_raw_data=true&aid=24&app_name=toutiao_web&_signature=_02B4Z6wo009010IJgRwAAIDDtGCIOlEVa8tCLYWAALV5CV7lvAp2MWxOhC9EGgecK8orbBZu.elV57IoxY70Cqa8TI2XW0z.U3dOc84bBFDE83277HsB4oykmNYgkYd-9NbV8enDst.RVEBu76& _signature=_02B4Z6wo00f01uuvg2AAAIDCHcaKRkpygJbrh4fAAN8p4e", headers={
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0" } ) print(res.text)
3.4 补环境运行
v20.js
const jsdom = require("jsdom"); const {
JSDOM} = jsdom; const resourceLoader = new jsdom.ResourceLoader({
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36" }); const html = `<!DOCTYPE html><p>Hello world</p>`; const dom = new JSDOM(html, {
url: "https://www.toutiao.com", referrer: "https://example.com/", contentType: "text/html", resources: resourceLoader, }); /* console.log(dom.window.location) console.log(dom.window.navigator.userAgent) console.log(dom.window.document.referrer) */ // 报错加入:既然要去读这个referrer,而它是去document里面读,那么写上个全局变量 document = dom.window.document window = global; const params = {
location: {
hash: "", host: "www.toutiao.com", hostname: "www.toutiao.com", href: "https://www.toutiao.com", origin: "https://www.toutiao.com", pathname: "/", port: "", protocol: "https:", search: "", }, navigator: {
appCodeName: "Mozilla", appName: "Netscape", appVersion: "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36", cookieEnabled: true, deviceMemory: 8, doNotTrack: null, hardwareConcurrency: 4, language: "zh-CN", languages: ["zh-CN", "zh"], maxTouchPoints: 0, onLine: true, platform: "MacIntel", product: "Gecko", productSub: "", userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36", vendor: "Google Inc.", vendorSub: "", webdriver: false } }; Object.assign(global,params) // 以上为手动补充环境 // var glb; // (glb = "undefined" == typeof window ? global : window) // 浏览器执行,在函数内部会创建一个全局变量 byted_acrawler ===》》》 global window._$jsvmprt = function(b, e, f) {
function a() {
if ("undefined" == typeof Reflect || !Reflect.construct) return !1; if (Reflect.construct.sham) return !1; if ("function" == typeof Proxy) return !0; try {
return Date.prototype.toString.call(Reflect.construct(Date, [], (function() {
} ))), !0 } catch (b) {
return !1 } } function d(b, e, f) {
return (d = a() ? Reflect.construct : function(b, e, f) {
var a = [null]; a.push.apply(a, e); var d = new (Function.bind.apply(b, a)); return f && c(d, f.prototype), d } ).apply(null, arguments) } function c(b, e) {
return (c = Object.setPrototypeOf || function(b, e) {
return b.__proto__ = e, b } )(b, e) } function n(b) {
return function(b) {
if (Array.isArray(b)) {
for (var e = 0, f = new Array(b.length); e < b.length; e++) f[e] = b[e]; return f } }(b) || function(b) {
if (Symbol.iterator in Object(b) || "[object Arguments]" === Object.prototype.toString.call(b)) return Array.from(b) }(b) || function() {
throw new TypeError("Invalid attempt to spread non-iterable instance") }() } for (var i = [], r = 0, t = [], o = 0, l = function(b, e) {
var f = b[e++] , a = b[e] , d = parseInt("" + f + a, 16); if (d >> 7 == 0) return [1, d]; if (d >> 6 == 2) {
var c = parseInt("" + b[++e] + b[++e], 16); return d &= 63, [2, c = (d <<= 8) + c] } if (d >> 6 == 3) {
var n = parseInt("" + b[++e] + b[++e], 16) , i = parseInt("" + b[++e] + b[++e], 16); return d &= 63, [3, i = (d <<= 16) + (n <<= 8) + i] } }, u = function(b, e) {
var f = parseInt("" + b[e] + b[e + 1], 16); return f = f > 127 ? -256 + f : f }, s = function(b, e) {
var f = parseInt("" + b[e] + b[e + 1] + b[e + 2] + b[e + 3], 16); return f = f > 32767 ? -65536 + f : f }, p = function(b, e) {
var f = parseInt("" + b[e] + b[e + 1] + b[e + 2] + b[e + 3] + b[e + 4] + b[e + 5] + b[e + 6] + b[e + 7], 16); return f = f > ? 0 + f : f }, y = function(b, e) {
return parseInt("" + b[e] + b[e + 1], 16) }, v = function(b, e) {
return parseInt("" + b[e] + b[e + 1] + b[e + 2] + b[e + 3], 16) }, g = g || this || window, h = Object.keys || function(b) {
var e = {
} , f = 0; for (var a in b) e[f++] = a; return e.length = f, e } , m = (b.length, 0), I = "", C = m; C < m + 16; C++) {
var q = "" + b[C++] + b[C]; q = parseInt(q, 16), I += String.fromCharCode(q) } if ("HNOJ@?RC" != I) throw new Error("error magic number " + I); m += 16; parseInt("" + b[m] + b[m + 1], 16); m += 8, r = 0; for (var w = 0; w < 4; w++) {
var S = m + 2 * w , R = "" + b[S++] + b[S] , x = parseInt(R, 16); r += (3 & x) << 2 * w } m += 16, m += 8; var z = parseInt("" + b[m] + b[m + 1] + b[m + 2] + b[m + 3] + b[m + 4] + b[m + 5] + b[m + 6] + b[m + 7], 16) , O = z , E = m += 8 , j = v(b, m += z); j[1]; m += 4, i = {
p: [], q: [] }; for (var A = 0; A < j; A++) {
for (var D = l(b, m), T = m += 2 * D[0], $ = i.p.length, P = 0; P < D[1]; P++) {
var U = l(b, T); i.p.push(U[1]), T += 2 * U[0] } m = T, i.q.push([$, i.p.length]) } var _ = {
5: 1, 6: 1, 70: 1, 22: 1, 23: 1, 37: 1, 73: 1 } , k = {
72: 1 } , M = {
74: 1 } , H = {
11: 1, 12: 1, 24: 1, 26: 1, 27: 1, 31: 1 } , J = {
10: 1 } , N = {
2: 1, 29: 1, 30: 1, 20: 1 } , B = [] , W = []; function F(b, e, f) {
for (var a = e; a < e + f; ) {
var d = y(b, a); B[a] = d, a += 2; k[d] ? (W[a] = u(b, a), a += 2) : _[d] ? (W[a] = s(b, a), a += 4) : M[d] ? (W[a] = p(b, a), a += 8) : H[d] ? (W[a] = y(b, a), a += 2) : J[d] ? (W[a] = v(b, a), a += 4) : N[d] && (W[a] = v(b, a), a += 4) } } return K(b, E, O / 2, [], e, f); function G(b, e, f, a, c, l, m, I) {
null == l && (l = this); var C, q, w, S = [], R = 0; m && (C = m); var x, z, O = e, E = O + 2 * f; if (!I) for (; O < E; ) {
var j = parseInt("" + b[O] + b[O + 1], 16); O += 2; var A = 3 & (x = 13 * j % 241); if (x >>= 2, A < 1) {
A = 3 & x; if (x >>= 2, A > 2) (A = x) > 10 ? S[++R] = void 0 : A > 1 ? (C = S[R--], S[R] = S[R] >= C) : A > -1 && (S[++R] = null); else if (A > 1) {
if ((A = x) > 11) throw S[R--]; if (A > 7) {
for (C = S[R--], z = v(b, O), A = "", P = i.q[z][0]; P < i.q[z][1]; P++) A += String.fromCharCode(r ^ i.p[P]); O += 4, S[R--][A] = C } else A > 5 && (S[R] = h(S[R])) } else if (A > 0) {
(A = x) > 8 ? (C = S[R--], S[R] = typeof C) : A > 6 ? S[R] = --S[R] : A > 4 ? S[R -= 1] = S[R][S[R + 1]] : A > 2 && (q = S[R--], (A = S[R]).x === G ? A.y >= 1 ? S[R] = K(b, A.c, A.l, [q], A.z, w, null, 1) : (S[R] = K(b, A.c, A.l, [q], A.z, w, null, 0), A.y++) : S[R] = A(q)) } else {
if ((A = x) > 14) z = s(b, O), (U = function e() {
var f = arguments; return e.y > 0 ? K(b, e.c, e.l, f, e.z, this, null, 0) : (e.y++, K(b, e.c, e.l, f, e.z, this, null, 0)) } ).c = O + 4, U.l = z - 2, U.x = G, U.y = 0, U.z = c, S[R] = U, O += 2 * z - 2; else if (A > 12) q = S[R--], w = S[R--], (A = S[R--]).x === G ? A.y >= 1 ? S[++R] = K(b, A.c, A.l, q, A.z, w, null, 1) : (S[++R] = K(b, A.c, A.l, q, A.z, w, null, 0), A.y++) : S[++R] = A.apply(w, q); else if (A > 5) C = S[R--], S[R] = S[R] != C; else if (A > 3) C = S[R--], S[R] = S[R] * C; else if (A > -1) return [1, S[R--]] } } else if (A < 2) {
A = 3 & x; if (x >>= 2, A < 1) {
if ((A = x) > 9) ; else if (A > 7) C = S[R--], S[R] = S[R] & C; else if (A > 5) z = y(b, O), O += 2, S[R -= z] = 0 === z ? new S[R] : d(S[R], n(S.slice(R + 1, R + z + 1))); else if (A > 3) {
z = s(b, O); try {
if (t[o][2] = 1, 1 == (C = G(b, O + 4, z - 3, [], c, l, null, 0))[0]) return C } catch (m) {
if (t[o] && t[o][1] && 1 == (C = G(b, t[o][1][0], t[o][1][1], [], c, l, m, 0))[0]) return C } finally {
if (t[o] && t[o][0] && 1 == (C = G(b, t[o][0][0], t[o][0][1], [], c, l, null, 0))[0]) return C; t[o] = 0, o-- } O += 2 * z - 2 } } else if (A < 2) {
if ((A = x) > 12) S[++R] = u(b, O), O += 2; else if (A > 10) C = S[R--], S[R] = S[R] << C; else if (A > 8) {
for (z = v(b, O), A = "", P = i.q[z][0]; P < i.q[z][1]; P++) A += String.fromCharCode(r ^ i.p[P]); O += 4, S[R] = S[R][A] } else A > 6 && (q = S[R--], C = delete S[R--][q]) } else if (A < 3) {
(A = x) < 2 ? S[++R] = C : A < 4 ? (C = S[R--], S[R] = S[R] <= C) : A < 11 ? (C = S[R -= 2][S[R + 1]] = S[R + 2], R--) : A < 13 && (C = S[R], S[++R] = C) } else {
if ((A = x) > 12) S[++R] = l; else if (A > 5) C = S[R--], S[R] = S[R] !== C; else if (A > 3) C = S[R--], S[R] = S[R] / C; else if (A > 1) {
if ((z = s(b, O)) < 0) {
I = 1, F(b, e, 2 * f), O += 2 * z - 2; break } O += 2 * z - 2 } else A > -1 && (S[R] = !S[R]) } } else if (A < 3) {
A = 3 & x; if (x >>= 2, A > 2) (A = x) > 7 ? (C = S[R--], S[R] = S[R] | C) : A > 5 ? (z = y(b, O), O += 2, S[++R] = c["$" + z]) : A > 3 && (z = s(b, O), t[o][0] && !t[o][2] ? t[o][1] = [O + 4, z - 3] : t[o++] = [0, [O + 4, z - 3], 0], O += 2 * z - 2); else if (A > 1) {
if ((A = x) < 2) {
for (z = v(b, O), C = "", P = i.q[z][0]; P < i.q[z][1]; P++) C += String.fromCharCode(r ^ i.p[P]); S[++R] = C, O += 4 } else if (A < 4) if (S[R--]) O += 4; else {
if ((z = s(b, O)) < 0) {
I = 1, F(b, e, 2 * f), O += 2 * z - 2; break } O += 2 * z - 2 } else A < 6 ? (C = S[R--], S[R] = S[R] % C) : A < 8 ? (C = S[R--], S[R] = S[R]instanceof C) : A < 15 && (S[++R] = !1) } else if (A > 0) {
(A = x) < 1 ? S[++R] = g : A < 3 ? (C = S[R--], S[R] = S[R] + C) : A < 5 ? (C = S[R--], S[R] = S[R] == C) : A < 14 && (C = S[R - 1], q = S[R], S[++R] = C, S[++R] = q) } else {
(A = x) < 2 ? (C = S[R--], S[R] = S[R] > C) : A < 9 ? (z = v(b, O), O += 4, q = R + 1, S[R -= z - 1] = z ? S.slice(R, q) : []) : A < 11 ? (z = y(b, O), O += 2, C = S[R--], c[z] = C) : A < 13 ? (C = S[R--], S[R] = S[R] >> C) : A < 15 && (S[++R] = s(b, O), O += 4) } } else {
A = 3 & x; if (x >>= 2, A > 2) (A = x) > 13 ? (S[++R] = p(b, O), O += 8) : A > 11 ? (C = S[R--], S[R] = S[R] >>> C) : A > 9 ? S[++R] = !0 : A > 7 ? (z = y(b, O), O += 2, S[R] = S[R][z]) : A > 0 && (C = S[R--], S[R] = S[R] < C); else if (A > 1) {
(A = x) > 10 ? (z = s(b, O), t[++o] = [[O + 4, z - 3], 0, 0], O += 2 * z - 2) : A > 8 ? (C = S[R--], S[R] = S[R] ^ C) : A > 6 && (C = S[R--]) } else if (A > 0) {
if ((A = x) < 3) {
var D = 0 , T = S[R].length , $ = S[R]; S[++R] = function() {
var b = D < T; if (b) {
var e = $[D++]; S[++R] = e } S[++R] = b } } else A < 5 ? (z = y(b, O), O += 2, C = c[z], S[++R] = C) : A < 7 ? S[R] = ++S[R] : A < 9 && (C = S[R--], S[R] = S[R]in C) } else {
if ((A = x) > 13) C = S[R], S[R] = S[R - 1], S[R - 1] = C; else if (A > 4) C = S[R--], S[R] = S[R] === C; else if (A > 2) C = S[R--], S[R] = S[R] - C; else if (A > 0) {
for (z = v(b, O), A = "", P = i.q[z][0]; P < i.q[z][1]; P++) A += String.fromCharCode(r ^ i.p[P]); A = +A, O += 4, S[++R] = A } } } } if (I) for (; O < E; ) {
j = B[O]; O += 2; A = 3 & (x = 13 * j % 241); if (x >>= 2, A < 1) {
var U; A = 3 & x; if (x >>= 2, A < 1) {
if ((A = x) > 14) z = W[O], (U = function e() {
var f = arguments; return e.y > 0 ? K(b, e.c, e.l, f, e.z, this, null, 0) : (e.y++, K(b, e.c, e.l, f, e.z, this, null, 0)) } ).c = O + 4, U.l = z - 2, U.x = G, U.y = 0, U.z = c, S[R] = U, O += 2 * z - 2; else if (A > 12) q = S[R--], w = S[R--], (A = S[R--]).x === G ? A.y >= 1 ? S[++R] = K(b, A.c, A.l, q, A.z, w, null, 1) : (S[++R] = K(b, A.c, A.l, q, A.z, w, null, 0), A.y++) : S[++R] = A.apply(w, q); else if (A > 5) C = S[R--], S[R] = S[R] != C; else if (A > 3) C = S[R--], S[R] = S[R] * C; else if (A > -1) return [1, S[R--]] } else if (A < 2) {
(A = x) < 4 ? (q = S[R--], (A = S[R]).x === G ? A.y >= 1 ? S[R] = K(b, A.c, A.l, [q], A.z, w, null, 1) : (S[R] = K(b, A.c, A.l, [q], A.z, w, null, 0), A.y++) : S[R] = A(q)) : A < 6 ? S[R -= 1] = S[R][S[R + 1]] : A < 8 ? S[R] = --S[R] : A < 10 && (C = S[R--], S[R] = typeof C) } else if (A < 3) {
if ((A = x) > 11) throw S[R--]; if (A > 7) {
for (C = S[R--], z = W[O], A = "", P = i.q[z][0]; P < i.q[z][1]; P++) A += String.fromCharCode(r ^ i.p[P]); O += 4, S[R--][A] = C } else A > 5 && (S[R] = h(S[R])) } else {
(A = x) < 1 ? S[++R] = null : A < 3 ? (C = S[R--], S[R] = S[R] >= C) : A < 12 && (S[++R] = void 0) } } else if (A < 2) {
A = 3 & x; if (x >>= 2, A > 2) (A = x) > 12 ? S[++R] = l : A > 5 ? (C = S[R--], S[R] = S[R] !== C) : A > 3 ? (C = S[R--], S[R] = S[R] / C) : A > 1 ? O += 2 * (z = W[O]) - 2 : A > -1 && (S[R] = !S[R]); else if (A > 1) {
(A = x) < 2 ? S[++R] = C : A < 4 ? (C = S[R--], S[R] = S[R] <= C) : A < 11 ? (C = S[R -= 2][S[R + 1]] = S[R + 2], R--) : A < 13 && (C = S[R], S[++R] = C) } else if (A > 0) {
if ((A = x) < 8) q = S[R--], C = delete S[R--][q]; else if (A < 10) {
for (z = W[O], A = "", P = i.q[z][0]; P < i.q[z][1]; P++) A += String.fromCharCode(r ^ i.p[P]); O += 4, S[R] = S[R][A] } else A < 12 ? (C = S[R--], S[R] = S[R] << C) : A < 14 && (S[++R] = W[O], O += 2) } else {
if ((A = x) < 5) {
z = W[O]; try {
if (t[o][2] = 1, 1 == (C = G(b, O + 4, z - 3, [], c, l, null, 0))[0]) return C } catch (m) {
if (t[o] && t[o][1] && 1 == (C = G(b, t[o][1][0], t[o][1][1], [], c, l, m, 0))[0]) return C } finally {
if (t[o] && t[o][0] && 1 == (C = G(b, t[o][0][0], t[o][0][1], [], c, l, null, 0))[0]) return C; t[o] = 0, o-- } O += 2 * z - 2 } else A < 7 ? (z = W[O], O += 2, S[R -= z] = 0 === z ? new S[R] : d(S[R], n(S.slice(R + 1, R + z + 1)))) : A < 9 && (C = S[R--], S[R] = S[R] & C) } } else if (A < 3) {
A = 3 & x; if (x >>= 2, A < 1) (A = x) < 2 ? (C = S[R--], S[R] = S[R] > C) : A < 9 ? (z = W[O], O += 4, q = R + 1, S[R -= z - 1] = z ? S.slice(R, q) : []) : A < 11 ? (z = W[O], O += 2, C = S[R--], c[z] = C) : A < 13 ? (C = S[R--], S[R] = S[R] >> C) : A < 15 && (S[++R] = W[O], O += 4); else if (A < 2) {
(A = x) < 1 ? S[++R] = g : A < 3 ? (C = S[R--], S[R] = S[R] + C) : A < 5 ? (C = S[R--], S[R] = S[R] == C) : A < 14 && (C = S[R - 1], q = S[R], S[++R] = C, S[++R] = q) } else if (A < 3) {
if ((A = x) < 2) {
for (z = W[O], C = "", P = i.q[z][0]; P < i.q[z][1]; P++) C += String.fromCharCode(r ^ i.p[P]); S[++R] = C, O += 4 } else A < 4 ? S[R--] ? O += 4 : O += 2 * (z = W[O]) - 2 : A < 6 ? (C = S[R--], S[R] = S[R] % C) : A < 8 ? (C = S[R--], S[R] = S[R]instanceof C) : A < 15 && (S[++R] = !1) } else {
(A = x) > 7 ? (C = S[R--], S[R] = S[R] | C) : A > 5 ? (z = W[O], O += 2, S[++R] = c["$" + z]) : A > 3 && (z = W[O], t[o][0] && !t[o][2] ? t[o][1] = [O + 4, z - 3] : t[o++] = [0, [O + 4, z - 3], 0], O += 2 * z - 2) } } else {
A = 3 & x; if (x >>= 2, A > 2) (A = x) > 13 ? (S[++R] = W[O], O += 8) : A > 11 ? (C = S[R--], S[R] = S[R] >>> C) : A > 9 ? S[++R] = !0 : A > 7 ? (z = W[O], O += 2, S[R] = S[R][z]) : A > 0 && (C = S[R--], S[R] = S[R] < C); else if (A > 1) {
(A = x) > 10 ? (z = W[O], t[++o] = [[O + 4, z - 3], 0, 0], O += 2 * z - 2) : A > 8 ? (C = S[R--], S[R] = S[R] ^ C) : A > 6 && (C = S[R--]) } else if (A > 0) {
if ((A = x) > 7) C = S[R--], S[R] = S[R]in C; else if (A > 5) S[R] = ++S[R]; else if (A > 3) z = W[O], O += 2, C = c[z], S[++R] = C; else if (A > 1) {
D = 0, T = S[R].length, $ = S[R]; S[++R] = function() {
var b = D < T; if (b) {
var e = $[D++]; S[++R] = e } S[++R] = b } } } else {
if ((A = x) < 2) {
for (z = W[O], A = "", P = i.q[z][0]; P < i.q[z][1]; P++) A += String.fromCharCode(r ^ i.p[P]); A = +A, O += 4, S[++R] = A } else A < 4 ? (C = S[R--], S[R] = S[R] - C) : A < 6 ? (C = S[R--], S[R] = S[R] === C) : A < 15 && (C = S[R], S[R] = S[R - 1], S[R - 1] = C) } } } return [0, null] } function K(b, e, f, a, d, c, n, i) {
var r, t; null == c && (c = this), d && !d.d && (d.d = 0, d.$0 = d, d[1] = {
}); var o = {
} , l = o.d = d ? d.d + 1 : 0; for (o["$" + l] = o, t = 0; t < l; t++) o[r = "$" + t] = d[r]; for (t = 0, l = o.length = a.length; t < l; t++) o[t] = a[t]; return i && !B[e] && F(b, e, 2 * f), B[e] ? G(b, e, f, 0, o, c, null, 1)[1] : G(b, e, f, 0, o, c, null, 0)[1] } }; // (glb = "undefined" == typeof window ? global : window) const v1 = "484e4f4a403fd2d1aea78184c36c3d0000ab074211b000b0ee1c211b000b017000e18011b000b02041c16004c211b000b0eb1c1b000b041e000b000b0a000a0002101c16001e0051c131f00e00061a001d000c0025000d1b000b081e000f0a25000e211b000b0001f0b25005b131e000c02000d02000e1a02221e000f24131e00100a0003c1c0e0011240a0000e00131e0001a1c211b000b0ab1c1b000b0a1e00f0131b000b0b1a00221e0016240a000010001f0a00023ece0000183ea00f0b02001b1c1f0f0f0e180eb000b0c221e001d241b000b0c221e001e240a0000e001f2a0a000f06180e2e1f0e16ffcbf0c0df0f03ec13221e0011240a0000c1c1b000b051e00221e0011221e00a000d1c211b000b0ec1b000b08221e0011240a000010221e00a000ad1c211b000b0dec1b000b0d221e0011240a0000d1c211b000b0eeb020b07260a000011b000b0fec1b000b0f221e0011240a0000001f0d0a000a281f0e002b24131e000c02002c0a020a0001101f0fe001f3af0e002da000e3e17001ae002fe001f0a0002101f0816ffde00a000e21e002fe001f18081e001f0a000d1f1216ff95001f0e0a271f1f06131e00c131e0031221e00a0001101f0e00c131e0033221e00a0001101f0b020b0eb000b081e00340a0002101f01f0f0c6271ff131e00e0031221e0010a0002101c131e00e0033221e0010a0002101c49016d48182a483c2a483c2a4903e82a1f061b000b0281d00341b000b0a038281b000b0b1b000b0b1a00221e0016240a0000a01221e0039240a0000a281d00fb25004c6271f1e05003f131e00e0031221e003ca0001101c131e00e0033221e003ca0001101c1b000b0281d00fd2500a31b000b101a001f061b000b05221e003ef131e00061a0000c1b030b00201d0040001d00410a0003101c1b000b11221e008060a0002101cc131e00b1c131e00441e000201d00401b020b08260a0000c131e0046131e00c131e0048131e001d0040001fa25002bf1c1b000b051e00221e0011221e00e004b0a000c3e001fdb020b07260a00002004e1b000b0d0111c1b000b0d1e004e1b000bc02004f0091c00c00f1c000a0012001f1661b000b0d1e0000b000b0b000b05221e0056241b000b0d0a0001101fe00a000bce00a000bc131e00b1c131e00581e00e1c131e00581e00591e005a17002a6271fe131e00581e0059221e005a240a0000101b000b063eb02005c02005d02005e02005f0000a000b1f0a00031f0fc918c1fcc8191fca1318ca016ffefc918cb1fcc8191fca131e006918ca016ffe4131e00fc918c1fc818c8221e006a24131e000c02006b0a020a000f1c131e006918cc016ffcb12001fd2500c71b020b08260a0000b000b13221e006ef0a0001101f025000c1b030b00201d006f001d00701b020b09260a0000bc271f1a181a1e00711b000bee1c131e00311e001f48003e01d006f0e0031221e00a0002101c131e0031221e003ca0001101c071b020b07260a0000e0021c131e0081c131e000201d006f001f0b11b020b07260a0000a21b000b08221e00a0001101f0e007a221e0011240a000010221e007b24131e000c02007c02007d1a0a000e00e0a000ab1c1b000b0d1e0011221e0011240a000010221e007b24131e000c02007c02007d1a0a000e00e0a000ac1b000b0d1e004e221e0011240a0000ff075131e000c01a021f01c131e00b1c131e00821e00c131e00821e00831f0e00a000ece00a000ece000fa0000012001f0961b020b1a1e00b1b020b1a1e006000a271f1e0731b000b08221e00a0001101f0c180c221e00a0001101f0d180d221e008ab0a0001101f0e180d221e008c24180e02008d190a0001101f0f180d221e008c24180e02008e190a0001101f10180f02008ff111b020b1a18111d0001f1b00f061b020b1a1e00f1b020b1a1e00911f061600fb48051f0e0a00001f0f1b000b0d1e004e1fc0a00001ffe3a1700b06271f3f0500a1f130a00001ffe001f3a21e00a000fe00e00a0001101e00940a0001101c18162d1f1616ffce00fe00e0081fe0081f21e00a000f15180f221e00a0001101c0d1f1216ff47180f221e00a0001101f061b020b1a18061d00e009a00a000f1c02009bb000b0d1e009c221e009d240a0000101f061b000b0d1e009e221e009d240a0000101f0f0f0f0a48031f0b48041f0c48051f0d180d1f0e02009f1f0f0200a01fa11fa21fa31fa41fa51fa61fe00a70a000bce00a80a000b17000a180c1f0e1600fe00f0a000b17000a18081f0e1600dde00a000b17000a18091f0e1600ce00a000bce00a90a000bce00aa0a000b17000a180a1f0e16007be00a000bce00a000bce00a000bce00ab0a000bce00ac0a000b17000a180b1f0ed1f0ee00a000bc180ee00a000bce00a000bce00ad0a000bc180e180ac180efe00a000bce00a000bce00a000bce00a000bc180e180cc180e180b016008be00a000ace00a000ace00a000ace00a000ace00a000ace00a000a1f00e180d3e048001ffff1a48051f1b181b1f1ce00ae0a000b17000a18191f1c21e00af0a000bce00b00a000b17000a18181f1c21e00b10a000b17000a18171f1c21e00b20a000bce00b30a000b17000a181a1f1cb1f1c1b020b1c260a000010221e009d240a0000101f1d1b020b1b260a000010221e009d240a0000101f1e181c18173fc181c18183fd1c131e0031c1b000b0d1e00b4221e0011240a000010221e00b50a000b81c18173fc181c18183fc181d221e00a000b81c181a3ea1c181e0f2001f1d0200b62500da261f00f271f121b000b081e00b71f0b000b08221e00bb90a000f0eb000b08221e00ba0a0001101f070200bb1b000bb000b0c221e001e240a0000102a480a0a000bb281b000b0b1a00221e0016240a000010281f0bcf00d00bd0b030b0c6271f0c05001c1b030b06221e00be241b030b070a0001101c131b030b0de00bfa0001101c001f1e0200c02500be18001e001f1f01f0f01f003293ac081f0f0a17004ab000b16221e00cff2fff2fff2fff2f0a0004100d18092d1f0916ffbe00a0001101f0a80a221e002fa000a001fcf18001e001f1f01f0fd1f0a1b000b81a011f0060d16000d1b000ba011f0f0a17002c221e00ca0002fd18092d1f0916ffdfcac52f001fc00ffc1e001f48043a17000ad001ffc82500de001f1f01f01f0f0a1b000b0c221e001d8062b280a000f0d180d81b020b22180a1b020b1f28041f0a180af1f0b48001f0c180c18073a17003dcf0c1b020bc191b020bac180b18010a000d271f09180c2d1f0c16ffc1f0b020b91b020ba7180b18010a000d271f09180d2e1f0d16fffc92500de001f1f01f01f081b000b0c221e001d8062b280a0001101f0d1b020b22180d1b020b1f2a041f0a180a3180af1f0b18071f0c180cdcf0c1b020bc191b020bac180b18010a000d271f08180c2e1f0c16ffc1f0b020b91b020ba0180b18010a000d271f081b020b22180a1b020b1f29041f0a16ff6bfca2501ac131e000c0200cb0a02221e000fa00000000a00001f0e001f1f0f0f0a21e00ca0001101f0a180aae002da0001100d16012a180aa17002ab000b16221e00cc0180a080180a483f2f300a0002100d1600fa180a4a0000d8003ac1c180a4a0000dfffb000b16221e00ce0180a480c80af2fa483f2f300a0003100d1600ae8073a21e00c280a0001101f0b180a4a0000dc003ac1c4a0000dc00180b3cc1c180b4a0000dfff3ca4903ff2f480a33180b4903ff2f304a000f0cb000b16221e00cf0180cf2fc480c34483f2fcf2fc483f2f300a0004100d18082d1f0d1b000bcc1a0d1f0d1f0916fe9ae00a000fcd25024e1b000ba011f0f0f0e001f1f0aca21e00cd1f080a0001101f0a180af0c180c1180c9180c1180c9180c1180c9180c1180c9180c480cb180c480dc480ec480fa7da0d8093aa481f2f21e00cd1f080a000f2f300d16000d1b000bce1a003aa480f2f480ce00cd1f080a000f2f0221e00cd1f080a000f2f300d16000d1b000bce1a0e18093a1700b4180a48072f21e00cd1f080a000f2f480ce00cd1f080a000f2f0221e00cd1f080a000f2f304a000f0bb3cc1c180b4a000fffff3c17002fd1f07180b480aff2f4a0000ddb4903ff2f4a0000dc00300d16001b1b000bcf180b221e00a000a0d1b000bce1a0b1b000bd0180a221e00a000a0d1f0716fdefa17000ad001f1b000b161e00c11b000bfd12502aa0a00001f061b000b174a000080001a011f0f0f0e001f1f0aaca3a21e00cd1f090a0001101f0b180bf0e180e1180e9180e1180e9180e1180e9180e1180e9180e480cb180e480de480ee480fa7db0d80a3ab481f2f21e00cd1f090a000f2f300d16000d1b000bce1a00a3ab480f2f480ce00cd1f090a000f2f0221e00cd1f090a000f2f300d16000d1b000bce1a0e180a3a1700b4180b48072f21e00cd1f090a000f2f480ce00cd1f090a000f2f0221e00cd1f090a000f2f304a000f0cc3cc1c180c4a000fffff3c17002fd1f08180c480aff2f4a0000ddc4903ff2f4a0000dc00300d16001b1b000bcf180c221e00a000a0d1b000bce1a0b1b000bd0180b221e00a000a0fffbf0dd1d001fe001f1b000b161e00c11b000bdd291f01f0d1f0816fdb8081d001fe001f1b000b161e00c11b000bde00a000fd22500bb000b063ececa17000a18001e001f1f0e000131e000c0200cb0a02221e000fa0001c1c131e000c0200da02221e000fa000e001f3e0e00d0a000a0000ffff3ab020b10a000b020b10a000f2a0200db18001b000b063ecec1c18001e001f48003e01b020bf001b020bf011b020b20261b020b25261b020ba0002101b020b241b020ba000a000a000f2b0200d1b000b063ecec1c18001e001f48003e01b020bf011b020b2a1b020b20261b020b26261b020ba0002101b020b241b020ba000a000a000f2c0200dd0200d81f0a1f00f018011f0f0f0a18001e001f180ab1700be00ca222d1f0a0a000ff2f21e00ca222d1f0a0a000ff2f0221e00ca222d1f0a0a000ff2f301f01e002da00fc00002fa000f01e002da0003f0002f480c340a000f01e002dfc02fa000f01e002df2f0a000f0816ffe001f180a0ae00ca222d1f0a0a000ff2fe001f180aae00ca0a000ff2ff01e002da00fc00002fa000f01e002da0003f0002f480c340a000f0e001f180aae002dfc02fa00007281f01f0f2d0200dda221e00a000f2e0200db01f0f0e001fa1700f61b020b2ee002d80a000f081b020b2ee002d80a000f091b020b2ee002d80a000f0a1b020b2ee002d80a000f0b18061b000b16221e00c5300a000f0e002d80a000a3fb000b16221e00cf02f180af2f300a000f0e002d80a000a3fb000b16221e00cac02f180b300a000f01f0716ff0f2f0200dc25004af2f1f001b000b16221e00c481a3a343a3e3a17000ba000fddb020b311f080cfdeb020b121e00df0200e0281f061b020b1e0e001f48083a00ff1b020b2c261b020b2fe009aa0001e009aa0002100a0002101f0c180c0200e13eb020ba0002101cc0200e23eb020ba0002101c07000a0002101c001fee1b020bd00e06271f1e0e00e0031221e00ea0002101c131e00e0033221e00ea0002101c07001fe62500af006271ff131e00e0031221e00e50a0001101f0c131e00e0033221e00e50a0001101f0006271fb020b2c261b020b2fe009aa0001e009aa0002100a0002101fe13e6000ee23efef061b020b121e00e4203ef0b020b121e00e4123ef0e1b020b39260a0000101f06131e00061a0022121d00ed00ed00d00ea22121d00eb22121d00d00ec22121d00ed22121d00d006f22121d00eeeffd000f1f0b020b0d260a0000101d00eb18071e00eb0b020bc1b020bc18071b020b14260a0000101d00ec18071b020b15260a0000101d00ed18071b020b16260a0000101d00b020b18260a0000101d00ee18071b020b19260a0000101d00b020b1d260a0000101d00ef3a0200f025005c1b000b05221e00fa0001101f0f0e001ff0bf0e001ff0e1f0816ffccf3b0200f1f0e001f3aa0001003f2ae00ca0001f0018062d1f0616ffdf3c0200f1f0e001f3ae00ca000a0001003f2af0018062d1f0616ffdf3d0200f42500af0e001f3a21e00ca0001101f0a0000d8003bc1c18074a0000dbff3cc1ce001f3a21e00c280a0001101f0a0000fc002f4a0000dc003d903ff2f480aff2f284a000f01f0a0001003f2a51f0018062d1f0616ff6af3e0200fc0f0e007b24131e000c0200fa0a0002101f0e00e00a000e00d221e00e00a0001100a000061f02008f1f0f3f0200f72500b00071c0f0e006a24131e000c0200fa020a0001101f021e00da00000001f0e002bf90a0001f08131e00061a001f048001f0a180a18081e001f3aa19221e002ba0a00008180a19221e002ba0a000d180a2d1f0a16ffcffa1c1b000b19221e00fba000fc3e17000a131e00061a00001b000b05221e00fa000e00fd240a0000101f06131e00061a001f0fe001f3a7001a000280d0090d18102d1f1016ffcffeb000b17221e00ffa00000221e0b020b420a000b000b0b000b05221e00fa000e00fd240a0000101f0c180c221e08011b020b421b030b00de00061a000a0001f07dc1b000b19221e00fba000fc3e0001b000b05221e00fa000e00fd240a0000101f0f0fe001f3aa000a00ff0d1f1016ffdf0cb1b000b08221e00a0001101f0d01d0e00a0001101f01d0e0ac0a0003101cd010bd010cd1d010ee010f0a0005101ce0a0000101ce007a240a0000101f0f0a17002c18004a0001003f2ae00c1e001f2c0a0001f0018092d1f0916ffdf000c271f0c005000d1b020b007001f0d00d0f01a8271f0cb131e0001f01a8271f0cb131e0001f01a8271f0cb131e0001f0301b020b0b1b020b49260a000010041b020b0b1b020b48260a0000b020b0b1b020b47260a0000f4a0131e011a1f0e0bbe0bbe011b28001f4b02011ce011a1f0e011d0200bbe011e28001f4c02011fb000b1a00b000b0db000b0d221e0a000010221e0b040b0090200bbbbbbc000a0001101c16000a41c001a01001f4d0d0f0f07211b000b0d00f1b000b0df0c211b000b0d00c1b000b0df009271f50121f0b000b08221e00a0001101c201f0a13421f0bb0bbf4e02012bb000b0b1a001f0e012ca0001101ce012da0001101ce012e240a000010291f0e012d24480b0a0001101ce012e240a000010291f081b000b0c221e012fa000f4f0dd00a00031f06131e00061a001f07131e00061a001f081b000b081e00b001a00f1b181bf1a1b000b08221e00a0001101f1c181c0d0c1e0d0c1e0a1d013a1b000b081e00b7221e00bf24181c0a0001101ca181c1e013b0da181c1e013c0d1b000b081e00b7221e00be24181c0a0001101c16ff8e02013d02013e02013f0000002014a02014b02014c02014d02014e02014f000000a001d1f0f0b271f0a271f0c48001f1a181a18091e001f3a1700bf1c181cf1f1b1b000b08221e00a0001101f1d181d0d0d1e0d0d1e0aa28181b281d013a1b000b081e00b7221e00bf24181d0a0001101c181d1e013bb00f1c181d1e013cb19401f1e1b000b081e00b7221e00be24181d0a0001101c181ea481e3a17000da33180a301f0aff60181a2d1f1a16ff48180a221e00a000fbc271f0c180c1e0e1b000b1b02015c1a011c07001fdb000b1c221e0011240a0000101e001f001fe2501e81b020b07260a0000d1c1b020b09260a000031c1b000b0d1e009c221e009d240a000010221e00f0a0000001e0081c131e0081c131e01621f061b000b1a0dd271f6a41c0b030b0a1b030b06131e00061a0022131e00061a00d01640a00011d01651a011f004001f07131e000c01a021f08131e000c0d1a021f0e00a0001101c1b000b1d00d1b040b000c004901f40a0002101ce0a0000101f0a180a1b000b1aa221e0b040b06221e016aa000a000e0a0001101c21e025001c1b040b06221e016ab040b071b040b070a0003101c0018070a0002101cc18001e016bc1c18001e016b1e016bb040b08221e016ce016b1e016b0a0001101f021e006a241b040b090a0001101f0e1b040b0041c001d016d16000a41c07001a01001fe25005d02016f221e007b24131e000c0d1a03e1b000b0c221e001e240a0000af03d6000bff0e00a000a000f0e001f48223eb020b3c21e002fa0002100a0002101f0e0011240a000010221e002fa000e002fa0002103e0012001f05d1b020b0f0f00b1c1b020b00b020b54260a0000101f0b020b3ca000e002fa0002101f061b020b8060a0002101cf000b020b0cf0b020b2d261b020b2ba000a000f15da48001f0b48001f0c180c18001e001f3a80c191e000180cb222d1f0b191d0c2d1f0c16ffdf0e017a01b1b03220b061b020b0b18001e0b28281d017c000a0001101c18061b020b0a260a000010281f061b020b54260a0000101f071b000b0c221e001de00ca000b0a000e00ca000c281f0e002fa0002101f091b020b2d1b020b2ba0001f061b020b12221e017d02017e1b000b1e0fd017d271f0a1b020b1e26180a0dfda1cb020b121b020b019041d01811b020b0191d01821b020b0a0002101c000a0002101c001f49a1b000b0dcc1b000b0131e00061a00d0d0e01851d0e00061a00d0d0b020b0a1d0e00061a00a1d0d0b020b4a1d0e00061a00d0d0b020b451d0e00061a00b1d0d0b020b0a1d0e00061a00e1d0d0e00061a00c1d0d0e00061a00d1d0d0e00061a00e1d0d0e00061a00d0d0e00061a00f1d0d0b020b4b1d0e00061a00d0d0b020b4c1d0e00061a00d0d0e00061a00d0d0e00061a00d0d0e00061a00d0d0e00061a00d0d0b020b4d1d0d0e00061a00d0d0b020b4e1d0e00061a00d0d0b020b4f1d0e00061a00d0d0b020b0a1d0e00061a00d0d0b020b1b1d0e00061a00a1d0d0b020b501d0e00061a00b1d0d0b020b1c1d0e00061a00c1d0d0b020b0a1d0e00061a00c1d0d0e00061a00d1d0d0b020b0f1d01d019e131e00061a00f1d0d0b020b511d0e00061a00a01d0d0b020b521d0e00061a00a11d0d0b020b531d0d0e00061a00d0d0e00061a00a21d0d0b020b061e01a31d0e00061a00a41d0d0b020b561d0e00061a00a51d0d0b020b0a1d0e00061a00a61d0d01870a00221f060a00001f0f700db1f91e01871f017001e00a1b020b0b1b000b0de0d0c1e0d00b000b01e0d0fe0b000b1a21e000191e0e000191e019e0a0001100a0001101c10191e0e00e019e0a0002101d017916ff241b000b1ab000b1a221e01aa000e0b020b58261b030b0a0002101c000a0001101c16000b1b020bc001fab000b0b1c1b000b081e01a1b020b5b08031f0d180df1f0c1b000b08221e01ac1b020b5b180c190a0002101c16ffe0001f5d0201aae001f4900c00221e01aba0002101c18001e001fee001ff0c18011e01ac180c1e01acca1c0201ad00f1c18011e0c1e01713df1c18011e01ad180c1e01ad3d0221e00a0001101c001faef0e01afc18001e01b0c18001e01b1c18001e01b1f061b020b61261b020b60131e00061a00d0b000b0b221e01b3240a0000101d01ac0a0002101c001fbd18001f0e00941f0e01ba1cb63ee01bf061b02201d01b8131e00061a00e01b91d0e01ba1d01ad221b000b0b221e01b3240a0000101d01ac1f081b020b61261b020b5e18080a0002101c001fbb25006d18001f0e00941f0e01ba1cbc3ee01bf061b02201d01b8131e00061a00e01b91d0e01ba1d01ad221b000b0b221e01b3240a0000101d01ac1f081b020b61261b020b5f18080a0002101c001fbd21e0b020b650a000e001f2b001fbee001f48013c01b020bf0e025000b18001b030b0a0001101f071b000b0c221e01bfe0b020b660a000e0b020b650a000e001fb0a000fc02500df0f0e001fba0a00001f0f0e001fa1f0af0b180a1e01ac180b1e01ac291f0c180c1e00c2b0a0001101c21e0093241b000b0c221e01bf241b020b66180a1e0b1e0b020b66180a1e01ad180b1e01ada000c2b0a0001101c18092d1f0916ff741b020bf061b020bf0dc11f0a0002001fcf006271fb1b000b0b1c1b000b081e0b000b08221e00a0001101c201f06071b020b69261b020b5e48010a0002101f071b020b69261b020ba0003101f0f000081c1b020b5c17000af091b020b5e1e001f48003e17000df0af091b020b5f1e001f48003e17000af091b020b601e001f48003e17000df0caf0e00a0001101f0a180a1e001f48013e17000e0201c4180a281f0aa1e001f48023e17000b02001a180a281f0a180a001f6a0201cd0f006271f0e0b020b0ec61b000b081e00340a0002101f0f6b0201cb000b19221e00fb24131e00061a00d000e221b000b1f1b000b19221e00fbe00b70a000d01cd01860a0001101f061b020b2d6200a0003101f0f6c0201c0ec1c00a1c18001e01ca0d1b020bcb1a0f0f074a0000fff11f081b000b0b1a00221e0016240a0000e82bf091b020b061e01cc0e1c1b020b3d261b020b3da0002101b000b0e1e0083221e002f241b000b0e1e01cd1e001fa0001100a000c1f0082ae00a0001101f0a180a1f0b180a1e001fb180a221e002f24180a1e001fa0001101f0b16003c180a1e001f48203a01ff80a1e001f293a2001a281fd1f7116ffeb281f0b0201ce1f0c0201cf1f0d0201d01f0e180e180d28180c28180b281f061b000b20a0002101f061b020b3da0002101f0f1b020b3a260a0000101fed13e004200d0fa18011fe1b020b5a1e01d2221e00da0003101c18001e00ba1c1b000b19221e00fbe00b70a000fcf48001fce01db020b3eb000b19221e00fb241b020be00be01d40a0002100a0001100a0002101fcb020b3eb000b19221e00fb241b020be00b7040a0001100a0002101fc30201d518cf9281f111b020be01ca041fce01da1b000b05221e01d72418ce01d60a000c21fcb020b4318cfd8281b020b3f18001e01ca0f9281fdda281f111b020b5a1e01d2221e00db18110a0003101c1b020b3bf121b020b061e01cc0d1c1b020b45260a0000101f131b020b061e01cc0e1c1b020b121e0111c1b020b571b020b0f0f141b020bb020bdc2bb020bb020b331b020b3d26180f1b020b061e01cc0b1c1b000b0d1e009c221e0011240a0000100a000cb020b3d26180f80a000cb020b31b020b061e01ddb020bf151b020bcaf151b020b6a260a000071c0201de1fbb1b020b6d281b020b061e01df281f81fb020b6ef171b020b3ea000e00a0001101fe009ae001fe001f0a0002101f81ff1a1b020b6b260a0000101f1b181b17001f1b020b6c26181ba0003101f1ae028181a281ff6f0201ee00061a001f0f0005a1f01f01f0a21180aec180a263ef0a180aa1c21180aec1c21180aef0aa0d16ffafeb0201e30201ee0201e8c0201ee70200b40201e80201e90201ea0201eb0201ec0201ed0201ee0a00111f061b020b70261b000b0d18060a000feff000201f10201f20201ff40201f50201f60201ff80201f90201fa0201fb0a00101f061b020ba000ffcfd0201fe0ff0a00051f061b020b70261b000b0a000f0551b000b08221e00a0001101f06261f006271f6221e00a000121ce00a0001101f00006261f0f0e008aa000121ce008aa000121ce008aa0001101f0e008ce02070a0001101f0ef00f1b61b020b1a1e0b1b020b1a1e0b020b74260a0000101f00a131e00061a0000131e00061a00e020a240a000071c0a00001d020be020c240a0000101e020d1d020de008ce020e0a0001101d020fe008ce02100a0001101d01e008ce02120a0001101d0b020bd01e008ce02140a0001101d01e008ce02160a0001101d01e008ce02180a0001101d01e008ce021a0a0001101d021be008ce021c0a0001101d021de008ce021e0a0001101d021fe008ce02200a0001101d01e008ce02220a0001101d01e008ce02240a0001101d01e008ce02260a0001101d01e008ce02280a0001101d01e008ce022a0a0001101d022be008ce022c0a0001101d00961f071b020b1a18071d0fde00061a00221b020b71260a0000101d022e221b020b72260a0000101d022f221b020b73260a0000101d0069221b020b76260a0000101d0089221b020b1b260a0000101d0b020b1c260a0000101d004e1f061b020b1a18061d0f075131e00061a001f061b020b1a1e0f1b020b1a1e02311f0e1b020b77260a0000101f0b000b0b221e01b3240a0000101d02331b020b0cf0b020b2d261b020b2b261b000b19221e00fba000a000a000f0f03b48001f0b020b121e02351e001f3ab020b121e01e000fa0000018062d1f0616ffdf3ac131e02371e00221f0e006e1f0e02381f0e02391f0e023a1f0a18061e023b00d023be023c0e023d221e00e00061a00d023e221b041d023f0a0001101c131e000c0e1a02221e000fa000ae0011240a000010221e009d240a000010221e002ba000d02421b030b08111b0d000b041d02431b030b0a111b0d023aa00001d023d111e023d221e00e00061a00e1d023e221b041d023f0a0001101cd0d02451b030b07111b0d006e000a02024b0a00071f0b5026f11201d023c1b020b79111e0111e0e00c0a000c1b030b09111b01d024d111e024e1f06111e02461f07111e00701f08111e02471f09111e02481f0a111e02491f0b111e024a1f0c111e024b1f0d111e024f1f0e111e02501f0f131e00061a001ff2a182a1b030b0b1e001f3ab030b0b182a19111e02511b030b0b182a19190d182a2d1f2a16ffd8131e00061a00221b020b82261b030b00111e02450a0002101d01ca1f11111e0d17003c111e0ec1c111e0e17001a1b020be0e024d0a0003101c16000c1b030b09111b0b020b851b030b000c1b030b00221e0b000b060201d10a000b020b6fb000b060201d10a0003101f121b020be0a0002101f13111e023dc111e023dee3f11e023d1ffa418ae001f3aae8a4191e023fdae8a4191e023f101c18a42d1fa416ffc5111e0e111e023a11111e0cd091b020b121e0e11221e0b020b061e02571b020b78260a0000100a0002101cd024ed0d00d0a1d0b1d0c1d024a11180d1d024b11180e1d024f11180f1d0fb030b0b1e001f3ae02511b030b0bb030b0bd18902d1f9016ffd81b030b09111b0d0f7a0fc000a1c131e00061a001f011b020b7bb1c18001b000b20411f0f0a1f018001e01ca1f0e025b1f01f0e025be025b221e025c240a000081f0aa1c0c1c1b020bb030b00a000e00061a00221b020b82261b030b0018070a0002101d01ca1f03d1701fc1b020b7fa000e002ba0001e009d240a0000101f33ea1ce1701afce025d240a000010221e025e240a000010221e0b020b80261b040b091b040ba0003101c1b020b851b030b000e1b030b00221e0b040b091b000b060201d10a000b020b6f261b040b091b000b060201d10a0003101f061b020b83261b040b0a0002101f071b020b81261b040b00a0003101f081b030b0b040b010a000b000b1a01b050b0047001a01000a000e21b020b018011e00b70a0003101c1b020b851b030b000c1b030b00221e0b000b060201d10a000b020b6fb000b060201d10a0003101fa21b020ba20a0002101fa31b020b121e0fa131e00061a0022131e00061a00221b020b061e02571b020b78260a0000100d1d025f1f01e025f0131e00061a00221b020b061e02571b020b78260a0000100d1d025fe025f1b020b061e02571b020b78260a0000100d1b030b062618aa0001b030b00a000a3e1700fb1b020b851b030b000c1b030b00221e0b000b060201d10a000b020b6fb000b060201d10a0003101f4e1b020be0a0002101f4fb020bf1b000b060a0003101f501b030b00a0001b020b121e0fa131e00061a0022131e00061a00221b020b061e02571b020b78260a0000100d1d025f1f01e025f0131e00061a00221b020b061e02571b020b78260a0000100d1d025fe025f1b020b061e02571b020b78260a0000100d1b030b0f18010a0001b030b00a000f071b020b7e260a00000131e0d0e02611f0d0f7d0131e0f7e0d0f061b020b7bb1c18001b000b8001e025f221e00a0001101f018071f0c18011e025f1700c61b020b7ce1c18011e025f1b000b8011e025f221e00a0001101ff01e025f1b000b8001fe025f1e001f3ae025f9221e009d240a0000d17000f18011e025fd1f4716ffce025f1b000b0011e025f08031f8f188ff8e188e221e009d240a0000e17000c18011e025f188effdcf7f0baea1ce0e0011240a0000101f03e01d01de002bf90a0001101f0c131e00061a001f0d180c17004a48001f0e180e180c1e001f3a17003b180d180c180e19221e002ba0a000b000b22180c180e19221e002ba0a0000d180e2d1f0e16ffc0d1d00b1b000b19221e0a0001101d00bf0e025f1f061b020b121e0fe0b020b061e02571b020b78260a0000100a0002101c1b000be00061a00e025b1d025bd025fd00be02691d0e026a1d026ae026b1d026be01eb1d01ebe026c1d026ce026d1d026de026e1d026e1a02001fff061b020b121e02701e001f048001f0b020b121e02701e001f3a17006c1b020b121e000191f0e000fa00001221e007bb020b121e001190a0002101f061b020b5a1e01d2221e000a0003101c16000b18082d1f0816ff8a1b000b63d17000c1b000b1ff0e00e00a0001101f0ce00a000004de00da0002101fe00de001f0a0002101f21e002ba000e00a000f0f02de00e00a000c01fab020b7ac1b020b7dc001fb25000b18001b020bfcb000b19221e0b020b860a0001101d027d001fe2500c01b020b061e01ccb020ba111e027db020b121f061b000b05221e01d0a0002101c1b020b8ac18061e027ab020b8b18061e027f041c1b020b8c18061e0c1b020bc18061e0b000b1d261b020ba0002101c1b020b5d260a0000101c1b020b121e0091c18061e0b020b12201d02811b020b37260a0000101c1b000b1d261b020ba0003101c001f0e0ec1c1b000b0c221e001de01850a000e01853f17000d1b020ba0e027a17002a18001e027f1e001f48003ed1c18001e027f1e00d1b020ba0f8a0f48001f0e001f3a17002f7001f1b020b121e0e0093241b000b91a010a0001101c18062d1f0616ffcc001f8b0f18001b000b0001f0e001f3ab020b121e0e0093241b000ba0a00020a0001101c18062d1f0616ffc6001f8c0131e0071c0f8d01b020b0f1b020b061e028a01c0f061b020b111b020b061e028a041cb3d17000b0f00d17000c1b000b081e02691f0d0f8e211b000b051e01d1700c71b000b05221e003e241b000b050201d7131e00061a00d263eb1c18001b000b063e17000d1b000b0c1a01471b000b0f0f0b031e001f3a17005b1b0f017000b1c18081b000b00f7002c1f091b000b051e00221e028d221e0090a000dd16ffdd1f0716ffa0f8f188f1d028e22201d028f22201d02900a0003101c1b000b051e00fb000b0021b000b051e00221e028d1f06131e00061a0022261d0011221e00a000f028d002000d0a00071f0e001f1f0b0001c00081ce17000d1b000b0a01470a00001f0f7002a1f071b030b06221e0070a00006221e00a0001101c16ffd51b030b01f0b030b093ab030b06221e00b030b0a00006221e0093241b030b0a0001101c18082d1f0816ffc0a0000101d00f1131e00061a00d01ad01dd22121d01ccd028ad01dfd02571f06131e00061a0022121d0d0d0d0d027a220a00001d027f220a00001d0a00001d0a00001d0a1d017db1d00dfc1d029d1f12131e00061a001f1a14029e1f1f48001f01e1b021b020b351d029f1b0d02a01b020bf34271f02a1b021b020b361d029f1b020b30481c5301f061b0d02a01b020bf0271b021b020b341d029f1b020b321b020b30481ab020b01f36131e00061a00049121f061b020bf111e027d1e02991f0c1b020b121e02991f0201c1b000b11221e00aaaa0003101c001d01d21f5a131e00061a00d02ad01bd02ad01bcd02a61f5b121f5c0a00001f5e0a00001f5f0a00001f00001f00a001fa71f6d0202a81f6e1b000bd1c1b000b201b000b05411f7b1b000bd1c1b000b211b000b05411f7c1b000b19221e00fba0001101f86186f1fe00d027e18871e00d0e0022188d1d017000b1c180d260a0000101d01cc188e260a0000101cd027cd1d01d027ed02551b000b05221e003ea9131e00061a0022201d028e0a0003101c000a0002101c0002aa00066d9776cb6cc61766b6d6c03636fa726dde607bdeb714b470c666d61776f676c764f6db71446bd7a086b06b0a720b616d6c66d70016b0b4a564f4e476e676f676cdb6cd6b50676f6d76674c6d766b646bb6d6c5f06ba4c6d766b646bb6d6c0cb6ff66b6f4636ed6d6e67636c0c70636c666d6fb6c653ea3b4656a6b68696e6f6c6da7ba4b48494e4f4c4da5be6d6dc666d6f066e676c65766a09666d6f60f596d2556b6c666d755f0d766d767be6e076b6c66677a4dd61776f676cd24c63746bd705f10596d24a6b71766d707b5f0ad6f6706b6c65013f0e6bf06616a76706b6c16d6d696b670eb6d6c51766db76676f0c6e6d61636e51766d16d6d696b16d6d696bb76676f313fa726bf4f6d6c2ea3f2d390aa726bf0b766d454fb6c3766a3f2de416d6d696b670a70676f6d74674b76676f0eeb6cdb026be6d16d6c716d6eba6db66766a0a6b6c6cb66766a0b6da676b656a760b6b6c6c67704a676b656a760a6c6d6d96ddf0d726a636c766d6fe77656b6c71085d726a636c766d6f0b61636e6e526a636c766d6f0b5d5d6c6b656a766f7666b6dccb6c65416d6c76677afbb7764d756c52706db4c636fe636ca706d6fc766b6fd6c6cd5dbded5d71676e676c6b776f5deb5d5dbdb72765d64776c61766b6d6c175d5dbdb72765d64776c61155d5dbdb72765d646c135d5d647a66706bded5d66706bd776cd5dbd776cd5d66706bded5d71676e676c6b776f5d776cd5d647a66706bd776cd71676e676c6b776f0c61636e6e51676e676c6b776f165d51676e676c6b776f5d4b46475dd66d61776f676c76056fa0a5ef785f66615d0a675d0f6b6c616d656c6b766d6046d72676c096b6c616d656c6b766d076d6cddd56435d475a65dd6fb4abb6c66677ac526d6b6c76c760e4f51526d6b6c76c760a6a6d6d1760d7476e676f676ccd04e0eea6c63766bdd2526e77656b6cb5f0e6e6db6d6c64a5c6ad385e2d5e2d2a59322f3b5f79332e317f2a5e2c59322f3b5f79332e317f2b79317f7e59632f64322f3b5f79332e367f2af64322f3b5f79332e367f2b79357f2b086e6db6d6c046ab6e67106ad2d6e6d61636e6a6d52574b4c444d0ad6c76677a56e0ca76676c716b6d6ce5dd70676cd6b6c646d0c0636f74c4fd54474c464d505de17574c4fd50474cde012d0ae77656b6ce57454b4c046b76676f0a04767bc636f16b6d6c08646b6e676c636fd6b6c0e6b61670c616d6c716ba6c760b766d4e6ded706f07756b6c666db6c07636c66706d6b66056e6b6c777a066b726a6d6c67046bb726d66036ff63616b6c766d716a0c6f63615d726db0d71037ab6da6b6dbbd7a2d066dd05226d72702d07616a706d6f672d0b66676c762d046f716bc666dd6d656ed6cd667be676f676cbc636f67046a1706bd0e6ef0b70676f6da6b6e660bc66416a6b6e660e766d406b6c63707bb6c650c64706d6f416ad66670d766d576b6c0637b0a616adb6ca36303b363bb37026f7a04646b7ac61707bb6c0637bbb6c0637b0aa476c616d66670e5c595e7a32322f5e7a35645ff636e646d706f06b6cada6db6c651f576c646b6c6b716a42f3a226dcadbe6bc6b616dcaf3a22676c616d666b6caad66674e6d6cb6c650aad66670e5c595e7a32322f5e7a64645f0a7ab72760eca03a322d4fa4be476b354c4e606d735b564dfc707b7a3b4ad616a63704b6c66677aa4b48494e4f4c4da5ba6b68696e6f6c6da7ba3b292dc7616dd616a0df0f57706e013d026d6c036db76616a0e5df51756b76616a4d6c0f5d607bdf5db76616a44706d6fa670f6436c6d6f636e6b67710a666bb656c0a616d6c716bcb76616a03666d6f046c6da636c766d6f046a6d6d690b0ef606eeb710bf5deff5de675d726d6c7b0766a222a6ae2d5e2d7e6ae2d5e2d7e5e2d5e2d2b3d595c5e2d5fb0e593d5f2a5e75293f2c28243d2bdd06b6c656b647b02797f04716dd6c516dbb036fd0cd646b6cb6cb66766a066a676b656aaabd6cb6e6e56677a7604c09f9a8e138e22c0acbf0a716a63666d75406e77700b716a6d754da046e6b6fa6d75416d6e6ddcab303a37373b0f416d6c646b65477ab6d6c076f7116a16b6d6c51766df6a63714e6d61636e51766dc6a63714b6c66677acb6e6b766b67710d16d6e77766b6d6c06c0a616d6e6da4636b6ed6e77766b6d6c0ab6e556b66766a0bb6e4a676b656a760eb4b6c646d0ab04766a676c08616ab6c650c616ab6c65566b6f670f666b71616ab6c65566b6f67056ee0cd77616a4b6c646d0e6f637a566d77616a526d6b6c76710bc760a566d77616ac760c6d6c766d77616abb6f67786d6c67764f6d6c766ab6f67786d6c674d36f6b6c0d6cf6d6c6da71636c712fbbc0d6f6f6f6f6f6f6f6f6f6f6e6e6b096b6c6c67704a564f4e0b6ea08646d6c76516b78670a646d6cf6b6e7b0b6d56b66766a0c6da676b656a760c16afb6c65666b6cb6ec0db0a416d6cc766b630b516b6f51776c2f477afa76e6b6f0a4e67676ecf676b707b6d0b6cd70666b6bb706b2636e63766b6c6d0a416d6e6d6c6c63224fe637b606b6e6e08486df636c0a6f676c760a4f51224d77766e6d6d1676c224f56064d52564b4f474c4b500c43706b636e224aad7b67224ee6e63700a4f5b504bd012e0eb6c76637ad60516dfc63766b74674e676c65766a0614b720b746b746d60706d00416d6c6cb6d6c146f6dd6c6cb6d6cbd6c6cb6d6c1ccc2c6e2c656d6d656e672c616d6f38333b06e710a6be2a59322f3b5f79332e317f2a5e2c59322f3b5f79332e317f2b79317f7e59632f64322f3b5f79332e367f2af64322f3b5f79332e367f2b79357f2b355c2a333b305e2c33343a5e2c7e33343b5e2ce2c7e33325e2c7ee2c2af3b5f7e305e667ef2b2b416a636c6c676e0b74de6d61636eb72766b6d6c0c666b77a67610e6d6c6bc666b7776b66207a7a7a7a7a7a7a7a7a7a7a7a367a7a7a7b7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a04597a7b5f017a0d616ae6b676c764b660be6b676c764bb660d676c61707b66ba4b48494e4f4c4da5ba6b68696e6f6c6da7ba3b2f2c0ef606ef7646da025c5c01340cd646b6ee033d733f0d616de5d607bdd666b660c5ddd666bd71616b3636b66016c0b6f06b6e6b766b67710a766b6ffa067416d6cc617b0cb61674f676f6d707b086e636cad6e77766b6d6c0fb6ed6e77766b6d6c06c566d720ac4e7746bb7a676eb6d0a72706db09766d77616a4b6c646d08766b6f67786d6c670a766b6ff74b6c646d0bd6c76714e6b71760b726e77656b6c714e6b71760a766b6ff72310ad6d696b67016f0b717b6c76637ad700c6c63766b74674e676c65766a0bb6d6c0b5d5db6d6c5d5d08616e6b676c764b660a766b6ff72360b677a76676c66446b676ee6e6516b6f726b646b6c764e6bc6566d4e6be6bb136a636c666eb606d76ceb0e49677b076fb08716a6bb036c6d75136a636c666e67526d716b766b6d6cc760e616a636cd77616ad77616a6f6dd77616abe6b676c765a07616e6b676c765b106a636c666e67416e6bc760a766d77616ae614f67636cec7746b63766b6d6c061636ec6516b6f726e6b646bec764b660b5d5d63615db660f65676ce6dcb656ce2c6c6d6cfc226d2756b766aedb230b666d6f4c6de6bd766d616d6e007646de0056c6d6c61670b606d667b54636ea606d667b5d6a63716a3f0b0b656c0a6c636f673f0db663f0b663f086c6d6ca36303b363bbb6d6c0bab6d6c01280aec63746bd70516b656c636e710bd66674c636fc636fded4676c666da666d4c6dbbc766b636edb1764f67666bb517bfed6d766a0d756b6c666d75516b656c636e71054b6fc5a06c5b0f6b067416d6c76677ad6d6eb6e6db6d6cdb74675a4d8677ac636e0b726d71764f71bbc6b6f63766b6d6cf670d406ed6d766a57574b46086c2670f666d61776f676c76516b656c636e710c616aa616d6ff6de637bb6fe0656e41636cab6f676c76636e2fe0d6f637a436c6b716d76706d727b1e475a565d76677ad646b6ed636c6b716d76706d726b94b565d475a565d76677ad646b6ed636c6b716d76706d726b61224f4d585d475a565d76677ad646b6ed636c6b716d76706d726b611e4f435a5d56475ad4f435a5d434c4b514d56504d525b5d475a560ce516b656c636e54eda76676c716b6d6c26da76676c716b6d6c16d6c76677ab9636c766b636e6be57475d404beb76710aa5d404b2766a406b76710ac5d404b7676c406bf435a5d414d4f404b4c47465d56475ad4b4fd574c4b56511c6f637a416d6f606b6cab6fc6bf435a5dd4f43525d56475ad514bf637afab78671c4f435a5df474c565d574c4b444d504f5ddf637af676c76576c6b646d706fdf435a5d50474cd514bf637a50676cbf435a5d56475ad4b4fd574c4bf637a56677ab6fc6bf435a5d56475ad514b58470e6f637a56677abf435a5db4b4c455ddf637ab6b6cdf435a5da5dbf637aab60711e4f435a5da5d56475ad4b4fd574c4b56511a6f637aa56677ab6fc6b76711a4f435a5da5d574c4b444d504f5ddf637aa576c6b646d706fda43464b4c455d4e434cdb4d4c16716a63666b6c654e636cb6d6c0cc414b4e5d404b56510bc616b6e406b0514b4d4c0ac63746bdb6c666db4c444d0a14b6c646d09766b6ff720d6b71476c63606ea145d676c63606ea4e6b77a0c6b6c2765a4a500e5a4f4e4aac66106db66674f6b6f67567b72670f5d63615d6b6cd71676c66155d607bd6b6c2765d6e6bc76f676c76710e5c616d6c76676c762f767be5d607bd616d6c76676c76115d6db66674f6b6f67567b72670d5d607bd6f67766a6d660a5d607bd77706e076d6c63606dd6c6e6dd6c6e6dc660b6d6c6e6d0760a6d6c72706d96d6c766b6f676d77760b5d716b656cf0b5d607bd606d667b126d6cb16a636c65670cd6cbb6f676de6dd26e6bb6d6c2d7a2ff646d706f2f77706e676c616d2726e6bb6d6c2d68716d6c04716b656c0b0db6c646d4ae6b6c6a0a0f67766a6d660b766d6e6d6ca76076a1165d5d63615d6b6cda0a0dd6616a145d6616a416d6c76676c76567b72670c616d6c76676c762f767b72670b74c6d6c071670f60776b6e664c0e0d6e6b617b046f6d16abb6cb767b0e5706be105d77706ebe67710bbe22084d504b454b4c38220b0bb6eb6c66677a4d0b6ee0c245d716b656cf0c3d5d716b656cf096b6cb714b6cc61674d64407b063756e67700d407b063756ed72766b6d6c71046b6c6b760e676c63606ea4e6b71760f77706ebedf74636e6bd72766b6d6c711e6d72766b6d6c22636b662a4b6cb226b71226c3276d72766b6d6c22676c63606ea4e6b71762ab2b226b71226cca4e6b77ac57706eb77a0ac5d5d63615d6ea670ab0a5d5d63615d606e636c692a41636c6c6dd6c76cb6cd70226c776e6e22766d226de6a63714d756c52706db0ebe670c616d6c646bedb4b71476c776fe670e766d4e6d61636eb6ce77674d640d6bd766d767b72674d64204dc69677be6ed6c226c6d6c2f6d6302c33332c4756d0c5a2f4ff4b6c646d03606d67296ad2d7a7a60652c716cc616d6f2d92d74332db6c646d236ad2d7a7a60652c716cc616d6f2d92d74332d72236ad2d7a7a60652c716cc616d6f2d92d74332d06e0ab0a0f3c0d616d6e6df6df6db666d756c096f6dd756c00a5d5d67714f6d66776e67"; window._$jsvmprt(v1, [, , void 0, "undefined" != typeof module ? module : void 0, "undefined" != typeof define ? define : void 0, "undefined" != typeof Object ? Object : void 0, void 0, "undefined" != typeof TypeError ? TypeError : void 0, "undefined" != typeof document ? document : void 0, void 0, void 0, "undefined" != typeof Date ? Date : void 0, "undefined" != typeof Math ? Math : void 0, "undefined" != typeof navigator ? navigator : void 0, "undefined" != typeof location ? location : void 0, "undefined" != typeof history ? history : void 0, "undefined" != typeof Image ? Image : void 0, "undefined" != typeof console ? console : void 0, "undefined" != typeof PluginArray ? PluginArray : void 0, "undefined" != typeof indexedDB ? indexedDB : void 0, "undefined" != typeof DOMException ? DOMException : void 0, "undefined" != typeof parseInt ? parseInt : void 0, "undefined" != typeof String ? String : void 0, "undefined" != typeof Array ? Array : void 0, "undefined" != typeof Error ? Error : void 0, "undefined" != typeof JSON ? JSON : void 0, "undefined" != typeof Promise ? Promise : void 0, "undefined" != typeof WebSocket ? WebSocket : void 0, "undefined" != typeof eval ? eval : void 0, "undefined" != typeof setTimeout ? setTimeout : void 0, "undefined" != typeof encodeURIComponent ? encodeURIComponent : void 0, "undefined" != typeof encodeURI ? encodeURI : void 0, "undefined" != typeof Request ? Request : void 0, "undefined" != typeof Headers ? Headers : void 0, "undefined" != typeof decodeURIComponent ? decodeURIComponent : void 0, "undefined" != typeof RegExp ? RegExp : void 0]);
编译通过了,下面看看byted_acrawler有没有生成并且看看有没有生成signature
3.4.1 Python获取签名值并实现
# -*- coding: utf-8 -*- # (venv) E:\crawler(爬虫)\day04> node v20.js "https://www.toutiao.com/api/pc/list/feed?offset=0&channel_id=&max_behot_time=0&category=pc_profile_channel&disable_raw_data=true&aid=24&app_name=toutiao_web" # _02B4Z6wo00f01vu4PgAAAIDBBEfB.ftCImL7mjqAANsre0 import os import subprocess # 根据自己的操作系统去修改(相当于python的sys.path,加载安装的模块) os.environ["NODE_PATH"] = "D:\\Nodejs\\node_global\\node_modules" url = "https://www.toutiao.com/api/pc/list/feed?offset=0&channel_id=&max_behot_time=0&category=pc_profile_channel&disable_raw_data=true&aid=24&app_name=toutiao_web" result = subprocess.run(f'node v20.js "{
url}"', shell=True, stdout=subprocess.PIPE) signature = result.stdout.decode('utf-8') print(signature)
得到签名在让url拼接起来已发送请求就应该获取到评论
拿着url再去发送请求
4.pyexecjs签名并实现
import requests import execjs import os os.environ["NODE_PATH"] = "D:\\Nodejs\\node_global\\node_modules" with open('v20.js', mode='r', encoding='utf-8') as f: js = f.read() JS = execjs.compile(js) url = "https://www.toutiao.com/api/pc/list/feed?offset=0&channel_id=&max_behot_time=0&category=pc_profile_channel&disable_raw_data=true&aid=24&app_name=toutiao_web" signature = JS.call("get_sign", url) final_url = f"{
url}&_signature={
signature}" res = requests.get( url=final_url, headers={
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36" } ) print(res.text)
六、知网资料批量爬取并可视化展示
1.批量爬取知网数据
- lxml:是 Python 的一个功能强大且易用的 XML 和 HTML 处理库。它提供了简单又轻巧的 API,使得解析、构建和操作
XML 和 HTML 文档变得非常方便。lxml 库通常用于处理 XML 和 HTML 文档,例如解析网页、处理配置文件等。 - openpyxl:是 Python 中用于操作 Excel 文件(.xlsx 格式)的库。通过 openpyxl,你可以读取、修改和创建 Excel 文件,包括对工作表、单元格内容、样式等的操作。这个库在处理 Excel 数据时非常方便,可以用于数据处理、报表生成等应用场景。
import requests from lxml import etree from openpyxl import Workbook base_url = 'http://search.cnki.com.cn/Search/ListResult' headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36' } def get_page_text(url, headers, search_word, page_num): data = {
'searchType': 'MulityTermsSearch', 'ArticleType': '', 'ReSearch': '', 'ParamIsNullOrEmpty': 'false', 'Islegal': 'false', 'Content': search_word, 'Theme': '', 'Title': '', 'KeyWd': '', 'Author': '', 'SearchFund': '', 'Originate': '', 'Summary': '', 'PublishTimeBegin': '', 'PublishTimeEnd': '', 'MapNumber': '', 'Name': '', 'Issn': '', 'Cn': '', 'Unit': '', 'Public': '', 'Boss': '', 'FirstBoss': '', 'Catalog': '', 'Reference': '', 'Speciality': '', 'Type': '', 'Subject': '', 'SpecialityCode': '', 'UnitCode': '', 'Year': '', 'AcefuthorFilter': '', 'BossCode': '', 'Fund': '', 'Level': '', 'Elite': '', 'Organization': '', 'Order': '1', 'Page': str(page_num), 'PageIndex': '', 'ExcludeField': '', 'ZtCode': '', 'Smarts': '', } response = requests.post(url=url, headers=headers, data=data) page_text = response.text return page_text def list_to_str(my_list): my_str = "".join(my_list) return my_str def get_abstract(url): response = requests.get(url=url, headers=headers) page_text = response.text tree = etree.HTML(page_text) abstract = tree.xpath('//div[@class="xx_font"]//text()') return abstract def parse_page_text(page_text): tree = etree.HTML(page_text) item_list = tree.xpath('//div[@class="list-item"]') page_info = [] for item in item_list: # 标题 title = list_to_str(item.xpath( './p[@class="tit clearfix"]/a[@class="left"]/@title')) # 链接 link = 'https:' + \ list_to_str(item.xpath( './p[@class="tit clearfix"]/a[@class="left"]/@href')) # 作者 author = list_to_str(item.xpath( './p[@class="source"]/span[1]/@title')) # 出版日期 date = list_to_str(item.xpath( './p[@class="source"]/span[last()-1]/text() | ./p[@class="source"]/a[2]/span[1]/text() ')) # 关键词 keywords = list_to_str(item.xpath( './div[@class="info"]/p[@class="info_left left"]/a[1]/@data-key')) # 摘要 abstract = list_to_str(get_abstract(url=link)) # 文献来源 paper_source = list_to_str(item.xpath( './p[@class="source"]/span[last()-2]/text() | ./p[@class="source"]/a[1]/span[1]/text() ')) # 文献类型 paper_type = list_to_str(item.xpath( './p[@class="source"]/span[last()]/text()')) # 下载量 download = list_to_str(item.xpath( './div[@class="info"]/p[@class="info_right right"]/span[@class="time1"]/text()')) # 被引量 refer = list_to_str(item.xpath( './div[@class="info"]/p[@class="info_right right"]/span[@class="time2"]/text()')) item_info = [i.strip() for i in [title, author, paper_source, paper_type, date, abstract, keywords, download, refer, link]] page_info.append(item_info) print(page_info) return page_info def write_to_excel(info, search_word): wb = Workbook() ws = wb.active # 创建子表 ws.title = search_word title = ['title', 'author', 'paper_source', 'paper_type', 'date', 'abstract', 'keywords', 'download', 'refer', 'link'] # 设置表头 ws.append(title) for row in info: ws.append(row) wb.save('data.xlsx') return True # 获取页面数据1页 page_text = get_page_text(base_url, headers, 'YOLOV5', 1) # 解析页面数据 page_info = parse_page_text(page_text) # # 添加循环遍历1到10页 # page_info_list = [] # for page_num in range(1, 11): # page_text = get_page_text(base_url, headers, 'YOLOV5', page_num) # page_info = parse_page_text(page_text) # page_info_list.extend(page_info) # 读取excel表格 write_to_excel(page_info, 'YOLOV5') # 将整个列表写入 Excel 文件 # write_to_excel(page_info_list, 'YOLOV5')
2.数据可视化
可视化第一作者、下载量、被引量
- pandas 是一个强大的数据分析工具,主要用于数据的清洗、处理、分析和建模。它提供了快速、灵活、简单和实用的数据结构,使您能够轻松地操作结构化数据。
- matplotlib.pyplot 是 Matplotlib 库的一部分,用于创建各种类型的图表,包括折线图、散点图、柱状图、饼图等。通过 matplotlib.pyplot,您可以将 pandas 中处理过的数据可视化,以便更直观地理解数据、分析数据间的关系,或进行结果的展示和分享。
import pandas as pd import matplotlib.pyplot as plt # 设置中文字体 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False # 从 Excel 文件中读取数据 df = pd.read_excel('data.xlsx') # 提取每篇论文的第一个作者 df['first_author'] = df['author'].str.split(';').str[0] # 统计第一个作者的出现次数 first_author_counts = df['first_author'].value_counts() # 创建第一个作者条形图 plt.figure(figsize=(12, 8)) plt.barh(range(len(first_author_counts)), first_author_counts.values, align='center', alpha=0.5, color='skyblue') plt.yticks(range(len(first_author_counts)), first_author_counts.index) plt.xlabel('第一个作者出现次数') plt.title('第一个作者', pad=20) plt.gca().invert_yaxis() plt.tight_layout(pad=2.0, rect=[0, 0.03, 1, 0.95]) plt.show() # 创建下载量条形图 plt.figure(figsize=(8, 6)) plt.barh(df['title'], df['download'], color='lightgreen') plt.ylabel('论文标题') plt.xlabel('下载量', labelpad=20) plt.xticks([]) # 将 x 轴的刻度设置为空列表 plt.title('下载量', pad=20) plt.tight_layout(pad=2.0, rect=[0, 0.03, 1, 0.95]) plt.show() # 创建被引量条形图 plt.figure(figsize=(8, 6)) plt.barh(df['title'], df['refer'], color='gold') plt.xlabel('被引量') plt.title('被引量', pad=20) plt.tight_layout(pad=2.0, rect=[0, 0.03, 1, 0.95]) plt.show()
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/158887.html