Python HTTP 请求入门

一、程序怎么和外界通信

你的 Python 脚本  ──HTTP 请求──▶  远程服务器(API)
                 ◀──HTTP 响应──   返回 JSON / 文本

二、requests 入门

安装 requests

requests 是 Python 最常用的 HTTP 库,语法简单

项目根目录下,先激活虚拟环境,再安装:

cd D:\test\python_study
python -m venv .venv
.venv\Scripts\activate
pip install requests

验证:

python -c "import requests; print(requests.__version__)"
第 1 行:python -m venv .venv

作用:创建虚拟环境

部分 含义
python 调用系统里的 Python
-m venv 以模块方式运行 venv(Python 自带的虚拟环境工具)
.venv 在当前目录下创建名为 .venv 的文件夹

执行后会在项目根目录生成 .venv/,里面有独立的 Python 和 pip,依赖只装在这个项目里,不影响系统全局 Python。
类比前端: 类似在项目里初始化一个独立的依赖空间(类似有独立 node_modules 的项目环境),而不是用全局安装的包。

第 2 行:.venv\Scripts\activate

作用:激活虚拟环境

执行后,当前终端会「切换」到 .venv 里的 Python 和 pip。成功后提示符前会出现 (.venv)`,例如:

(.venv) PS D:\test\python_study>
第 3 行:pip install requests

作用:在当前环境里安装 requests 这个第三方包

部分 含义
pip Python 的包管理器(类似前端的 npm / pnpm)
install 安装依赖(类似 npm install)
requests 要安装的包名,用来发 HTTP 请求

前提是你已经激活了虚拟环境(提示符里有 (.venv)),这样包装进项目的 .venv,不会污染全局 Python。

GET 请求的两种传参

类型 写法 例子
路径参数 写在 URL 路径里 /posts/1/api/voi/123
查询参数 写在 ? 后面(Query String) /posts?userId=1

前端路由里的 params(如 /api/voi/:id)指的是路径参数;Python requests 里的 params= 指的是查询参数,不要混用。

路径参数:直接拼进 URL

post_id = 1
response = requests.get(f"https://jsonplaceholder.typicode.com/posts/{post_id}")
data = response.json()  # 返回 dict,id=1 的那篇文章

查询参数:URL 后面加 ?key=value

https://jsonplaceholder.typicode.com/posts?userId=1

params= 传查询参数,更清晰:

response = requests.get(
    "https://jsonplaceholder.typicode.com/posts",
    params={"userId": 1},
)
print(response.url)   # 看最终拼好的 URL
data = response.json()  # 返回 list,该用户的所有帖子

推荐的公开测试 API

本课用 JSONPlaceholder — 免费、稳定、无需 API Key:

端点 说明
GET /posts/1 获取 id=1 的文章(返回 dict)
GET /posts?userId=1 获取 userId=1 的所有文章(返回 list)
GET /users/1 获取 id=1 的用户信息

常见错误

错误 原因
ModuleNotFoundError: No module named ‘requests’ 没安装或虚拟环境没激活
ConnectionError 网络不通或 URL 写错
KeyError JSON 字段名写错,先用 print(data) 看结构
不检查 status_code 直接用 .json() 404/500 时可能解析失败

三、POST 请求

发 POST 的几种方式

# 方式 1:发 JSON(推荐,API 最常用)
# json= 会自动做两件事:把 dict 转成 JSON 字符串,并设置 Content-Type: application/json。
requests.post(url, json={"key": "value"})

# 方式 2:手动发 JSON 字符串(需自己设 Content-Type)
# 用 data= 传字符串时,requests 默认是 application/x-www-form-urlencoded(表单编码),需手动设为 JSON。
requests.post(url, data='{"key": "value"}', headers={"Content-Type": "application/json"})

# 方式 3:纯文本
requests.post(url, data='hello world', headers={"Content-Type": "text/plain"})

# 方式 4:表单字段(data 传 dict 时常见)
requests.post(url, data={"key": "value"})  # 默认 application/x-www-form-urlencoded

Header(请求头 / 响应头)

Header 是请求的「元信息」,键值对形式。

常见请求头
Header 作用 例子
Content-Type Body 是什么格式 application/json
Authorization 身份认证 Bearer sk-xxxx(LLM API 常用)
User-Agent 客户端是谁 MyApp/1.0
在 requests 里设置 Header
headers = {"User-Agent": "PythonStudy/1.0"}
response = requests.get(url, headers=headers)
看响应头
print(response.headers)                    # 全部响应头
print(response.headers.get("Content-Type"))  # 常见:application/json; charset=utf-8

HTTP 状态码

状态码 含义 你该怎么想
200 OK,成功 正常处理 response.json()
201 Created,创建成功 POST 创建资源时常见
400 Bad Request,请求有误 检查 Body、参数格式
401 Unauthorized,未授权 缺 API Key 或 Key 无效
404 Not Found,找不到 URL 或 id 写错(你测过 99990)
500 Internal Server Error 服务器内部错误

通过 response.status_code 读取。

读响应体

response.text       # 字符串(原始文本)
response.json()     # 解析成 dict/list(前提是 JSON)
response.content    # 二进制 bytes(图片等)

对象属性 和 字典键 的区别

response                    ← httpx.Response 对象
├── status_code             ← 对象的属性(int)
├── headers                 ← 对象的属性(Headers 映射)
│   └── "Content-Type"      ← headers 里的一个键(字符串)
└── ...

四、httpx — API(支持 async/await:)

安装 httpx

环境同上,pip install httpx

保存二进制文件

文本用 write_text(),图片用 write_bytes():

from pathlib import Path

path = Path("downloads/cat.jpg")
path.parent.mkdir(parents=True, exist_ok=True)  # 确保目录存在
path.write_bytes(response.content)             # 写入二进制
parents=True

自动创建路径上所有缺失的上级目录。
比如:会依次创建:a → a/b → a/b/c。
如果 parents=False(默认),中间缺一层就会报错。

exist_ok=True

目录已经存在时不报错。

exist_ok=False(默认):目录已存在 → 抛 FileExistsError
exist_ok=True:目录已存在 → 静默跳过
常见组合就是「缺啥建啥,有了也不报错」。

httpx 异步下载一张图

import httpx

async def download_image(url: str, save_path: Path) -> bool:
    async with httpx.AsyncClient(timeout=30.0) as client:
        response = await client.get(url)
        if response.status_code == 200:
            save_path.write_bytes(response.content)
            return True
    return False

response.content 是 bytes 类型,正好对应图片二进制数据。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐