如何通过关键词爬取ScienceDirect数据?解决乱码与JSON解析报错
问题:爬取ScienceDirect AJAX接口返回乱码,JSON解析失败
我想通过关键词爬取ScienceDirect平台的全部数据,已知该平台采用AJAX技术加载数据,无法直接从搜索结果页面URL提取数据。我在浏览器Network面板找到了返回JSON数据的请求接口,但调用该接口时返回乱码,尝试解析JSON时直接报错。
我的代码如下:
import requests as res import json from bs4 import BeautifulSoup keyword="digital game" url = 'https://www.sciencedirect.com/search/api?' payload = { 'tak': keyword, 't': 'ZNS1ixW4GGlMjTKbRHccgZ2dHuMVHqLqNBwYzIZayNb8FZvZFnVnLBYUCU%2FfHTxZMgwoaQmcp%2Foemth5%2FnqtM%2BGQW3NGOv%2FI0ng6yDADzynQO66j9EPEGT0aClusSwPFvKdDbfVcomCzYflUlyb3MA%3D%3D', 'hostname': 'www.sciencedirect.com' } r = res.get(url, params = payload) print(r.content) # 返回乱码 r = r.json() print(r) # 解析报错
相关截图说明:
- 目标爬取页面:显示ScienceDirect关键词“digital game”的搜索结果列表
- 包含JSON数据的请求:浏览器Network面板中记录的AJAX请求详情
- 返回乱码截图:控制台打印的响应内容为乱码字符
- JSON解析报错截图:提示JSON格式错误的解析异常信息
解决方案
1. 补充必要的请求头
ScienceDirect会验证请求合法性,缺失关键头信息会导致响应被加密或拒绝。必须添加以下核心请求头:
User-Agent:模拟真实浏览器标识,示例值:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36Accept:指定接受的响应格式,设置为application/json, text/plain, */*Cookie:从浏览器登录ScienceDirect后的请求中复制有效Cookie,包含会话验证和权限信息,未登录状态下无法获取完整数据
修改后的请求头示例:
headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Accept': 'application/json, text/plain, */*', 'Cookie': '替换为浏览器中复制的有效Cookie字符串' }
2. 动态获取t参数
你代码中的t参数是动态生成的会话令牌,有效期极短,页面刷新或会话过期后会失效,硬编码固定值必然导致请求失败。需要每次请求前从搜索页提取最新的t值:
- 先请求关键词搜索页面
- 解析HTML获取隐藏的
t参数值
示例代码:
# 先请求搜索页获取动态参数 search_url = f'https://www.sciencedirect.com/search?qs={keyword.replace(" ", "%20")}' search_res = res.get(search_url, headers=headers) soup = BeautifulSoup(search_res.text, 'html.parser') # 查找t参数(实际页面结构可能有变化,需根据实际情况调整选择器) t_param = soup.find('input', {'name': 't'})['value'] # 更新payload中的t值 payload['t'] = t_param
3. 确保响应正确解码
如果仍出现乱码,可强制指定编码或让requests自动推断:
# 方法1:让requests自动推断编码 r.encoding = r.apparent_encoding # 方法2:手动用UTF-8解码 decoded_text = r.content.decode('utf-8')
4. 规避反爬限制
ScienceDirect反爬机制严格,需注意:
- 添加随机延迟:每次请求后暂停1-3秒(导入
time和random模块实现) - 避免单一IP高频请求:必要时使用代理IP池
- 保持会话一致性:使用同一
requests.Session()对象发起所有请求,自动维护Cookie
内容的提问来源于stack exchange,提问作者alienDog
相关产品推荐
相关产品推荐

