百度指数数据

一.相关环境

开发工具:pycharm

开发环境:Python

操作系统:windows

二.目标数据

在百度指数首页登录,之后输入我们需要的关键词,我们需要抓取指定关键词的搜索指数趋势图中某一短时间的数据,我们首先需要登录我们的百度账号以获取cookie。

我们需要获取曲线上的每一点所对应的数据,打开开发者工具F12,在元素栏中搜索其中数据,搜索结果不到,说明数据不是网页中的,而是通过后方数据库,动态获取的。

三.获取动态数据

动态数据都是后台数据库返回的,所以我们需要找到这个文件。

打开开发者工具-->点击到网络栏-->选中XHR项-->刷新页面

XHR选项:XMLHttpRequests(XHR)请求通常会返回从服务器获取的数据。这些数据可以是各种格式,取决于服务器端和前端的配置以及应用程序的需求

我们逐个点击左侧请求的名称并查看右侧响应预览

我们可以发现在index开头的请求中包含数据,观察一下我们发现应该就是我们要的数据,其中all是指全部数据,PC是指pc端,wise是指移动端,但是data被加密了,所以我们需要通过‘JS逆向‘找到对应的解密方式。

四.JS逆向

我们分析以上请求中给我们返回的json数据

"data": {
        "userIndexes": [
            {
                "word": [
                    { }
                ],
                "all": {
                        "startDate": "",
                        "endDate": "",
                        "data": ""
                },
                },
                "pc": {
                },
                "wise": {
                },
                "type": "day"
            }
        ],
        "generalRatio": [
            {}                 
        ],
        "uniqid": "c195cf6d98dde7b9d7f06238796a1e42"
    },

其中当我们想从data中获得数据时,必然会用到类似data.userIndexes的方式从response中来取出整个数组数据,并且最终会用all.data来获取最后一层数据。为此,我们尝试使用generalRadio,userIndexes去搜索。

Ctrl+F打开全局搜索框,搜索userIndexes(我们需要其中的数据),定位到三个JS

逐个查看后发现第一个JS就是之前我们看的数据,第二个JS中·userIndexes只有一处,是在处理请求函数中,并没有解密数据

第三个JS中userIndexes有3处,其中第一处是向后端发送axios请求(响应数据等)。第二第三处在一块,可以发现这里调用了all.data,pc,data,wise.data。我们可以看到其中有一个decrypt函数,至此咱们可以知道就是解密函数,我们可以看到dectypt函数传入了两个参数,

从其中我们可以看出其中第二个参数是从后端获取的加密数据,第一个参数暂时看不出来,因此我们搜索decrypt,并在函数中打上断点进行调试,跳转到函数内部

我们可以看到t="kAhjeN4z3WOuaD6-918652.4+370,%"这样的加密字符

搜索这个字符,我们可以发现结果显示参数是从https://index.baidu.com/Interface/ptbk?uniqid=223acdc67372b787e7619f43834b6d15返回的

打开文件的负载我们发现其中有个参数uniqid发现好几个请求都有该参数,同时在我们请求数据接口时,后台数据库也给我们返回了该参数

因此我们整理一下思路我们要获取数据因此去访问数据库,随后,数据库给我们返回了一个加密厚的数据,同时给我们返回了一个uniqid参数(此参数用于获取t参数,又叫ptbk参数),获取这个ptbk参数的url:https://index.baidu.com/Interface/ptbk?uniqid=851b6825de9a14255d199cbd73338cd2需要一个参数uniqid,我们进行GET请求,返回一个JSON数据,获取uniqid和data的url:https://index.baidu.com/api/SearchApi/index?area=0&word=[[%7B%22name%22:%22%E7%8E%AF%E5%A2%83%E6%B1%A1%E6%9F%93%22,%22wordType%22:1%7D]]&days=30

(如果要指定日期只需在word后面追加&startDate=,&endDate=,days代表多少天,area代表位置等于0就是全国)

总结:

1.通过URL获取uniqid和data

2.通过uniqid获取ptbk

3.通过ptbk和data解密

五.代码实现

因为百度指数的请求会验证用户登录,所以我们在发送请求需要携带Cookie信息,百度Cookie的核心是BDUSS,所以我们要登录账户--》开发者工具--》Cookie-->BDUSS

1,请求头和我们需要的参数

cookies = ''  # 自己的cookie

search_param = {
  "area": "0",
  "word": [
    [
      {
        "name": "环境污染",
        "wordType": 1
      }
    ]
  ],
  "days": 30
}
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,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'Cipher-Text': '1716807885460_1716889185749_Nl3QA+PCPMLfYvM8U1T5ZxzmJhWSzfcSr46qfguTO1HbBO67J3CJLqUjtGlJCXGNiTVpkYh0icU2ZDkQO8g563PDL/4t+GtDE3A7xaxw8pNR5ih53NZTVWDCGGebbvonuH9whIQAnsS7IkMVf5kOyXvMpEmA80LLdpLn4tXtUSo1UK5WwoJxGNph7EvWY1JuVN5vqEvqhYdxAz7IzQ398zN7des33r7I3n9/3fTxVXa/Dx1hAJdm4h32YB4Ked60dI7Dl8U3SLFRIEjZIUiKhwx2+Dfm5SM22XwvGNCmkW6qr53R5JVo8XMpGYQZZYJr4+YnXcGn709ns/cRMHGuvHjZMxqI217Nrdsbo8nfD2n6QyfCmdngXhGpycCVMNIKJJqXQeoLX1IwF7NvcQXkwi1e+ZofFgXj50iLi3lciLlc853OY7xcURptTZQCdslP4Z7wyh3qiqciMR7sQAucTQ==',
    'Connection': 'keep-alive',
    'Cookie': cookies,
    'Host': 'index.baidu.com',
    'Referer': 'https://index.baidu.com/v2/main/index.html',
    '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'
}

随后,我们向api发送get请求,获取到加密数据,同时保存好uniqid

response = requests.get(search_url, params=search_param, headers=headers)
encrypted_data = response.json()['data']
print(type(encrypted_data))
uniqid = encrypted_data['uniqid']

获得到加密数据后我们要对他进行解密

2.解密数据

为此我们要先获得解密参数

ptbk_url = f'http://index.baidu.com/Interfac/ptbk?uniqid={uniqid}'
ptbk_response = requests.get(ptbk_url, headers=headers)
ptbk = ptbk_response.json()['data']

随后我们需要改写JS中的解密函数

改写后的python版

def decrypt(ptbk, encrypted_data):
    """
    :param ptbk: 解密参数
    :param encrypted_data: 加密数据
    :return: 解密后的数据
    """
    if not ptbk:
        return ""
    n = len(ptbk) // 2
    d = {ptbk[o]: ptbk[n + o] for o in range(n)}
    decrypted_data = [d[data] for data in encrypted_data]
    return ''.join(decrypted_data)

扩展

搜素关键词以及设置时间和指定省份

search_param = {
    'area': '0',  # 这是省份城市编号,当area = 0代表全国
    'word': json.dumps([[{"name": "环境污染", "wordType": 1}]]),  # 将参数值转换为 JSON 字符串,其中name是搜索关键词
    # 'days': 30,
    'startDate': '2024-01-03',  # 输入查询开始时间
    'endDate':'2024-05-30',  # 输入查询结束时间
}  # 我们更改参数去查询

总代码如下

import requests
import pandas as pd
import json
# from fake_useragent import UserAgentent

cookies = ''  # 自己的cookie

search_param = {
    'area': '0',  # 这是省份城市编号,当area = 0代表全国
    'word': json.dumps([[{"name": "环境污染", "wordType": 1}]]),  # 将参数值转换为 JSON 字符串,其中name是搜索关键词
    # 'days': 30,
    'startDate': '2024-01-03',  # 输入查询开始时间
    'endDate':'2024-05-30',  # 输入查询结束时间
}  # 我们更改参数去查询
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,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'Cipher-Text': '1716807885460_1716889185749_Nl3QA+PCPMLfYvM8U1T5ZxzmJhWSzfcSr46qfguTO1HbBO67J3CJLqUjtGlJCXGNiTVpkYh0icU2ZDkQO8g563PDL/4t+GtDE3A7xaxw8pNR5ih53NZTVWDCGGebbvonuH9whIQAnsS7IkMVf5kOyXvMpEmA80LLdpLn4tXtUSo1UK5WwoJxGNph7EvWY1JuVN5vqEvqhYdxAz7IzQ398zN7des33r7I3n9/3fTxVXa/Dx1hAJdm4h32YB4Ked60dI7Dl8U3SLFRIEjZIUiKhwx2+Dfm5SM22XwvGNCmkW6qr53R5JVo8XMpGYQZZYJr4+YnXcGn709ns/cRMHGuvHjZMxqI217Nrdsbo8nfD2n6QyfCmdngXhGpycCVMNIKJJqXQeoLX1IwF7NvcQXkwi1e+ZofFgXj50iLi3lciLlc853OY7xcURptTZQCdslP4Z7wyh3qiqciMR7sQAucTQ==',
    'Connection': 'keep-alive',
    'Cookie': cookies,
    'Host': 'index.baidu.com',
    'Referer': 'https://index.baidu.com/v2/main/index.html',
    '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(search_url, params=search_param, headers=headers)
encrypted_data = response.json()['data']
print(type(encrypted_data))
uniqid = encrypted_data['uniqid']

ptbk_url = f'http://index.baidu.com/Interface/ptbk?uniqid={uniqid}'
ptbk_response = requests.get(ptbk_url, headers=headers)
ptbk = ptbk_response.json()['data']


def decrypt(ptbk, encrypted_data):
    """
    :param ptbk: 解密参数
    :param encrypted_data: 加密数据
    :return: 解密后的数据
    """
    if not ptbk:
        return ""
    n = len(ptbk) // 2
    d = {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 0
    else:
        return data


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.在爬取数据过程关键词用json格式,否则可能报错

2.在逆向过程中断点可以帮助我们更好的跟踪数据

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值