写爬虫这个话题,我一直觉得网上大多数教程都走歪了——上来就甩一段 requests + BeautifulSoup 的代码,然后告诉你"复制就能跑"。结果你复制完,要么跑不出数据,要么被对方网站拒绝访问,要么连为什么这样写都说不清楚。我做了几年 Web 自动化相关的工作,日常跟各种网页、接口、反爬机制打交道,踩过不少坑。这篇就当作一次系统性的基础复盘,不讲虚的,只讲真正会用到的东西。
先说清楚"爬虫基础"到底要解决什么问题。一句话概括:用程序代替人工,批量、自动地从网页里提取结构化数据。你要么在给数据分析攒料,要么在做舆情监控,要么在搭自己的信息聚合工具,要么就是想验证某个页面下的某种变化。不管需求是什么,核心链路都一样:请求页面 → 拿到内容 → 解析数据 → 存储落地 → 应对异常。这篇文章会沿着这条链路,把每一环的底层逻辑和实操细节掰开讲,并且专门补上"静态页面和动态页面"这条分水岭——因为很多初学者正是在这里卡住的。
无论你是想入门 Python 爬虫,还是已经在用 Selenium 做 Web 自动化却对"为什么这样写"没有底,这篇都适用。我会尽量用"为什么这么做"的视角来讲,而不是只给结果。毕竟,爬虫这东西,知其然不知其所以然,遇到问题根本无从下手。
1. 爬虫的本质:从“模拟浏览器”到“理解网页数据”
1.1 爬虫到底在爬什么:先弄懂 HTTP 请求与响应
很多人第一次写爬虫,脑子里想的都是"怎么写代码",但真正要解决的第一步是:你的程序怎么跟目标网站对话。这个对话就是 HTTP 协议。
你可以把浏览器访问网页想象成你去餐厅点菜。你(客户端)拿着菜单说"我要一份宫保鸡丁",厨房(服务器)做完之后把菜端到你面前。HTTP 请求就是你的"点菜动作",HTTP 响应就是"端上来的菜"。爬虫要做的,就是跳过人坐在餐厅里这个环节,让程序自己拿着菜单去点菜,然后把端上来的菜直接放到自己的盘子里。
在实际代码里,一次最简单的 HTTP 请求是什么样?用 Python 的 requests 库,几行就能跑通:
python复制import requests
resp = requests.get("https://example.com")
print(resp.status_code) # 200 表示请求成功
print(resp.text[:500]) # 打印 HTML 前 500 个字符
这段代码里,resp.status_code 就是服务器返回的状态码,resp.text 就是网页源码。但注意,requests 拿到的东西,和你在浏览器里"看到"的东西不是一回事。你在浏览器里看到的排版、图片、按钮,都是浏览器基于 HTML、CSS、JavaScript 渲染之后的结果;而 requests 拿到的,只是原始的 HTML 文本。这就是后面静态页面和动态页面岔路口的起点。
1.2 状态码、请求头与常用方法
爬虫基础里,有几个 HTTP 概念必须烂熟于心。
状态码最常见的就是这几类:
| 状态码 | 含义 | 爬虫常见场景 |
|---|---|---|
| 200 | 请求成功 | 正常拿到页面 |
| 301/302 | 重定向 | 服务器把请求转到了另一个地址 |
| 403 | 禁止访问 | 大概率被反爬拦截了 |
| 404 | 不存在 | 路径写错了 |
| 429 | 请求过多 | 触发频率限制 |
| 500/502/503 | 服务器错误 | 服务器本身出问题了 |
请求头是爬虫最容易忽视、却也最容易被反爬卡住的地方。其中最重要的是 User-Agent(用户代理)和 Cookie。
- User-Agent:告诉服务器"你是什么浏览器"。很多网站会判断 UA,如果发现你不是一个常见浏览器而是一段 Python 脚本,直接拒绝响应。
- Cookie:相当于你的"通行证",服务器用它识别会话状态。登录后的网站,很多时候只有带上 Cookie 才能访问到真实数据。
一个更接近真实场景的请求,通常长这样:
python复制headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9",
}
resp = requests.get("https://example.com", headers=headers, timeout=10)
timeout=10 是很多人一开始会漏掉的参数。没有超时设置,一旦目标服务器迟迟不响应,你的爬虫会一直挂在那里,看起来像"死机"了一样。所以我会习惯性地给每个请求都加上超时时间。
1.3 页面渲染方式:决定你用什么方案的关键因素
网页内容的产生方式,大致可以分成两类。
静态页面:服务器直接把 HTML 传给你,你要的内容就在 HTML 里面。这种页面用 requests 就能搞定,解析起来也简单,用正则、XPath、CSS 选择器都行。
动态页面:服务器传给你的 HTML 只是一个空壳,真正的内容是 JavaScript 在浏览器里运行时,再向后端接口请求数据,然后动态渲染出来的。这种页面的典型特征就是:你用 requests 拿到 HTML,搜索结果里根本找不到你要的数据,或者只有一堆 <script> 标签和空的 div 节点。
怎么判断一个页面是静态还是动态?很简单,在浏览器里右键"查看网页源代码",然后 Ctrl+F 搜索目标内容。如果在源码里搜得到,说明是静态;搜不到,说明是动态。这个方法对初学者来说是最直观的验证手段。
动态页面的爬取方式有两种思路:
- 找到它背后的真实接口,直接请求接口拿 JSON 数据——这是最高效、最稳定的方式。
- 用 Selenium 之类的 Web 自动化工具,启动一个真实浏览器,让页面自己渲染完,然后再去读取渲染后的内容——这是最通用的兜底方案。
这就是我为什么说"爬虫基础"和"Web 自动化"是天然相关的话题。爬虫不一定要用 Selenium,但当你遇到动态页面时,Selenium 往往才是能让你顺利收工的那把刀。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工具选型与基础环境:requests、BeautifulSoup、lxml、Selenium 怎么选
2.1 Python 环境与库的定位
学爬虫,绕不开几个库。但很多人一开始就被"到底该学哪个"搞晕了。我的建议是:没有人只用一个库,不同环节用不同工具,组合起来才是常态。
| 库 | 定位 | 适用场景 |
|---|---|---|
| requests | 发 HTTP 请求 | 绝大部分请求环节 |
| httpx | requests 的现代替代品 | 需要异步、 |
