系列文章

Python 从入门到精通

第 25 / 36 篇

从环境安装和基础语法出发,逐步学习工程实践、自动化、数据处理与 Web 开发。

  1. 01
    Python 怎么装、怎么用
  2. 02
    变量、数字和字符串
  3. 03
    列表:把一组数据放在一起
  4. 04
    元组、集合和字典
  5. 05
    条件判断:让程序做选择
  6. 06
    循环:重复的事交给程序
  7. 07
    函数:把代码整理成可复用的块
  8. 08
    模块与包:拆分你的程序
  9. 09
    输入、输出与字符串格式化
  10. 10
    文件读写:保存程序的数据
  11. 11
    异常处理:程序出错时怎么办
  12. 12
    基础阶段练习:命令行记账本
  13. 13
    类和对象:面向对象入门
  14. 14
    继承、组合与特殊方法
  15. 15
    迭代器与生成器
  16. 16
    列表推导式与生成器表达式
  17. 17
    装饰器:给函数增加能力
  18. 18
    上下文管理器与 with
  19. 19
    类型标注与 dataclass
  20. 20
    正则表达式:从文本中找规律
  21. 21
    日期、时间与时区
  22. 22
    日志与调试
  23. 23
    虚拟环境与依赖管理
  24. 24
    测试:让修改不再提心吊胆
  25. 25
    网络请求:用 Python 调用 API正在阅读
  26. 26
    网页解析与合规采集
  27. 27
    操作 Excel、CSV 与批量文件
  28. 28
    SQLite:给程序加一个数据库
  29. 29
    数据分析入门:NumPy 与 Pandas
  30. 30
    画图:把数据变得直观
  31. 31
    Flask 入门:做一个小网站
  32. 32
    异步编程:同时处理多项任务
  33. 33
    线程、进程与并发选择
  34. 34
    性能分析与优化
  35. 35
    项目结构、配置与发布
  36. 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 /usersPOST /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、认证、端点、参数与返回

练习

  1. 用 wttr.in 或任意公开 API 写一个”城市天气”命令行工具,支持输入城市名
  2. 请求一个公开 API(如 httpbin.org/get),带上自定义参数和 header,打印返回的 JSON
  3. 思考:为什么 requests 的 raise_for_status() 值得每次调用?如果忽略 404/500 继续处理响应,会发生什么?