详解百度指数搜索指数js逆向
一、相关环境
开发工具:PyCharm 2022.3.1 (Community Edition)
开发环境:Python 3.9
操作系统:Windows10
二、目标数据
在百度指数首页登录,然后输入一个关键词进入搜索指数页面,以下操作全是基于该页面进行。
我们要抓取的是指定关键词的搜索指数趋势图中某一段时间的数据,这里以python的搜索指数为例:
需要获取曲线上每一个这样的点对应的数据。打开开发者工具,在元素栏中Ctrl+F搜索其中一个数据,搜索结果为0条,说明网页源代码中不存在需要的数据,而是动态获取的。
三、获取动态数据
打开开发者工具->切换到网络栏->选中XHR项->刷新页面
逐个点击左侧请求的名称并查看右侧的响应预览,发现index开头的请求中包含数据,观察一下发现应该是我们需要的数据,但是data被加密了,那么下一步需要js逆向找到加密方式。
四、JS逆向
我们分析上述请求返回的json数据,其形式大致如下:
{"data": {"generalRatio": [{}],"userIndexes": [{"word": [],"all": {"data": "","endDate": "","startDate": ""},"pc": {},"wise": {},"type": "day"}],"uniqid": "xxxxxxxxxx"}
}
当前端拿到这样的加密数据来解密时,必然要用到类似data.generalRatio、data.userIndexes这样的方式来取出整个数组;更进一步考虑,前端会使用all.data来获取最后一层数据。由于编译过的js中整个数据一般会赋值给单字母,而all和data这种单词又过于常见,因此我们的思路是先用generalRatio、userIndexes去搜索,没有结果的话再用all.data去搜索。
Ctrl+Shift+F调出全局搜索框,搜索userIndexes(因为我们找的是userIndexes中的数据),定位到两个js。
逐个查看后发现第一个js中userIndexes只有一处,是在处理请求的函数中。第二个js中userIndexes有三处,第一处是向后端发送axios请求,说明我们的目标就在这个js中;第二处和第三处在一起,可以很明显得发现这里在构造趋势图的数据,除了赋值操作之外,我们可以看到有一个decrypt函数,且分别用它操作了all.data、pc.data、wise.data,至此我们可以确定这个函数就是解密函数。
decrypt函数传入了两个参数,第二个参数可以看出是从后端获取的加密数据,第一个参数暂时看出来是,我们在其中一个decrypt函数处打断点进行调试,跳转至decrypt函数内部时,可以看到第一个参数是"-GlAwgjW3yBdeQm7,%5+940831-6.2"这样的加密字符串,在网络栏中搜索一下看是不是从后端传过来的,结果显示这个参数是https://index.baidu.com/Interface/ptbk?uniqid=47ec7818050d810e4d02951afcbd38c7的返回。
再搜索一下参数uniqid,发现好几个请求都有该参数返回且值相同,同时请求数据的接口也返回了该参数。
最后整理一下思路:
#mermaid-svg-1I81rQEBzhYBwEs5 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-1I81rQEBzhYBwEs5 .error-icon{fill:#552222;}#mermaid-svg-1I81rQEBzhYBwEs5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1I81rQEBzhYBwEs5 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-1I81rQEBzhYBwEs5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1I81rQEBzhYBwEs5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1I81rQEBzhYBwEs5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1I81rQEBzhYBwEs5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1I81rQEBzhYBwEs5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1I81rQEBzhYBwEs5 .marker.cross{stroke:#333333;}#mermaid-svg-1I81rQEBzhYBwEs5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1I81rQEBzhYBwEs5 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-1I81rQEBzhYBwEs5 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-1I81rQEBzhYBwEs5 .actor-line{stroke:grey;}#mermaid-svg-1I81rQEBzhYBwEs5 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-1I81rQEBzhYBwEs5 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-1I81rQEBzhYBwEs5 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-1I81rQEBzhYBwEs5 .sequenceNumber{fill:white;}#mermaid-svg-1I81rQEBzhYBwEs5 #sequencenumber{fill:#333;}#mermaid-svg-1I81rQEBzhYBwEs5 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-1I81rQEBzhYBwEs5 .messageText{fill:#333;stroke:#333;}#mermaid-svg-1I81rQEBzhYBwEs5 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-1I81rQEBzhYBwEs5 .labelText,#mermaid-svg-1I81rQEBzhYBwEs5 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-1I81rQEBzhYBwEs5 .loopText,#mermaid-svg-1I81rQEBzhYBwEs5 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-1I81rQEBzhYBwEs5 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-1I81rQEBzhYBwEs5 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-1I81rQEBzhYBwEs5 .noteText,#mermaid-svg-1I81rQEBzhYBwEs5 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-1I81rQEBzhYBwEs5 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-1I81rQEBzhYBwEs5 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-1I81rQEBzhYBwEs5 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-1I81rQEBzhYBwEs5 .actorPopupMenu{position:absolute;}#mermaid-svg-1I81rQEBzhYBwEs5 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-1I81rQEBzhYBwEs5 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-1I81rQEBzhYBwEs5 .actor-man circle,#mermaid-svg-1I81rQEBzhYBwEs5 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-1I81rQEBzhYBwEs5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 程序 api/SearchApi/index接口 Interface/ptbk接口 登录 请求数据 加密数据、uniqid 参数:uniqid 解密参数ptbk 通过解密参数ptbk解密数据 程序 api/SearchApi/index接口 Interface/ptbk接口
五、代码实现
导入所需的包
import requests
import pandas as pd
from fake_useragent import UserAgentnt
获取Cookie
百度指数的请求会验证用户是否登录,所以发起请求前需要获取Cookie信息,百度Cookie的核心是BDUSS,只能自己登录账号->开发者工具->应用程序->Cookie->BDUSS然后复制值。
在前面拼接BDUSS=即可构造Cookie
cookies = 'BDUSS=XXXXXXXXXX'
请求数据
1.请求头及参数构造
网络栏查看api/SearchApi/index请求,有三个参数:
1.area:省份代码,默认0表示全国
2.word:由关键词构造的二维数组,形如[[{“name”: “python”, “wordType”: 1}]]
3.days:返回数据是最近多少天,默认30
然后复制请求头,将Cookie传入
search_param = {'area': '0', 'word': '[[{"name": "python", "wordType": 1}]]', 'days': '60'}
search_url = 'https://index.baidu.com/api/SearchApi/index?'headers = {'Accept': 'application/json, text/plain, */*','Accept-Encoding': 'gzip, deflate, br','Accept-Language': 'zh-CN,zh;q=0.9','Cipher-Text': '1672733200884_1672792253933_1NLQa+cgc5N2JSNoinHAaMmrDrPtwqHL6D2NHONACx//1P+9YXcg/erBma8ucj43shvH2VsAi3Dzlo9cFfqA3k/PmqixjXJEslJCwNzCzNCVHs+/y7su33mGAxAtFWXrl55rYxzEJNGi4xM6jb4UUibTrVbOl46gKWq/7PVKAIzRyrJbxQP9pKmxECIpO12JbXFrA3leOj8xDZk69P1O/tNU6lD8eMPylUrgCp5k89c9EAD+Q4lgHhsZpTktcKTzKSbrJ5/l0GYNxNS96gEpS/0BnesBc6X52rqE7K4fNzrxm5cfgwbCJx/2+1ayhkI2gUMNDabQ1dnR0hr/NyWxeh7nYvxqarQHsZ+cu3XCt5uEHE4aAPgcXTfDgMsCQOrtMfDGKuxX5PiMDzDODjxSn8cDFRnJ+RMvfPjIIfq2P4k=','Connection': 'keep-alive','Cookie': cookie,'Host': 'index.baidu.com','Referer': 'https://index.baidu.com/v2/main/index.html','Sec-Fetch-Dest': 'empty','Sec-Fetch-Mode': 'cors','Sec-Fetch-Site': 'same-origin','User-Agent': str(UserAgent().random)
}
2.发送请求,解析数据
使用requests发送get请求,获取加密数据,同时保存uniqid
response = requests.get(search_url, params=search_param, headers=headers)
encrypted_data = response.json()['data']
uniqid = encrypted_data['uniqid']
解密数据
1.获取解密参数
ptbk_url = f'http://index.baidu.com/Interface/ptbk?uniqid={uniqid}'
ptbk_response = requests.get(ptbk_url, headers=headers)
ptbk = ptbk_response.json()['data']
2.改写解密函数
JS中的解密函数
Python版本的解密函数
def decrypt(ptbk, encrypted_data):""":param ptbk: 解密参数:param encrypted_data: 加密数据:return: 解密后的数据"""if not ptbk:return ""n = len(ptbk) // 2d = {ptbk[o]: ptbk[n + o] for o in range(n)}decrypted_data = [d[data] for data in encrypted_data]return ''.join(decrypted_data)
顺带把填充零的函数写了
def fill_zero(data):""":param data: 字符串格式的数据:return:data为空则返回0,否则返回原数据"""if data == '':return 0else:return data
3.解析数据并保存到csv
result = pd.DataFrame(columns=['关键词', '日期', '全部', '电脑端', '移动端'])
for userIndexes_data in encrypted_data['userIndexes']:word = userIndexes_data['word'][0]['name']start_date = userIndexes_data['all']['startDate']end_date = userIndexes_data['all']['endDate']timestamp_list = pd.date_range(start_date, end_date).to_list()date_list = [timestamp.strftime('%Y-%m-%d') for timestamp in timestamp_list]encrypted_data_all = userIndexes_data['all']['data']decrypted_data_all = [int(fill_zero(data)) for data in decrypt(ptbk, encrypted_data_all).split(',')]encrypted_data_pc = userIndexes_data['pc']['data']decrypted_data_pc = [int(fill_zero(data)) for data in decrypt(ptbk, encrypted_data_pc).split(',')]encrypted_data_wise = userIndexes_data['wise']['data']decrypted_data_wise = [int(fill_zero(data)) for data in decrypt(ptbk, encrypted_data_wise).split(',')]df = pd.DataFrame({'关键词': word, '日期': date_list, '全部': decrypted_data_all, '电脑端': decrypted_data_pc, '移动端': decrypted_data_wise})result = pd.concat([result, df])
result.to_csv('./result.csv',index=False)
扩展
1.同时搜索多个关键词
在word参数中添加多个关键词,最多五个,超过五个只会返回前五个的结果
'word': '[[{"name": "python", "wordType": 1}],[{"name": "java", "wordType": 1}],[{"name": "c", "wordType": 1}],[{"name": "c++", "wordType": 1}],[{"name": "go", "wordType": 1}]'
2.指定时间段
将days参数修改为startDate、endDate这两个参数
'startDate': '2022-12-01',
'endDate': '2022-12-31'
3.指定省份
可以只搜索某一个省份的数据,将area参数改为相应省份的代码即可,如北京市的代码为911,其他省份的代码可以在步骤四的js文件中找到:
详解百度指数搜索指数js逆向相关推荐
- 2篇CIKM详解阿里妈妈搜索广告CTR模型如何低碳瘦身
作为<阿里妈妈搜索广告CTR模型的"瘦身"之路>的姊妹篇,本文将结合团队发表的 CIKM 2021 两篇论文,详解我们在模型瘦身之路上的延续性思考与实践.姊妹篇已经总结 ...
- Apollo进阶课程 ⑮丨Apollo自动定位技术详解—百度无人车定位技术
目录 1.百度无人车定位进化历程 2.百度自动驾驶应用的定位技术 2.1GNSS定位技术 2.2载波定位技术 2.3激光点云定位技术 2.4视觉定位技术 原文链接:进阶课程 ⑮丨Apollo自动定位技 ...
- 站点html标贴验证,SEO优化之详解百度站点验证
原标题:SEO优化之详解百度站点验证 最近有不少SEO新手同学问,百度站点验证怎么搞?.SEO新手问这样的问题也不算奇怪.作为一名"SEO老司机"不懂得如何做百度站点验证,显然是说 ...
- 百度上线搜索指数3.0含义
百度经过几个月的调整终于上线了搜索指数3.0,这也是很多站长预料之中的,移动端现在百度APP由于安装量和在线量达到每天活动上亿的数据看,百度还是要推自己的百家号和小程序,门槛以后会越来越高,首先必须是 ...
- js和php能生成一样的随机数_JavaScript_JS生成某个范围的随机数【四种情况详解】,前言:
JS没有现成的函数,能 - phpStudy...
JS生成某个范围的随机数[四种情况详解] 前言: JS没有现成的函数,能够直接生成指定范围的随机数. 但是它有个函数:Math.random() 这个函数可以生成 [0,1) 的一个随机数. 利用它 ...
- php写语音朗读,详解在网页上通过JS实现文本的语音朗读
摘要: 语音合成:也被称为文本转换技术(TTS),它是将计算机自己产生的.或外部输入的文字信息转变为可以听得懂的.流利的口语输出的技术. 1.接口定义 http://tts.baidu.com/tex ...
- 语音朗读html的源码,详解在网页上通过JS实现文本的语音朗读
摘要: 语音合成:也被称为文本转换技术(TTS),它是将计算机自己产生的.或外部输入的文字信息转变为可以听得懂的.流利的口语输出的技术. 1.接口定义 http://tts.baidu.com/tex ...
- 智能猫窝是如何诞生的?详解百度大脑的开放生态
3 月 20 日下午,首场百度大脑开放日在北京中关村创业大街百度大脑创新体验中心举行.百度 AI 技术生态部总经理喻友平,就百度大脑平台与生态进行了全面的详解,同时展示了百度大脑开放平台 Q1 核心升 ...
- 指标详解(2)-- 指数平滑移动平均线(MACD)详解
一.定义:MACD称为指数平滑移动平均线,是从双指数移动平均线发展而来的,由快的指数移动平均线(EMA12)减去慢的指数移动平均线(EMA26)得到快线DIF,再用2×(快线DIF-DIF的9日加权移 ...
最新文章
- 万能的Python,不仅能开发效率高,还能绘画各种漫画图像
- OSSIM系统——mysql的使用
- 【有奖征文】情人节,和书一起走过的日子
- 图论:Dinic算法
- 程序员要学会读源代码
- vim 命令学习(高级篇)
- (五十九)iOS网络基础之UIWebView简易浏览器实现
- C#.NET验证码智能识别学习笔记---04C#.Net图片操作
- 高通msm8953 Android7.1支持Audio设备列表(十二)
- mac系统一些快捷键
- log4j输出日志级别控制
- 浙大计算机专业硕士专业代码,浙江大学海洋学院电子信息(专硕)专业代码
- 怎么保存html,怎么保存整个网页,教你一个妙招就可以搞定!
- Win7与VirtualBox ubuntu共享文件夹
- 计算机键盘无法使用的原因,电脑键盘失灵的原因及其解决方法
- arcgis 图层概念
- 怎么计算一个图像的面积呢?????
- 写的基于http协议的QQ聊天机器人
- 物联网IoT与万维物联网WoT
- z490 linux raid,PC硬件与外设 篇二十三:光威弈系列Pro Z490平台装机评测(含raid模式)...