如何在Python中下载JSON数据:从基础到实践
在Python开发中,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,被广泛应用于API响应、配置文件和数据存储场景,如何在Python中下载JSON数据是开发者必备的基础技能,本文将从基础到实践,详细介绍多种下载JSON数据的方法,包括使用标准库、第三方库以及处理常见问题的技巧。
使用标准库urllib:Python内置的HTTP工具
Python标准库中的urllib模块提供了处理URL的基本功能,无需额外安装即可实现JSON数据下载,核心步骤包括:发送HTTP请求、读取响应数据、解析JSON。
基本用法:GET请求获取JSON
假设我们要从公开API(如JSONPlaceholder示例API)获取JSON数据,可以使用urllib.request模块发送GET请求:
import urllib.request
import json
# 目标API URL(示例:获取单个用户信息)
url = "https://jsonplaceholder.typicode.com/users/1"
try:
# 发送GET请求,获取响应对象
with urllib.request.urlopen(url) as response:
# 读取响应数据(字节流)
data = response.read()
# 将字节流解码为字符串(默认UTF-8)
json_str = data.decode('utf-8')
# 解析JSON字符串为Python字典
json_data = json.loads(json_str)
# 打印解析后的数据
print(json_data)
except urllib.error.URLError as e:
print(f"请求失败: {e.reason}")
except json.JSONDecodeError as e:
print(f"JSON解析失败: {e}")
关键点说明:
urllib.request.urlopen()发送请求,返回的response对象支持上下文管理(with语句),确保资源自动释放。response.read()获取原始字节流,需通过decode()解码为字符串(若API返回非UTF-8编码,需指定编码格式,如decode('gbk'))。json.loads()将JSON字符串转换为Python字典/列表,若字符串格式不合法会抛出JSONDecodeError。
处理HTTPS与请求头
部分API需要HTTPS协议或自定义请求头(如模拟浏览器访问),可通过urllib.request.Request实现:
import urllib.request
import json
url = "https://api.github.com/users/python"
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"
}
# 创建Request对象,添加请求头
request = urllib.request.Request(url, headers=headers)
try:
with urllib.request.urlopen(request) as response:
data = json.loads(response.read().decode('utf-8'))
print(f"用户名: {data['name']}, 公共仓库数: {data['public_repos']}")
except Exception as e:
print(f"请求失败: {e}")
注意:GitHub API要求设置User-Agent,否则可能返回403错误。
使用第三方库requests:更简洁的HTTP请求
requests是Python中最流行的HTTP库,相比urllib,它提供了更简洁的API和更强大的功能(如会话管理、文件上传、自动解码等)。
安装requests
若未安装,可通过pip安装:
pip install requests
基本GET请求获取JSON
使用requests.get()发送请求,并通过response.json()方法直接解析JSON(无需手动解码和解析):
import requests
url = "https://jsonplaceholder.typicode.com/users/1"
try:
# 发送GET请求,timeout设置超时时间(秒)
response = requests.get(url, timeout=5)
# 检查HTTP状态码(200表示成功)
response.raise_for_status() # 非200状态码会抛出HTTPError
# 直接解析JSON为Python字典
json_data = response.json()
print(json_data)
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
优势:
response.json()自动处理响应编码(根据Content-Type头判断),无需手动decode()。raise_for_status()在状态码非2xx时抛出异常,简化错误处理。- 支持超时设置(
timeout参数),避免请求长时间阻塞。
处理复杂请求:参数、请求头与POST请求
若API需要查询参数或自定义请求头,可通过params和headers参数传递:
import requests
# 带参数的GET请求(获取ID为1和2的用户)
url = "https://jsonplaceholder.typicode.com/users"
params = {"id": [1, 2]} # 查询参数
headers = {"Accept": "application/json"}
try:
response = requests.get(url, params=params, headers=headers, timeout=5)
response.raise_for_status()
json_data = response.json()
print(json_data)
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
POST请求示例(向API提交JSON数据):
import requests
import json
url = "https://jsonplaceholder.typicode.com/posts"
data = {: "测试标题",
"body": "测试内容",
"userId": 1
}
headers = {"Content-Type": "application/json"}
try:
# 发送POST请求,data需转换为JSON字符串
response = requests.post(url, data=json.dumps(data), headers=headers, timeout=5)
response.raise_for_status()
print("响应数据:", response.json())
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
注意:POST请求中,若直接传递字典给data参数,requests会自动编码为application/x-www-form-urlencoded格式;若需发送JSON数据,需用json.dumps()转换为字符串并设置Content-Type: application/json。
处理JSON数据中的常见问题
大文件下载与流式处理
若JSON数据较大(如GB级别),直接读取可能导致内存溢出,可通过流式处理逐块读取:
import requests
url = "https://example.com/large_data.json"
try:
with requests.get(url, stream=True) as response:
response.raise_for_status()
# 流式写入文件,避免内存堆积
with open("large_data.json", "w", encoding="utf-8") as f:
for chunk in response.iter_content(chunk_size=8192): # 每次读取8KB
# chunk是字节流,需解码为字符串
f.write(chunk.decode("utf-8"))
print("大文件下载完成")
except requests.exceptions.RequestException as e:
print(f"下载失败: {e}")
错误处理与重试机制
网络请求可能因超时、连接失败等问题中断,可通过try-except捕获异常并结合重试机制提高稳定性:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# 创建会话,配置重试策略
session = requests.Session()
retry = Retry(
total=3, # 最大重试次数
backoff_factor=1, # 重试间隔(指数退避)
status_forcelist=[500, 502, 503, 504] # 需重试的HTTP状态码
)
adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)
url = "https://jsonplaceholder.typicode.com/users/1"
try:
response = session.get(url, timeout=5)
response.raise_for_status()
print(response.json())
except requests.exceptions.RequestException as e:
print(f"请求失败(已重试): {e}")
处理非UTF-8编码的JSON
若API返回的JSON数据编码非UTF-8(如GBK),可通过response.encoding手动指定:
import requests
url = "https://example.com/gbk_data.json"
try:
response = requests.get(url, timeout=5)
response.encoding = "gbk" # 手动指定编码
response.raise_for_status()
print(response.json())
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
如何选择合适的方法?
| 场景 | 推荐方法 | 优点 | 缺点 |
|---|---|---|---|
| 简单JSON下载 | urllib(标准库) |
无需安装,适合轻量级任务 | API较繁琐,需手动处理编码和异常 |
| 复杂HTTP请求 | requests(第三方库) |



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