Python爬虫入门实战:18个案例掌握HTTP请求、数据解析与存储
大家好,我是你们的技术博主。今天这篇文章想和大家聊一聊 Python 爬虫入门实战。网上关于 Python 爬虫的教程非常多,但大多只讲爬虫库的用法,或者直接丢出几个大网站的抓取案例就不管了,新手照着写,没过几天就被反爬机制拦截,不仅练不了手,还容易丧失信心。
本文会换一种思路:不追求“抓取某个大平台”,而是把爬虫开发中最常用、最核心的 18 个真实场景拆解成独立案例。每个案例都配套完整源码,覆盖请求、解析、数据提取、数据清洗、数据存储、异常处理、翻页、会话保持、定时调度等知识点。你只要把每个案例跑通,就等于把爬虫开发的整个知识体系打了一遍。
本文适合以下读者:
- 刚学完 Python 基础语法,想了解爬虫怎么入门的同学;
- 有一定 Python 基础,但觉得“网上爬虫教程不够系统”的同学;
- 想用 Python 自动化获取公开数据、练习数据采集技能的开发者。
文章内容偏实操,不做过多的底层原理挖掘,但会解释每个关键步骤的语义,让你不仅会写代码,还知道为什么要这样写。
1. 认识 Python 爬虫
1.1 什么是爬虫
爬虫(Web Crawler)从广义上讲,是“按照一定规则,自动请求互联网上的资源,并从响应结果中提取所需数据的程序”。它本质上就是一段自动化代码,模拟浏览器向服务器发送 HTTP 请求,再对服务器返回的 HTML、JSON 等数据做解析。
用通俗的例子解释:你打开浏览器访问新闻网站,看到网页上的标题、正文、日期,这个过程可以理解成“手动爬取”。爬虫程序就是把这些手工操作自动化:
- 浏览器地址栏输入网址 → 程序用代码请求 URL;
- 浏览器渲染出页面 → 程序把返回内容解析成字符串或 JSON;
- 人用眼睛找标题 → 程序用解析库、正则表达式按规则提取;
- 人复制粘贴到本地 → 程序自动写入 CSV、Excel 或数据库。
1.2 爬虫的应用场景
爬虫的能力放在真实业务里,常见应用场景有:
- 搜索引擎:搜索引擎本身就是大型爬虫系统,不断抓取网页并建立索引。
- 数据分析与行业调研:抓取招聘网站的岗位要求、电商平台的商品价格、天气数据、公开论文元数据等进行趋势分析。
- 舆情监控与新闻聚合:采集新闻网站、论坛的公开内容,做一些关键词统计。
- 自动化测试:模拟用户在网站上的请求行为,配合接口测试框架使用。
- 个人数据备份:将自己在某个平台公开过的内容批量下载到本地收藏。
需要注意的是,爬虫本身只是一个技术工具。工具没有原罪,关键取决于使用方式。你在学习阶段,最好优先选择公开接口、官方 API、以及允许抓取的练习页面,不要一上来就去爬那种有明显反爬策略的电商平台或社交平台,更不要用爬虫获取非公开数据,也不要对目标站点造成压力。
1.3 本文的 18 个案例设计逻辑
这 18 个案例,我会按照爬虫开发流程从易到难安排:
| 阶段 | 案例编号 | 学习目标 |
|---|---|---|
| 请求基础 | 案例 1-4 | 学会用 urllib、requests 发起 HTTP 请求 |
| 页面解析 | 案例 5-7 | 学会 BeautifulSoup、XPath、正则提取数据 |
| 场景进阶 | 案例 8-12 | 学会翻页、图片下载、请求头和 Session 处理 |
| 数据持久化 | 案例 13-16 | 学会保存到 CSV、Excel、SQLite,断点续爬 |
| 工程化与稳定性 | 案例 17-18 | 学会异常处理、超时重试、定时调度 |
每节代码都尽量保证精简、可独立运行,并标注文件路径。你可以新建一个python_spider_practice文件夹,把每个案例保存为单独的.py文件。
2. 环境准备
在开始写代码之前,先检查一下本机环境。下面这些工具是运行本文案例需要准备的:
2.1 Python 环境
- Python 3.8 及以上版本(建议使用 3.10 或 3.11,较新的版本对类型注解和异步支持更好)。
- 安装方式:Windows 用户到 Python 官网下载安装包,勾选“Add Python to PATH”;macOS/Linux 用户可以使用系统自带的 Python 3,也可以使用 Homebrew 或 apt 安装。
检查方式:
python --version # 或者 python3 --version如果命令提示找不到 Python,请检查环境变量。
2.2 第三方爬虫库
本文主要使用以下第三方库:
| 库名 | 用途 |
|---|---|
| requests | 最常用的 HTTP 请求库,API 简洁 |
| beautifulsoup4 | 解析 HTML 文档,提供便捷的节点搜索方式 |
| lxml | 高性能解析器,配合 XPath 使用 |
| openpyxl | 写入 Excel 文件 |
| APScheduler | 定时任务调度(作为可选扩展) |
安装命令:
pip install requests beautifulsoup4 lxml openpyxl APScheduler如果你的环境是 Python 3.10 以下,且安装 lxml 时遇到编译错误,请先升级 pip:
pip install --upgrade pip2.3 IDE 建议
推荐使用 VS Code 或者 PyCharm。如果你是新手,VS Code 轻量,配置 Python 插件后就能直接调试,比较方便。如果使用 PyCharm,建议选择 Community 版本即可。
3. 第一组案例:HTTP 请求基础
看过爬虫源码的同学都知道,爬虫的第一步是向服务器发出请求。本组 4 个案例会帮你建立 HTTP 请求的基本认知。
3.1 案例 1:用 urllib 请求网页并获取标题
为什么要先学 urllib?因为它是 Python 标准库自带的模块,不需要安装任何第三方依赖,适合理解 HTTP 请求的过程。
# 文件路径:python_spider_practice/case01_urllib_title.py import urllib.request url = "https://www.example.com" # 1. 发起 GET 请求 response = urllib.request.urlopen(url, timeout=5) # 2. 读取响应内容 html = response.read().decode("utf-8") # 3. 用字符串查找的方式粗略提取 title 标签内容 start = html.find("<title>") + len("<title>") end = html.find("</title>") title = html[start:end] print("页面标题:", title)代码说明:
urlopen是 urllib 内置的请求方法,返回一个类文件对象;read()读取二进制内容,使用decode("utf-8")转成字符串;find方法定位<title>标签的位置,这种方式虽然不够优雅,但能很好说明“解析”的本质。
3.2 案例 2:requests 发起 GET 请求
相比 urllib,requests 的代码更简洁,也是大多数 Python 爬虫的标配。下面请求一个公共 JSON 占位接口,这是学习数据抓取时很常用的练习接口,返回的是模拟数据,不涉及敏感信息。
# 文件路径:python_spider_practice/case02_requests_get.py import requests url = "https://jsonplaceholder.typicode.com/posts/1" response = requests.get(url, timeout=5) print("HTTP 状态码:", response.status_code) print("响应文本:", response.text) print("JSON 数据:", response.json())代码说明:
response.status_code表示 HTTP 状态码,200 表示成功,404 表示资源不存在;response.json()会把 JSON 字符串自动转成 Python 字典。
运行输出大致如下:
HTTP 状态码: 200 响应文本: { "userId": 1, "id": 1, "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit ..." } JSON 数据: {'userId': 1, 'id': 1, 'title': '...', 'body': '...'}3.3 案例 3:requests 发送 POST 表单请求
很多网页的搜索功能,本质是向服务器提交一个表单。requests 发送表单数据,只需要提供一个字典给data参数。
# 文件路径:python_spider_practice/case03_requests_post.py import requests # 注意:以下示例用的是公开测试地址,实际开发中请替换为真实的表单提交接口 url = "https://httpbin.org/post" form_data = { "username": "test_user", "keyword": "python 爬虫" } response = requests.post(url, data=form_data, timeout=5) print("状态码:", response.status_code) print("返回内容:", response.text)httpbin.org 是一个常用于调试 HTTP 请求的公开测试服务,它能原样返回你提交的数据,非常适合学习时验证请求是否正确。
3.4 案例 4:抓取公开 JSON 接口并解析
很多时候,服务器返回的不是 HTML,而是 JSON 数据。比如 GitHub 的公开搜索 API、天气公开接口、RSS 服务等。这类数据是结构化数据,解析起来更方便。
# 文件路径:python_spider_practice/case04_json_api.py import requests # 使用 GitHub 公开搜索 API:搜索 Python 语言中 star 数较高的仓库 url = "https://api.github.com/search/repositories" params = { "q": "language:python", "sort": "stars", "order": "desc", "per_page": 5 } headers = { "Accept": "application/vnd.github+json", "User-Agent": "Mozilla/5.0 (Python Spider Learning)" } response = requests.get(url, params=params, headers=headers, timeout=10) # 判断请求是否成功,GitHub API 有请求频率限制 if response.status_code == 200: data = response.json() print("返回仓库数量:", data.get("total_count")) for item in data.get("items", []): print(item.get("full_name"), "Stars:", item.get("stargazers_count")) else: print("请求失败,状态码:", response.status_code) print("响应内容:", response.text)代码说明:
params参数会自动把字典拼接到 URL 的查询字符串中;- GitHub 官方 API 要求请求头携带
User-Agent,否则可能返回 403; response.json()把 JSON 转成 Python 字典,再通过get方法安全读取字段。
4. 第二组案例:从 HTML 中提取数据
第一组案例演示了怎么把数据“拿回来”,接下来要解决的是“怎么把想要的内容从 HTML 中挑出来”。
4.1 案例 5:BeautifulSoup 解析标题和所有链接
BeautifulSoup 是很流行的 HTML 解析库,它把 HTML 文档转换成一棵节点树,通过标签名、class、id 等属性定位元素。
# 文件路径:python_spider_practice/case05_bs4_parse.py import requests from bs4 import BeautifulSoup url = "https://www.example.com" response = requests.get(url, timeout=5) response.encoding = "utf-8" soup = BeautifulSoup(response.text, "html.parser") # 1. 获取页面标题 print("标题:", soup.title.string) # 2. 获取页面中所有 a 标签的 href 链接 links = soup.find_all("a") for link in links[:10]: # 只打印前 10 个,避免输出过长 href = link.get("href") text = link.get_text(strip=True) print("链接文本:", text, "| 链接地址:", href)代码说明:
BeautifulSoup(response.text, "html.parser")表示用 Python 内置的解析器解析文档;soup.find_all("a")返回所有<a>标签的列表;link.get("href")获取属性值;如果属性不存在,返回None。
在实际项目中,更常用的是lxml解析器,速度更快:
soup = BeautifulSoup(response.text, "lxml")4.2 案例 6:使用 lxml + XPath 精准提取
XPath 是一种在 XML/HTML 文档中查找信息的路径表达式语言。它比 BeautifulSoup 的选择器更适合复杂层级定位。
# 文件路径:python_spider_practice/case06_xpath_parse.py import requests from lxml import html url = "https://example.com" response = requests.get(url, timeout=5) response.encoding = "utf-8" tree = html.fromstring(response.text) # 提取页面标题 title = tree.xpath("//title/text()") print("标题:", title[0] if title else "未找到标题") # 提取所有链接 links = tree.xpath("//a/@href") for link in links[:10]: print(link)XPath 常用语法:
//title:在文档任意位置找title节点;/text():获取节点文本;//a/@href:获取所有a节点的href属性;//div[@class="content"]//p:找到 class 为 content 的 div 下所有 p 标签。
4.3 案例 7:正则表达式提取特定内容
正则表达式适合提取有明显规则特征的文本。比如邮箱地址、手机号、日期等。这里先声明:示例数据来自我们自造的演示文本,不涉及任何真实个人信息。
# 文件路径:python_spider_practice/case07_regex_extract.py import re demo_text = """ 联系邮箱:contact@example.com,备用邮箱:support@test.org。 产品上线日期:2025-06-18,版本号:v2.3.1。 """ # 1. 提取邮箱 email_pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" emails = re.findall(email_pattern, demo_text) print("邮箱列表:", emails) # 2. 提取日期 date_pattern = r"\d{4}-\d{2}-\d{2}" dates = re.findall(date_pattern, demo_text) print("日期列表:", dates) # 3. 提取版本号 version_pattern = r"v\d+\.\d+\.\d+" versions = re.findall(version_pattern, demo_text) print("版本列表:", versions)在真实爬虫中,正则可以配合 BeautifulSoup 一起使用:先用解析库定位到某个区域,再用正则从该区域的文本中提取字段。
5. 第三组案例:进阶采集场景
本组案例开始接触真实开发中更常见的场景:翻页、下载文件、处理 Cookie 和 Session。
5.1 案例 8:翻页采集列表数据
很多网站的数据都分页展示。翻页采集的核心,是找到翻页时 URL 变化的规律,或者 POST 参数中页码字段的变化规律。
下面用一个模拟的分页请求例子来讲:
# 文件路径:python_spider_practice/case08_pagination.py import requests # 这是一个演示性质的公共接口,每页返回 10 条数据 base_url = "https://jsonplaceholder.typicode.com/posts" page_size = 10 total_pages = 3 for page in range(1, total_pages + 1): params = { "_page": page, "_limit": page_size } response = requests.get(base_url, params=params, timeout=5) data = response.json() print(f"第 {page} 页,获取 {len(data)} 条数据") # 这里可以继续做数据清洗、入库等操作代码说明:
- 这里用的公共接口,
_page和_limit是分页参数; - 在电商、招聘等场景,分页参数名称可能是
page、pageNum、offset等,需要根据实际情况调整。
5.2 案例 9:批量下载图片
图片下载从本质上说,就是把服务器返回的二进制内容写入本地文件。
# 文件路径:python_spider_practice/case09_download_images.py import requests from pathlib import Path # 这里使用两张占位图片链接,方便演示;实际项目中请替换为合法的图片地址 image_urls = [ "https://www.example.com/images/demo1.jpg", "https://www.example.com/images/demo2.jpg" ] save_dir = Path("images") save_dir.mkdir(exist_ok=True) for index, image_url in enumerate(image_urls, start=1): response = requests.get(image_url, timeout=10) if response.status_code == 200: # 根据 URL 后缀推断文件扩展名 suffix = Path(image_url).suffix or ".jpg" file_name = f"image_{index}{suffix}" file_path = save_dir / file_name # 以二进制模式写入文件 file_path.write_bytes(response.content) print("已下载:", file_path)代码说明:
response.content返回二进制内容,适合图片、文件下载;- 使用
pathlib处理路径比字符串拼接更安全; mkdir(exist_ok=True)确保目录存在,重复运行不会报错。
5.3 案例 10:模拟请求头,提升请求兼容性
很多服务器会检查请求头User-Agent,如果发现请求来自陌生程序,可能直接拒绝或限制访问。模拟常见的浏览器请求头,是爬虫开发中最基本的操作。
# 文件路径:python_spider_practice/case10_headers.py import requests url = "https://httpbin.org/headers" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9" } response = requests.get(url, headers=headers, timeout=5) print(response.text)代码说明:
User-Agent是当前浏览器环境的标识;- 设置
Accept表示希望服务器返回什么类型的资源; - 在爬虫开发中,建议不要把请求头伪装得过于“假”,更不要伪造身份信息去绕过平台限制。
5.4 案例 11:使用 Session 维持会话状态
有些网站需要先登录才能访问目标页面。登录后的身份凭证通常保存在 Cookie 中。requests 的Session对象可以自动保存 Cookie,并对后续请求持续生效。
下面的例子用公开的 httpbin cookies 接口演示 Session 行为:
# 文件路径:python_spider_practice/case11_session.py import requests # 创建 Session 对象 session = requests.Session() # 第一步:访问设置 Cookie 的接口 set_cookie_url = "https://httpbin.org/cookies/set/username/spider_learner" session.get(set_cookie_url, timeout=5) # 第二步:访问获取 Cookie 的接口,验证 Session 中是否保存了 Cookie get_cookie_url = "https://httpbin.org/cookies" response = session.get(get_cookie_url, timeout=5) print("Session 中保存的 Cookie:", response.json())代码说明:
session.get()会保存服务器通过Set-Cookie方式下发的 Cookie;- 后续同一个 Session 发起请求时会自动携带这些 Cookie;
- 在真实项目中,登录通常需要构造 POST 请求,把用户名、密码发给登录接口,成功后 Session 就自动保持登录状态。
5.5 案例 12:处理超时与异常
网络请求大概率会遇到超时、DNS 解析失败、连接被重置等情况。如果不做异常处理,爬虫很可能运行到一半就崩溃退出。
# 文件路径:python_spider_practice/case12_timeout_retry.py import time import requests from requests.exceptions import RequestException def fetch_with_retry(url, max_retries=3, timeout=5): for attempt in range(1, max_retries + 1): try: response = requests.get(url, timeout=timeout) response.raise_for_status() # 状态码不是 2xx 时抛出异常 return response except RequestException as e: print(f"第 {attempt} 次请求失败:{e}") if attempt < max_retries: wait_time = 2 ** attempt # 指数退避 print(f"等待 {wait_time} 秒后重试...") time.sleep(wait_time) return None url = "https://httpbin.org/delay/3" response = fetch_with_retry(url, timeout=2) if response: print("请求成功") else: print("重试多次后仍然失败")代码说明:
timeout=2表示连接和读取的等待时间;raise_for_status()会在返回 4xx、5xx 时主动抛异常;- 重试使用指数退避策略,避免在服务端异常时加剧压力。
6. 第四组案例:数据持久化
爬虫抓回来的数据,最终要落地存储。这里介绍三种最常见的方式:CSV、Excel、SQLite。
6.1 案例 13:保存数据到 CSV 文件
CSV 是最通用的表格格式,Excel、数据库工具都能打开。
# 文件路径:python_spider_practice/case13_save_csv.py import csv # 模拟爬取到的数据 data_list = [ {"title": "Python 爬虫入门", "author": "小明", "views": 1200}, {"title": "requests 库实战", "author": "小红", "views": 890}, {"title": "BeautifulSoup 解析技巧", "author": "小刚", "views": 1560}, ] with open("articles.csv", "w", encoding="utf-8", newline="") as f: fieldnames = ["title", "author", "views"] writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() writer.writerows(data_list) print("CSV 文件保存成功")注意:写入 CSV 时指定encoding="utf-8"可以确保中文不乱码。部分旧版 Excel 打开 UTF-8 CSV 会乱码,如果你要兼容旧版 Excel,可以改成utf-8-sig。
6.2 案例 14:保存数据到 Excel 文件
Excel 文件更适合做数据分析和展示。openpyxl 库支持 xlsx 格式的写入。
# 文件路径:python_spider_practice/case14_save_excel.py from openpyxl import Workbook wb = Workbook() ws = wb.active ws.title = "爬虫数据" # 表头 ws.append(["标题", "作者", "阅读量"]) # 数据行 data_list = [ ["Python 爬虫入门", "小明", 1200], ["requests 库实战", "小红", 890], ["BeautifulSoup 解析技巧", "小刚", 1560], ] for row in data_list: ws.append(row) wb.save("articles.xlsx") print("Excel 文件保存成功")如果你要处理大量数据,可以使用write_only=True模式减少内存占用:
from openpyxl import Workbook wb = Workbook(write_only=True) ws = wb.create_sheet(title="爬虫数据") ws.append(["标题", "作者", "阅读量"]) # 循环中写入数据... wb.save("articles_large.xlsx")6.3 案例 15:保存数据到 SQLite 数据库
SQLite 是轻量级数据库,无需安装服务端,非常适合爬虫阶段的本地存储。
# 文件路径:python_spider_practice/case15_save_sqlite.py import sqlite3 # 连接数据库,如果文件不存在会自动创建 conn = sqlite3.connect("articles.db") cursor = conn.cursor() # 创建表 cursor.execute(""" CREATE TABLE IF NOT EXISTS articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, author TEXT, views INTEGER ) """) # 模拟数据 data_list = [ ("Python 爬虫入门", "小明", 1200), ("requests 库实战", "小红", 890), ("BeautifulSoup 解析技巧", "小刚", 1560), ] cursor.executemany( "INSERT INTO articles (title, author, views) VALUES (?, ?, ?)", data_list ) conn.commit() # 查询数据 cursor.execute("SELECT * FROM articles") rows = cursor.fetchall() for row in rows: print(row) conn.close()代码说明:
- 使用
?占位符来传参,可以有效防止 SQL 注入,这是数据库操作的标准做法; executemany批量插入多条记录,性能比逐条插入更好;- 对爬取到的数据入库前,建议做去重处理,可以通过给关键字段加唯一索引实现。
6.4 案例 16:断点续爬
如果爬虫跑了一半崩溃了,重新从第一页开始爬会很浪费时间。断点续爬的核心思路是记录“已经处理到的位置”,下次启动时从该位置继续。
# 文件路径:python_spider_practice/case16_resume_crawl.py import json from pathlib import Path status_file = Path("crawl_status.json") def load_status(): if status_file.exists(): data = json.loads(status_file.read_text(encoding="utf-8")) return data.get("last_page", 0) return 0 def save_status(page): status_file.write_text( json.dumps({"last_page": page}, ensure_ascii=False, indent=2), encoding="utf-8" ) # 模拟分页爬取 start_page = load_status() for page in range(start_page, 10): print(f"正在爬取第 {page + 1} 页...") # 这里写入真正的爬取逻辑 # 每爬完一页就保存状态 save_status(page + 1) print("全部爬取完成")这种“状态持久化”的思想,在真实爬虫项目中非常重要。你可以把状态存到文件、数据库或 Redis 中。
7. 第五组案例:工程化与稳定性
爬虫不只是“写几行代码抓数据”,还要考虑异常处理、日志记录、定时执行等工程问题。
7.1 案例 17:统一异常处理与日志记录
日志可以帮助你在爬虫无人值守运行时追踪问题。Python 标准库logging提供了非常完整的日志能力。
# 文件路径:python_spider_practice/case17_logging.py import logging import requests # 配置日志 logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s", handlers=[ logging.FileHandler("spider.log", encoding="utf-8"), logging.StreamHandler() ] ) def crawl_page(url): try: logging.info("开始请求:%s", url) response = requests.get(url, timeout=5) response.raise_for_status() logging.info("请求成功,数据长度:%d", len(response.text)) return response.text except requests.exceptions.Timeout: logging.error("请求超时:%s", url) except requests.exceptions.RequestException as e: logging.exception("请求异常:%s", url) return None if __name__ == "__main__": html = crawl_page("https://jsonplaceholder.typicode.com/posts/1") if html: print("拿到页面内容")代码说明:
FileHandler把日志写入文件,StreamHandler同时输出到控制台;logging.exception会输出完整异常堆栈,便于排查问题;- 正确定位异常日志级别,能显著减少后期维护成本。
7.2 案例 18:定时爬虫任务调度
爬虫经常需要按固定周期执行。比如每天早上 8 点抓取一次天气预报、每周抓取一次榜单数据。APScheduler 是一个轻量级任务调度库,适合爬虫场景。
# 文件路径:python_spider_practice/case18_scheduler.py import time from datetime import datetime from apscheduler.schedulers.blocking import BlockingScheduler def job(): print(f"{datetime.now()} 开始执行定时爬虫任务") # 这里放你的爬虫主逻辑 # 比如 requests 请求、数据解析、入库等 print("任务执行完成") scheduler = BlockingScheduler() # 每 10 分钟执行一次 scheduler.add_job(job, "interval", minutes=10) # 也可以改成每天固定时间执行 # scheduler.add_job(job, "cron", hour=8, minute=0) print("调度器启动,按 Ctrl+C 结束") scheduler.start()如果你想部署在服务器上,更推荐使用系统级的定时任务工具(Windows 的任务计划程序、Linux 的 crontab),这样即使 Python 进程意外退出,任务也会由操作系统重新拉起。
8. 爬虫开发中的常见问题与排查思路
以下是我在实际爬虫开发中经常遇到的问题,整理成了一张速查表:
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 请求返回 403 | 服务器拒绝访问,通常是缺少请求头或触发了反爬策略 | 添加User-Agent、Referer等请求头;降低请求频率 |
| 请求返回 404 | URL 拼写错误,或列表页与详情页 URL 规则不一致 | 在浏览器中手动访问,检查 URL 实际路径 |
| 中文乱码 | 页面编码不是 UTF-8,响应内容被错误解码 | 查看响应头中的charset字段,指定response.encoding |
| 请求超时 | 目标网站响应慢,或网络环境不稳定 | 设置合理 timeout,加入重试机制 |
| JSON 解析失败 | 返回内容不是 JSON 格式,可能被重定向到登录页或验证页面 | 先打印response.text确认内容格式 |
| 数据提取结果为空 | XPath/CSS 选择器写错,或页面为动态渲染 | 用浏览器开发者工具检查实际元素结构;考虑使用 Selenium 等工具 |
| 爬取过程中被限制访问 | 请求频率过高,触发了服务端限制 | 增加间隔时间,设置随机延迟,控制并发数 |
| Excel 打开 CSV 乱码 | CSV 文件编码与 Excel 默认编码不一致 | 写入时使用utf-8-sig编码 |
排查异常时,建议按照“先看状态码 → 再看响应文本 → 接着定位解析逻辑 → 最后检查数据存储”的顺序进行,大部分问题都能快速锁定。
9. 最佳实践与工程建议
这里结合平时做爬虫项目的经验,给大家一些比较实用的建议。
9.1 遵守规则与底线
- 只抓取公开、合法、允许访问的数据;
- 遵守目标网站的 robots.txt 协议和用户协议;
- 控制请求频率,不要对目标服务器造成压力;
- 不要将爬虫用于批量注册、刷票、恶意攻击、未授权抓取个人隐私等行为;
- 下载的数据仅用于学习研究,不要用于商业用途或公开传播。
9.2 代码设计规范
- 把请求、解析、存储三个流程拆分成独立函数,便于测试和维护;
- 使用配置模块统一管理 URL、headers、超时时间、重试次数;
- 对关键路径使用 try-except 包裹,但不要吞掉异常,至少要记录日志;
- 为每个函数写简要注释,说明入参、返回值和注意事项。
大型爬虫项目可以参考下面的分层:
spider_project/ ├── config.py # 全局配置 ├── spiders/ # 各个爬虫模块 │ ├── article_spider.py │ └── image_spider.py ├── parsers/ # 解析模块 ├── storage/ # 数据存储模块 ├── utils/ # 通用工具 └── run.py # 启动入口9.3 数据清洗与去重
爬取到的数据通常不干净,入库前要处理:
- 去空格、去换行、去除 HTML 标签;
- 统一日期格式;
- 去除重复数据(可以用数据库唯一索引或 set 集合);
- 对字段缺失的数据做默认值处理。
9.4 性能与稳定性
- 对耗时操作设置合理的超时时间;
- 使用 Session 复用连接;
- 如果并发量较大,考虑使用线程池控制并发上限;
- 加入失败重试和失败 URL 记录;
- 生产环境使用 Supervisor、systemd、Docker 等方式管理爬虫进程。
9.5 学会利用官方 API
如果能找到官方 API,优先使用 API 而不是解析 HTML。API 返回的是结构化 JSON 数据,稳定、高效、不容易因为页面改版而失效。很多平台都提供了公开 API 或开发者接口,这是更友好、更合规的数据获取方式。
10. 总结与下一步学习建议
到这里,18 个 Python 爬虫实战案例就全部过完一遍了。你掌握了以下这些能力:
- 用 urllib、requests 发起 HTTP 请求;
- 用 BeautifulSoup、XPath、正则表达式提取数据;
- 处理翻页、图片下载、Cookie 会话、超时与异常重试;
- 把数据保存到 CSV、Excel、SQLite;
- 使用日志、定时任务来提升爬虫的工程化能力。
如果你把每个案例都亲手敲一遍,再尝试改一改数据源和解析规则,就已经具备独立开发大部分静态网页爬虫的能力了。
接下来,建议你按这样的顺序继续深入:
- 用官方 API 做一个小项目,比如利用 GitHub API 抓取开源项目信息,保存到数据库;
- 找一个合法的公开练习站点,尝试完成列表页 → 详情页 → 多字段采集 → 数据持久化的全流程;
- 学习 CSS 选择器,配合 BeautifulSoup 的
select方法使用,它比find_all在一些场景下更简洁; - 了解 requests-html、Selenium、Playwright 这类工具在动态页面中的用途;
- 学习 Scrapy 框架,进一步掌握分布式爬虫和管道处理。
爬虫这门技术,实践价值很高,但它真正考验的是你的排查能力、数据清洗能力和工程意识。入门阶段不要贪多,先跑通这 18 个案例,你对 Python 爬虫的技术体系就会有一个非常完整的感觉。如果文章对你有帮助,欢迎收藏备用。后面我也会继续更新爬虫和数据采集相关的实战内容。
