Python轻松爬取JSON数据:从入门到实践
在数据驱动的时代,JSON(JavaScript Object Notation)因其轻量、易读和结构化的特点,成为Web数据交换的主流格式之一,无论是API接口返回的数据、网页内嵌的动态内容,还是配置文件,JSON都无处不在,用Python爬取JSON数据,是数据采集、分析和处理的基础技能,本文将带你从零开始,一步步了解Python爬取JSON数据的完整流程,包括环境准备、请求发送、数据解析及常见问题解决。
准备工作:安装必要的库
Python爬取JSON数据主要依赖两个核心库:
- requests:用于发送HTTP请求,从目标URL获取JSON数据。
- json:Python内置库,用于解析JSON数据,将其转换为Python字典或列表。
如果尚未安装requests,可通过pip安装:
pip install requests
json库无需额外安装,Python自带。
Python爬取JSON数据的完整流程
确定目标JSON数据的来源
JSON数据的来源通常有两种:
- 直接API接口:许多网站提供API接口,返回纯JSON数据(如天气API、数据开放平台等)。
- 网页内嵌JSON:部分网页通过JavaScript动态加载JSON数据,可能隐藏在HTML的
<script>标签或XHR请求中。
示例目标:以“和风天气API”为例(假设接口为https://api.qweather.com/v7/weather/now?location=101010100&key=YOUR_API_KEY,返回JSON格式的实时天气数据)。
发送HTTP请求获取JSON数据
使用requests库的get()或post()方法向目标URL发送请求,获取响应内容。
基础请求示例:
import requests
# 目标URL(需替换为实际接口地址)
url = "https://api.qweather.com/v7/weather/now?location=101010100&key=YOUR_API_KEY"
# 发送GET请求
response = requests.get(url)
# 检查请求是否成功(状态码200表示成功)
if response.status_code == 200:
print("请求成功!")
print("原始响应内容(JSON字符串):")
print(response.text) # 输出JSON格式的字符串
else:
print(f"请求失败,状态码:{response.status_code}")
关键参数说明:
- headers:设置请求头,模拟浏览器访问(避免被网站拦截)。
headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" } response = requests.get(url, headers=headers) - params:传递URL查询参数(如上述API的
location和key)。 - timeout:设置超时时间(单位:秒),避免请求卡死:
response = requests.get(url, timeout=10)
解析JSON数据
requests响应对象的text属性返回的是JSON格式的字符串,需通过json库解析为Python对象(字典或列表)。
解析步骤:
import json
# 假设response是上一步的请求响应
json_data = response.json() # 直接调用.json()方法解析
# 解析后为Python字典,可通过键访问数据
print("解析后的Python字典:")
print(json_data)
# 提取具体字段(根据实际JSON结构调整)
if "now" in json_data:
temperature = json_data["now"]["temp"] # 温度
weather_text = json_data["now"]["text"] # 天气状况
print(f"当前温度:{temperature}℃")
print(f"天气状况:{weather_text}")
JSON与Python对象的对应关系:
| JSON类型 | Python类型 |
|---|---|
| 对象() | 字典(dict) |
数组([]) |
列表(list) |
| 字符串() | 字符串(str) |
| 数字 | 整数/浮点数(int/float) |
| 布尔值 | 布尔值(True/False) |
| null | None |
处理复杂JSON结构
如果JSON数据包含嵌套对象或数组,需逐层解析,假设JSON结构如下:
{
"code": "200",
"now": {
"temp": "25",
"text": "晴",
"wind": {
"speed": "12",
"dir": "东北风"
}
},
"forecast": [
{"date": "2023-10-01", "temp_max": "28", "temp_min": "18"},
{"date": "2023-10-02", "temp_max": "30", "temp_min": "20"}
]
}
解析嵌套数据:
json_data = response.json()
wind_speed = json_data["now"]["wind"]["speed"] # 提取风速
forecast_dates = [day["date"] for day in json_data["forecast"]] # 提取预报日期列表
print(f"风速:{wind_speed} km/h")
print(f"未来2天日期:{forecast_dates}")
保存JSON数据到本地文件
解析后的数据可直接保存为.json文件,方便后续使用:
import json
# 将Python字典保存为JSON文件
with open("weather_data.json", "w", encoding="utf-8") as f:
json.dump(json_data, f, ensure_ascii=False, indent=4) # ensure_ascii=False支持中文,indent=4格式化缩进
print("JSON数据已保存到weather_data.json")
读取本地JSON文件:
with open("weather_data.json", "r", encoding="utf-8") as f:
loaded_data = json.load(f) # 从文件加载JSON数据
print(loaded_data)
常见问题与解决方案
请求被拒绝(403错误)
原因:网站检测到非浏览器访问或缺少必要参数(如API密钥)。
解决:
- 添加
headers模拟浏览器(如User-Agent)。 - 检查API接口是否需要密钥、参数是否正确传递。
JSON解析失败(json.JSONDecodeError)
原因不是有效的JSON格式(如HTML错误页面、重定向页面)。
解决:
- 检查
response.status_code,确保请求成功(状态码200)。 - 打印
response.text,查看实际返回内容是否为JSON。 - 使用
try-except捕获异常:try: json_data = response.json() except json.JSONDecodeError: print("JSON解析失败,响应内容:", response.text)
处理动态加载的JSON数据
场景:部分网页通过JavaScript动态加载JSON数据,直接请求API接口可能无法获取。
解决:
- 使用浏览器开发者工具(F12)的“Network”选项卡,找到XHR请求,复制真实的API地址。
- 若需模拟浏览器渲染,可结合
selenium或playwright等自动化工具(需额外安装库)。
大量数据分页或限流
场景:API返回数据量过大,需分页请求;或请求频率过高被限制。
解决:
- 查看API文档,确认分页参数(如
page、per_page)。 - 添加延时(如
time.sleep(1)),避免请求过快:import time for page in range(1, 6): url = f"https://api.example.com/data?page={page}" response = requests.get(url) data = response.json() # 处理数据... time.sleep(2) # 每次请求间隔2秒
实战案例:爬取知乎热榜JSON数据
以知乎热榜为例(实际接口需通过浏览器开发者工具获取,此处为模拟):
import requests
import json
# 知乎热榜API(模拟地址,实际需替换为真实接口)
url = "https://www.zhihu.com/api/v3/feed/topstory/hot-lists/total?limit=20"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.


还没有评论,来说两句吧...