🐸 青蛙编程网
首页 / Python / 爬虫 / 2. requests 抓第一个网页

2. requests 抓第一个网页

这是什么:requests 是 Python 最流行的 HTTP 请求库——上一章用标准库 urllib 裸发请求,能跑但啰嗦;requests 把「发请求、带参数、管身份、处理重定向」都做成了顺手的函数,是全世界 Python 爬虫的起点。

为什么用它:爬虫 90% 的时间在和 HTTP 打交道,requests 把 HTTP 请求封装成「调用一个函数、拿到一个响应对象」,r.status_code 是状态码、r.text 是网页文本——你不用关心底层 socket 和编码细节。

如何用:先在虚拟环境里装好,然后按「裸请求 → 带身份 → 带参数 → 稳如老狗」四步升级你的脚本。

装包

按 虚拟环境 venv 的规矩,先建项目环境再装包:

python -m venv .venv
.venv\Scripts\activate        # Windows(macOS/Linux 用 source .venv/bin/activate)
pip install requests

第一步:裸请求

存成 get_quotes.py 运行:

import requests

url = "https://quotes.toscrape.com/"
r = requests.get(url)

print(r.status_code)   # 200
print(r.encoding)      # 服务器声明的编码
print(r.text[:200])    # 网页文本,和上一章 urlopen 的结果一样
属性/方法 作用
r.status_code 状态码,200 才继续干活
r.text 响应文本(自动按编码解码成 str)
r.content 响应字节(下载图片/文件用它)
r.encoding 当前解码用的编码
r.url 实际请求的 URL(跟过重定向之后的)
r.headers 响应头字典
r.raise_for_status() 状态码不是 2xx 就抛异常

第二步:带上浏览器身份(最常翻车的一步)

很多网站会检查「你自称是谁」。requests 默认自称 python-requests/x.x,一秒被认出是爬虫,返回 403。解决:带 User-Agent 请求头,装成浏览器。

import requests

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36"
}
r = requests.get("https://httpbin.org/user-agent", headers=headers, timeout=10)
print(r.json())   # 看看对方收到的 User-Agent 是什么

httpbin.org 是个调试请求的免费服务,你发什么它回显什么——以后想知道「我发出的请求长什么样」,就往它那儿发一发。

第三步:带参数的 GET 与 POST

搜索、翻页、筛选,本质都是「URL 后面挂参数」。别手工拼字符串,交给 params:

import requests

r = requests.get(
    "https://httpbin.org/get",
    params={"page": 2, "keyword": "python 爬虫"},   # 自动拼成 ?page=2&keyword=...
    timeout=10,
)
print(r.url)          # 参数自动 URL 编码,中文也不怕

提交表单(登录、发布)用 POST,数据放 data(表单)或 json(JSON 接口):

requests.post("https://httpbin.org/post", data={"username": "frog"}, timeout=10)

第四步:稳如老狗的三件套

线上跑的爬虫一定会遇到断网、超时、404——把这三件套写进肌肉记忆:

import requests
import time

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/126.0"}

def fetch(url, session=None, retries=3):
    s = session or requests.Session()   # Session:自动复用连接、记住 Cookie
    for i in range(retries):
        try:
            r = s.get(url, headers=headers, timeout=10)
            r.raise_for_status()        # 404/500 直接抛异常,不返回坏数据
            return r.text
        except requests.RequestException as e:
            print(f"第 {i + 1} 次失败:{e},{2 ** i} 秒后重试")
            time.sleep(2 ** i)          # 指数退避:2s、4s、8s
    return None

html = fetch("https://quotes.toscrape.com/")
if html:
    print(f"抓到了,长度 {len(html)}")
三件套 作用
timeout=10 10 秒没响应就报错,绝不傻等(不写默认永久等!)
raise_for_status() 把 404/500 变成异常,逼你处理,而不是拿空数据往下跑
try + 重试 + 退避 偶发失败自动再试,越失败等越久

Session 是什么:requests.Session() 是一个「会话」对象,多个请求共用一条 TCP 连接(更快),并且自动保留服务器给的 Cookie(登录态就靠它)。正式项目请全程用 Session。

下载一张图片练手

r.content 是字节,直接写文件:

import requests

r = requests.get("https://quotes.toscrape.com/favicon.ico", timeout=10)
r.raise_for_status()
open("favicon.ico", "wb").write(r.content)   # 注意是 "wb" 二进制模式
print("下载完成")

常见翻车现场

症状 原因 修复
r.text 中文全是乱码 服务器没声明编码,requests 猜错了 r.encoding = "utf-8" 后再取 r.text
403 Forbidden 没带 User-Agent / 被 Cookie 检查拦截 配 headers;需要登录态用 Session
卡住不动几十秒 没写 timeout,连接黑洞 永远写 timeout=10
SSLError 证书问题 公司代理/旧系统证书过期 先排查环境,别急着 verify=False 关校验
ConnectionError 断网、域名拼错、对方挂了 try/except 接住 + 重试三件套

动手改

  1. 给 fetch() 换个 URL 抓 Python 基础教程 的页面,打印长度对比哪个页面更大
  2. 把 timeout=10 改成 timeout=0.01,体验一下必然超时的报错长什么样
  3. 用 params={"page": 3} 请求 https://quotes.toscrape.com/page/3/,确认和直接写完整 URL 效果一致

上一章:爬虫是什么 · 下一章:解析 HTML 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。