📌 适合人群:完全没有爬虫经验的初学者 🛠️ 涉及工具:Python 3、requests、BeautifulSoup4、浏览器开发者工具 🎯 学习目标:看懂网页本质 → 发送请求 → 解析数据 → 批量爬取
一、爬虫到底是什么?先看大图景
在写任何代码之前,先建立整体认知。所谓网络爬虫 ,本质上是模拟浏览器向服务器发送请求,获取网页内容,然后从中提取我们想要的数据。
整个流程可以拆成三步(这也是几乎所有爬虫的灵魂框架):
plain
① 获取网页内容 ------ 向服务器要数据,服务器把网页"源代码"返回给我们
↓
② 解析网页内容 ------ 从一大堆 HTML 代码里,精准找到想要的数据
↓
③ 存储 / 分析数据 ------ 存成表格(Excel/CSV)、做数据分析、画可视化图表
对应到你的学习笔记,就是:获取 → 解析 → 存储分析。
二、前置知识一:HTTP协议(爬虫的地基)
2.1 什么是HTTP
HTTP(Hypertext Transfer Protocol,超文本传输协议 )是客户端(浏览器)和服务器之间的请求-响应协议。
你每打开一个网页,背后都在发生一次对话:
浏览器:"服务器你好,我要
/movie/top250这个页面的内容" 服务器:"好的,给你(返回网页代码)"
爬虫的第一步,就是用代码代替浏览器去完成这个对话。
2.2 HTTP请求的结构
一个HTTP请求由三部分组成:
(1)请求行
POST /user/info?new_user=true HTTP/1.1
-
POST:请求方法(常见的还有GET) -
/user/info?new_user=true:资源路径 + 查询参数 -
HTTP/1.1:协议版本(还有 0.9、1.0、2.0 等)
(2)请求头(Headers)
Host: www.example.com
User-Agent: curl/7.77.0
Accept: */*
请求头是关于请求的附加信息 。其中 User-Agent(用户代理)告诉服务器"我是谁"。
⚠️ 关键点来了 :如果不加 User-Agent,服务器看到的就是一个"裸奔的程序",很可能直接拒绝你(比如豆瓣会返回 418 错误 )。解决办法是伪装成浏览器:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
(3)请求体(Body)
POST请求通常带有数据(比如登录时提交账号密码),格式常见为 JSON:
{
"username": "zhangsan",
"email": "zhangsan@example.com"
}
2.3 GET 和 POST 的区别(面试高频)
表格
| 对比项 | GET | POST |
|---|---|---|
| 用途 | 获取数据 | 创建/提交数据 |
| 场景 | 浏览网页、翻页 | 提交账号、注册表单 |
| 参数位置 | 拼在URL里(?key=value) |
放在请求体里 |
| 爬虫常用度 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
plain
# GET请求:参数直接写在URL上
www.douban.com/movie/top250?start=75&filter=unwatched
└─────┬─────┘
问号后面就是查询参数
2.4 HTTP响应的结构
服务器返回的响应同样由三部分组成:
HTTP/1.1 200 OK ← 状态行
Date: Fri, 27 Jan 2023 02:10:48 GMT
Content-Type: text/html; charset=utf-8 ← 响应头
<!DOCTYPE html>
<html>
<head><title>首页</title></head>
<body><h1>Hello World</h1></body>
</html> ← 响应体(真正的网页内容)
-
状态行:协议版本 + 状态码 + 状态消息
-
响应头 :比如
Content-Type告诉我们返回内容的格式是text/html -
响应体:就是我们要爬的 HTML 源码
2.5 常见状态码(务必背下来)
| 状态码 | 含义 |
|---|---|
| ✅ 200 OK | 请求成功,最理想 |
| ↪️ 301 Moved Permanently | 资源永久移动到新地址 |
| ⚠️ 400 Bad Request | 客户端请求不能被服务器理解 |
| ⚠️ 401 Unauthorized | 请求未经授权 |
| ⚠️ 403 Forbidden | 服务器拒绝提供服务(反爬常见) |
| ⚠️ 404 Not Found | 请求的资源不存在 |
| ❌ 500 Internal Server Error | 服务器内部错误 |
| ❌ 503 Server Unavailable | 服务器当前无法处理请求 |
在代码中用 response.status_code 查看,用 response.ok 快速判断是否成功(2xx 返回 True)。
三、前置知识二:HTML网页结构(解析的地图)
3.1 网页三大件
| 技术 | 作用 |
|---|---|
| HTML | 定义网页的结构和信息(骨架) |
| CSS | 定义网页的样式(皮肤) |
| JavaScript | 定义网页的行为和交互逻辑(肌肉) |
爬虫主要和 HTML 打交道。
3.2 HTML的基本结构
<html>
<body>
<h1>这是一个标题</h1>
<p>这是一个段落</p>
</body>
</html>
HTML 由一对一对的标签(tag) 组成:<标签名> 开始,</标签名> 结束。<h1> 和 <p> 是兄弟标签(同级关系)。
3.3 常用标签速查
| 标签 | 含义 |
|---|---|
<h1> ~ <h6> |
标题(1最大,6最小) |
<p> |
段落 |
<br> |
换行 |
<i> |
斜体 |
<u> |
下划线 |
<a> |
链接 |
<div> |
区块容器(最常用,页面布局) |
<ul> / <ol> / <li> |
无序列表 / 有序列表 / 列表项 |
<span> |
行内容器(常用来包裹小片段文字) |
<b> / <strong> |
加粗 |
<table> / <tr> / <td> |
表格 / 表格行(table row)/ 单元格 |
<thead> / <tbody> |
表头区 / 表体区 |
以表格为例,完整结构长这样:
<table>
<thead>
<tr>
<td>表头1</td>
<td>表头2</td>
</tr>
</thead>
<tbody>
<tr>
<td>111</td>
<td>222</td>
</tr>
<tr>
<td>333</td>
<td>444</td>
</tr>
</tbody>
</table>
💡 爬虫提数据的核心思路:数据总是藏在某个标签里,我们要做的就是在 HTML 中找到那个标签,把它"抠"出来。
四、实战第一步:requests库获取网页内容
4.1 安装与导入
pip install requests
import requests
4.2 第一个爬虫:获取books.toscrape.com首页
import requests
response = requests.get("http://books.toscrape.com/")
if response.ok:
print(response.text)
else:
print("请求失败")
到这一步,你就已经完成了爬虫流程里的第一步------拿到了网页的源代码(一大串HTML文本)。
4.3 response对象的常用属性
response = requests.get("http://books.toscrape.com/")
print(response) # 打印响应对象本身
print(response.status_code) # 状态码,200表示成功
print(response.text) # 响应体内容(字符串形式)
print(response.headers) # 响应头
print(response.ok) # 是否成功(2xx → True)
4.4 反爬入门:伪装User-Agent
直接爬豆瓣 Top250 会遇到 418("我是茶壶"),说明服务器识破了你:
import requests
response = requests.get("https://movie.douban.com/top250")
print(response) # <Response [418]> 被识破了!
加 headers 伪装成浏览器:
import requests
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
response = requests.get("https://movie.douban.com/top250", headers=headers)
print(response.status_code) # 200,成功!
print(response.text)
🔑 记忆口诀:先不加 headers 试试,不行就加 User-Agent;还不行就检查 Cookie、Referer 等。
五、实战第二步:BeautifulSoup解析网页内容
获取到的 response.text 是一大坨字符串,肉眼找数据是不可能的。我们用 BeautifulSoup 把它变成一个结构化、可查询的对象。
5.1 安装与导入
pip install beautifulsoup4
from bs4 import BeautifulSoup
import requests
5.2 三步走:请求 → 做汤 → 找料
from bs4 import BeautifulSoup
import requests
# 1. 请求网页
content = requests.get("http://books.toscrape.com/").text
# 2. 把字符串"熬成汤"(解析成结构化对象)
soup = BeautifulSoup(content, "html.parser")
经过 BeautifulSoup 处理后,得到的 soup 对象就拥有了非常多的方法和属性,可以像查字典一样查找标签。
5.3 findAll():批量查找标签
# 按标签名查找:找到所有 <p> 标签
all_prices = soup.findAll("p", attrs={"class": "price_color"})
for price in all_prices:
print(price.string[2:])
运行结果:
51.77
53.74
50.10
47.82
54.23
...
逐行拆解这个方法:
-
soup.findAll("p", attrs={"class": "price_color"}):找到所有 class 为price_color的<p>标签,返回一个列表 -
price.string:取标签里的文本内容(如£51.77) -
[2:]:字符串切片 ,去掉前2个字符£,留下纯数字
🔑 注意区分:
find()→ 找第一个,返回单个对象
findAll()→ 找所有,返回列表
5.4 案例:提取书名
在 books.toscrape 上,书名藏在 <h3> 标签里的 <a> 标签中:
<h3>
<a href="catalogue/a-light-in-the-attic_1000/index.html" title="A Light in the Attic">A Light in the ...</a>
</h3>
对应代码:
all_titles = soup.findAll("h3")
for title in all_titles:
all_links = title.findAll("a")
for link in all_links:
print(link.string) # 通过string属性拿到标签内的文本
输出:
A Light in the ...
Tipping the Velvet
Soumission
Sharp Objects
Sapiens: A Brief History ...
...
💡 嵌套查找 是很常用的技巧:先找大容器(h3),再在容器内部继续找小标签(a)。
5.5 案例:爬豆瓣Top250电影名
先在浏览器里右键 → 检查(审查元素),找到标题对应的标签:
<span class="title">三傻大闹宝莱坞</span>
对应代码:
import requests
from bs4 import BeautifulSoup
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
response = requests.get("https://movie.douban.com/top250", headers=headers)
html = response.text
soup = BeautifulSoup(html, "html.parser")
all_titles = soup.findAll("span", attrs={"class": "title"})
for title in all_titles:
title_string = title.string
# 豆瓣每部电影有中文名和英文名两个title,用"/"判断过滤
if "/" not in title_string:
print(title_string)
这里用了一个细节技巧:if "/" not in title_string------因为每部电影的中文名和英文名都是 class="title",通过是否包含 / 来只保留中文名。
六、实战第三步:翻页爬取全部250部电影
豆瓣Top250每页只有25部,URL规律是:
第1页: https://movie.douban.com/top250?start=0
第2页: https://movie.douban.com/top250?start=25
第3页: https://movie.douban.com/top250?start=50
...
规律是 start 每次加 25。用 range(0, 250, 25) 生成翻页参数:
for start_num in range(0, 250, 25):
print(start_num)
# 输出: 0, 25, 50, 75, 100, 125, 150, 175, 200, 225
完整代码:
import requests
from bs4 import BeautifulSoup
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
for start_num in range(0, 250, 25):
response = requests.get(
f"https://movie.douban.com/top250?start={start_num}",
headers=headers
)
html = response.text
soup = BeautifulSoup(html, "html.parser")
all_titles = soup.findAll("span", attrs={"class": "title"})
for title in all_titles:
title_string = title.string
if "/" not in title_string:
print(title_string)
🛡️ 善意提醒 :实际爬取时建议在循环中加入
time.sleep(1~3)降低请求频率,避免对目标网站造成压力。
七、爬虫法律与道德红线(重要!)
笔记里总结的三条底线,必须刻进DNA:
-
不要爬取公民隐私数据
-
要尊重版权保护的内容
-
国家事务、国防建设相关网站绝对不碰
技术层面的注意点:
-
⚡ 请求频率不能过高 ,否则无异于 DDoS 攻击(通过给服务器发送海量高频请求,让网站资源被耗尽,无法服务其他正常用户)
-
🚧 网站如果做出明显的反爬限制 (如有些内容登录后可看),尊重限制机制,不要强行突破
-
📄 爬取前查看网站的
robots.txt文件 (如www.example.com/robots.txt),它声明了允许/禁止爬取的网页路径范围
八、完整知识图谱(复习用)
┌─────────────────────────────────────────┐
│ 爬虫三步走 │
├──────────────┬──────────────────────────┤
│ ① 获取网页内容 │ requests库 │
│ │ · requests.get(网址) │
│ │ · response.status_code │
│ │ · response.text / .ok │
│ │ · headers伪装User-Agent │
├──────────────┼──────────────────────────┤
│ ② 解析网页内容 │ BeautifulSoup库 │
│ │ · BeautifulSoup(text, │
│ │ "html.parser") │
│ │ · find() / findAll() │
│ │ · attrs={"class": "..."} │
│ │ · .string 取文本 │
│ │ · 切片 [2:] 清洗数据 │
├──────────────┼──────────────────────────┤
│ ③ 存储/分析 │ 存CSV/Excel → 数据分析 │
│ │ → 可视化图表 │
└──────────────┴──────────────────────────┘
底层支撑:
HTTP协议(请求行/请求头/请求体;状态行/响应头/响应体)
HTML结构(标签、class属性、层级与兄弟关系)
最小可运行模板(背下来,90%的简单爬虫都是它的变体):
import requests
from bs4 import BeautifulSoup
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
url = "目标网址"
response = requests.get(url, headers=headers)
if response.ok:
soup = BeautifulSoup(response.text, "html.parser")
items = soup.findAll("标签名", attrs={"class": "目标class"})
for item in items:
print(item.string)
else:
print("请求失败:", response.status_code)
九、常见问题速查(FAQ)
Q1:为什么返回418 / 403? 服务器识别出你是爬虫。加上 headers 伪装 User-Agent,必要时补充 Cookie、Referer。
Q2:为什么 findAll 返回空列表? 检查 class 名是否写对(浏览器里右键检查确认);注意有的class有多个值,要用完整字符串匹配。
Q3:price.string 报错 NoneType? 说明该标签内嵌套了子标签,string 无法确定取哪个。改用 .get_text()。
Q4:中文乱码? 尝试 response.encoding = response.apparent_encoding 后再取 .text。
十、写在最后
零基础学爬虫,其实就两条主线:
网络线 :理解HTTP请求-响应 → 用requests发请求 解析线:理解HTML标签结构 → 用BeautifulSoup查标签
把这两条线打通,再加一个 for 循环实现翻页,你就已经具备了爬取绝大多数静态网页的能力。下一步可以进阶学习:数据存储(CSV/Excel/MySQL)、XPath、正则表达式、Selenium动态页面爬取、Scrapy框架。
如果觉得本文对你有帮助,欢迎点赞收藏,复习时直接对照第八节的图谱过一遍即可。评论区欢迎交流爬取中遇到的问题,下期预告:《Python爬虫进阶:数据存储与清洗实战》。