• seleniumwire获取百度指数


    之前我在《如何用Python下载百度指数的数据》分享了如何使用接口获取百度指数,但是今年百度指数已经增加了新的校验方式,例如如下代码:

    import requests
    import json
    from datetime import date, timedelta
    
    headers = {
        "Connection": "keep-alive",
        "Accept": "application/json, text/plain, */*",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Dest": "empty",
        "Referer": "https://index.baidu.com/v2/main/index.html",
        "Accept-Language": "zh-CN,zh;q=0.9",
        'Cookie': cookie,
    }
    
    words = '[[{"name":"python","wordType":1}],[{"name":"java","wordType":1}]]'
    start, end = "2022-06-28", "2022-07-27"
    url = f'https://index.baidu.com/api/SearchApi/index?area=0&word={words}&startDate={start}&endDate={end}'
    res = requests.get(url, headers=headers)
    res.json()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    {'status': 10018,
     'data': '',
     'logid': 2631899650,
     'message': '您好,百度指数监测到疑似存在xx访问行为,如您未有类似行为,可能是由于您使用公共网络或访问频次过高,\n        您可以通过邮箱ext_indexfk@baidu.com联系我们'}
    
    • 1
    • 2
    • 3
    • 4

    百度指数并未返回数据,而是提示访问异常访问。经简单检查,现在的请求参数header中增加了Cipher-Text参数,JS逆向大佬可以直接分析js从而正确产生该参数通过校验。

    不过今天我将演示一个非常简单实用的获取百度指数的方案,直接使用seleniumwire来获取数据并解密。

    关于seleniumwire的介绍,可参考我上一篇文章:《selenium对接代理与seleniumwire访问开发者工具NetWork

    实现自动登录百度指数

    由于selenium操作百度指数网页每次都需要登录比较麻烦,我们可以在缓存cookie到本地文件后,每次重启都能自动登录百度。

    自动保存cookie代码:

    from selenium import webdriver
    import time
    
    browser = webdriver.Chrome()
    browser.get("https://index.baidu.com/v2/index.html")
    browser.find_element_by_css_selector("span.username-text").click()
    print("等待登录...")
    while True:
        if browser.find_element_by_css_selector("span.username-text").text != "登录":
            break
        else:
            time.sleep(3)
    print("已登录,现在为您保存cookie...")
    with open('cookie.txt', 'w', encoding='u8') as f:
        json.dump(browser.get_cookies(), f)
    browser.close()
    print("cookie保存完成,游览器已自动退出...")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行以上代码后,会自动打开登录界面,待人工登录后,会自动保存cookie到本地并关闭游览器。

    然后我们以如下方式访问百度指数,即可自动登录:

    from seleniumwire import webdriver
    
    
    browser = webdriver.Chrome()
    with open('cookie.txt', 'r', encoding='u8') as f:
        cookies = json.load(f)
    browser.get('https://index.baidu.com/v2/index.html')
    for cookie in cookies:
        browser.add_cookie(cookie)
    browser.get('https://index.baidu.com/v2/index.html')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    参考:《提取谷歌游览器Cookie的五重境界

    搜索并获取数据

    使游览器执行搜索特定关键字,例如Python:

    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
    wait = WebDriverWait(browser, 30)
    edit = wait.until(EC.presence_of_element_located(
        (By.CSS_SELECTOR, "#search-input-form > input.search-input")))
    print("清空前历史记录数:", len(browser.requests))
    del browser.requests  # 清空历史数据
    edit.send_keys(Keys.CONTROL+'a')
    edit.send_keys(Keys.DELETE)
    edit.send_keys("Python")
    submit = browser.find_element_by_css_selector("span.search-input-cancle")
    submit.click()
    print("清空后再执行搜索后的历史记录数:", len(browser.requests))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    清空前历史记录数: 87
    清空后再执行搜索后的历史记录数: 3
    
    • 1
    • 2

    执行完搜索操作后,我们就可以从游览器缓存中获取数据了:

    import gzip
    import zlib
    import brotli
    import json
    
    
    def auto_decompress(res):
        content_encoding = res.headers["content-encoding"]
        if content_encoding == "gzip":
            res.body = gzip.decompress(res.body)
        elif content_encoding == "deflate":
            res.body = zlib.decompress(res.body)
        elif content_encoding == "br":
            res.body = brotli.decompress(res.body)
    
    
    def fetch_data(rule, encoding="u8", is_json=True):
        result = ""
        for request in reversed(browser.requests):
            if rule in request.url:
                res = request.response
                auto_decompress(res)
                result = res.body.decode(encoding)
                if is_json:
                    result = json.loads(result)
                return result
            
    def decrypt(ptbk, index_data):
        n = len(ptbk)//2
        a = dict(zip(ptbk[:n], ptbk[n:]))
        return "".join([a[s] for s in index_data])
    
    ptbk = fetch_data("Interface/ptbk")['data']
    data = fetch_data("api/SearchApi/index")['data']
    
    for userIndexe in data['userIndexes']:
        name = userIndexe['word'][0]['name']
        index_data = userIndexe['all']['data']
        r = decrypt(ptbk, index_data)
        print(name, r)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    python 21077,21093,21186,19643,14612,13961,21733,21411,21085,21284,18591,13211,12753,27225,20302,19772,20156,17647,12018,11745,19535,19300,20075,20136,18153,12956,12406,17098,16259,18707
    
    • 1

    对比结果后可以看到,数据获取正确。这样我们就可以通过seleniumwire获取百度指数的数据了,若需要获取指定日期范围或指定省份,只需通过selenium模拟人工执行相应的查询操作,再通过游览器后台缓存获取即可。

    多客户端数据的解析可以参考之前《如何用Python下载百度指数的数据》中的代码。

  • 相关阅读:
    管理心得--如何成为优秀的架构师
    2D割草/吸血鬼游戏 性能优化——GPU Spine动画
    舒服,给Spring贡献一波源码。
    HiEngine:可媲美本地的云原生内存数据库引擎
    正则表达式基础
    PL/SQL工具下载地址
    SAP message TK 248 solved
    LeetCode_动态规划_中等_313.超级丑数
    P1596 [USACO10OCT]Lake Counting S——dfs连通块
    域名的命名规则有哪些?
  • 原文地址:https://blog.csdn.net/as604049322/article/details/126040984