网页爬取遇复杂请求头问题:复制头仅短时有效如何解决?
解决动态请求头导致的爬虫失效问题
1. 定位动态变化的字段
先对比多次请求的请求头,筛选出核心动态项:
- 从你提供的请求头来看,
enc_data、timestamp、if-modified-since、if-none-match以及cookie中的部分值是导致请求失效的关键,其余如accept、user-agent等属于静态通用字段,无需频繁修改。 - 优先验证
timestamp:它大概率是当前Unix时间戳,可通过int(time.time())生成字符串形式的对应值,替换硬编码内容后测试请求是否恢复有效。
2. 破解enc_data的生成逻辑
enc_data是核心加密字段,需从网站前端代码中挖掘生成规则:
- 打开浏览器开发者工具的Sources面板,搜索
enc_data关键词,定位到请求发送前的加密逻辑代码(通常在某个JS文件中)。 - 分析加密算法:常见的是基于
timestamp、client_id、cookie中的特定值进行HMAC、MD5或自定义哈希运算,部分网站还会加入固定密钥。 - 将JS加密逻辑翻译成Python代码,比如如果是HMAC-SHA256加密,可使用Python的
hmac和hashlib库实现:import hmac import hashlib import base64 secret_key = "从JS代码中提取的加密密钥" raw_data = f"{timestamp}{client_id}{cookie_value}" # 按JS中的拼接规则组合参数 enc_data = hmac.new(secret_key.encode(), raw_data.encode(), hashlib.sha256).digest() enc_data = base64.b64encode(enc_data).decode()
3. 用Session自动管理会话状态
硬编码cookie容易过期,改用requests.Session可自动维持会话,获取最新的cookie:
import requests import time session = requests.Session() # 先访问网站首页或搜索页,获取初始会话cookie session.get("https://www.some-website.com") # 生成动态字段 timestamp = str(int(time.time())) client_id = "ffoesvm90e-6323-4asdac-a349-e78acdd2de60" # 若client_id动态,从页面源码或响应头提取 # 此处插入上面生成enc_data的代码 headers = { "accept": "application/json, text/plain, */*", "accept-encoding": "gzip, deflate, br", "accept-language": "en-GB,en-US;q=0.9,en;q=0.8", "client_id": client_id, "enc_data": enc_data, "timestamp": timestamp, "referer": "https://www.some-website.com/search?query=cholera", "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36" } # 发起请求 response = session.get( "https://www.some-website.com/kapi/secure/search-api?query=cholera&page=1", headers=headers ) print(response.json())
4. 替代方案:模拟真实浏览器请求
如果难以破解加密逻辑,直接用浏览器自动化工具(如Selenium、Playwright)模拟真实用户操作,自动处理所有动态请求头和会话:
from selenium import webdriver from selenium.webdriver.common.by import By import time driver = webdriver.Chrome() # 打开搜索页面,浏览器会自动处理所有动态参数 driver.get("https://www.some-website.com/search?query=cholera") time.sleep(2) # 等待页面加载完成 # 可直接从页面提取数据,或通过DevTools拦截API响应 results = driver.find_elements(By.CSS_SELECTOR, ".search-result-item") for result in results: print(result.text) driver.quit()
内容的提问来源于stack exchange,提问作者Mritunjay Prasad
相关产品推荐
相关产品推荐

