系列文章
Python 从入门到精通
第 25 / 36 篇
从环境安装和基础语法出发,逐步学习工程实践、自动化、数据处理与 Web 开发。
-
01
Python 怎么装、怎么用 -
02
变量、数字和字符串 -
03
列表:把一组数据放在一起 -
04
元组、集合和字典 -
05
条件判断:让程序做选择 -
06
循环:重复的事交给程序 -
07
函数:把代码整理成可复用的块 -
08
模块与包:拆分你的程序 -
09
输入、输出与字符串格式化 -
10
文件读写:保存程序的数据 -
11
异常处理:程序出错时怎么办 -
12
基础阶段练习:命令行记账本 -
13
类和对象:面向对象入门 -
14
继承、组合与特殊方法 -
15
迭代器与生成器 -
16
列表推导式与生成器表达式 -
17
装饰器:给函数增加能力 -
18
上下文管理器与 with -
19
类型标注与 dataclass -
20
正则表达式:从文本中找规律 -
21
日期、时间与时区 -
22
日志与调试 -
23
虚拟环境与依赖管理 -
24
测试:让修改不再提心吊胆 -
25
网络请求:用 Python 调用 API正在阅读 -
26
网页解析与合规采集 -
27
操作 Excel、CSV 与批量文件 -
28
SQLite:给程序加一个数据库 -
29
数据分析入门:NumPy 与 Pandas -
30
画图:把数据变得直观 -
31
Flask 入门:做一个小网站 -
32
异步编程:同时处理多项任务 -
33
线程、进程与并发选择 -
34
性能分析与优化 -
35
项目结构、配置与发布 -
36
综合项目:从需求到上线
学到这里,你的程序终于可以”联网”了。这一篇讲 Python 里最常用的 HTTP 客户端库 requests——调用 API、抓网页、发数据,全靠它。学完你能写出自己的第一个”调接口”程序。
安装和第一次请求
pip install requests
import requests
resp = requests.get("https://www.nsn0704y.cn")
print(resp.status_code) # 200(状态码)
print(resp.text[:200]) # 响应内容(前 200 字符)
print(resp.url) # 最终 URL(可能被重定向)
状态码含义(背下来):200 成功、301/302 重定向、400 请求错误、401 未认证、403 禁止访问、404 不存在、500 服务器内部错误。
GET 请求带参数
很多 API 用 URL 参数传参(?key=value),用 params 字典最规范:
import requests
# 手动拼:https://api.example.com/search?q=python&page=2 (容易拼错、要转义)
# 规范写法:
resp = requests.get(
"https://api.example.com/search",
params={"q": "python", "page": 2},
)
print(resp.url) # https://api.example.com/search?q=python&page=2
POST 请求:发数据
提交数据(登录、创建资源)用 POST:
import requests
# 发 JSON(现代 API 主流)
resp = requests.post(
"https://api.example.com/users",
json={"name": "南山", "age": 1},
)
print(resp.status_code)
print(resp.json()) # 响应如果是 JSON,直接解析成字典
# 发表单(老式接口)
resp = requests.post(
"https://api.example.com/login",
data={"username": "admin", "password": "123456"},
)
请求头(headers)
有些接口要求带认证信息或标识来源:
import requests
headers = {
"User-Agent": "Mozilla/5.0 (MyApp/1.0)", # 标识你是谁(别伪装成浏览器去爬)
"Authorization": "Bearer your-token-here", # 常见的认证方式
}
resp = requests.get("https://api.example.com/me", headers=headers)
# 响应头也能看
print(resp.headers.get("Content-Type")) # application/json; charset=utf-8
处理 JSON 响应
现代 API 基本都返回 JSON,requests 内置解析:
import requests
resp = requests.get("https://api.github.com/users/octocat")
if resp.status_code == 200:
data = resp.json() # 字典
print(data["login"])
print(data["public_repos"])
else:
print(f"请求失败:{resp.status_code}")
# 更稳的写法
try:
data = resp.json()
except requests.exceptions.JSONDecodeError:
print("响应不是合法 JSON")
超时和错误处理(必做!)
不设超时的请求,遇到网络问题可能卡住几分钟。超时和异常处理是网络代码的标配:
import requests
try:
resp = requests.get("https://api.example.com", timeout=10) # 10 秒超时
resp.raise_for_status() # 状态码 4xx/5xx 时抛异常
except requests.exceptions.Timeout:
print("请求超时")
except requests.exceptions.ConnectionError:
print("网络连接失败")
except requests.exceptions.HTTPError as e:
print(f"HTTP 错误:{e}")
else:
print("成功:", resp.json())
timeout 必填,raise_for_status() 必调——这两行能省掉你无数个不眠夜。
实战:天气查询工具
用公开 API 做个能用的东西(wttr.in 无需 key):
import requests
def get_weather(city):
resp = requests.get(
f"https://wttr.in/{city}",
params={"format": "3", "lang": "zh"},
timeout=10,
)
resp.raise_for_status()
return resp.text.strip()
for city in ["敦化", "长春", "北京"]:
try:
print(get_weather(city)) # get_weather 已含城市名,直接打印
except requests.exceptions.RequestException as e:
print(f"{city}: 获取失败({e})")
输出类似:
敦化: 敦化: ⛅️ +23°C
长春: 长春: ⛅️ +24°C
北京: 北京: ☀️ +30°C
阅读 API 文档的方法
拿到一个陌生 API,先看四样:
- Base URL:所有请求的公共前缀,如
https://api.example.com/v1 - 认证方式:要不要 key/token?放 header 还是参数?
- 端点(endpoint):
GET /users、POST /users……每个端点干什么 - 参数和返回结构:请求要传什么、响应长什么样(JSON 字段)
用 requests 把文档翻译成代码,就是套模板的事。
新手坑
坑 1:不设超时。程序卡死几分钟,用户以为崩了。所有请求都设 timeout。
坑 2:不看状态码直接 .json()。404 页面返回 HTML,.json() 直接抛异常。先检查 status_code 或 raise_for_status。
坑 3:高频无脑请求。写个循环每秒请求 100 次,你的 IP 很快被对方拉黑。控制频率(sleep),遵守对方的 robots.txt 和 API 限额。
小结
requests.get/post,参数用params=/json=/data=/headers=- 响应:
status_code、.text、.json()、.headers - 必做两件事:
timeout=+raise_for_status() - 异常处理:Timeout / ConnectionError / HTTPError
- 看 API 文档四要素:Base URL、认证、端点、参数与返回
练习
- 用 wttr.in 或任意公开 API 写一个”城市天气”命令行工具,支持输入城市名
- 请求一个公开 API(如 httpbin.org/get),带上自定义参数和 header,打印返回的 JSON
- 思考:为什么 requests 的
raise_for_status()值得每次调用?如果忽略 404/500 继续处理响应,会发生什么?