【Python爬虫教程及实战】
一、爬虫环境准备与核心库安装
1.1 Python 环境搭建
本文基于Python 3.8 及以上版本开发,若尚未安装 Python,可从Python 官方网站下载对应系统的安装包,安装时务必勾选Add Python to PATH,完成后可在终端执行以下命令验证安装:
python --version # 或 macOS/Linux 执行 python3 --version
规范建议:为每个爬虫项目创建独立虚拟环境,避免全局依赖冲突,执行命令如下:
# 创建虚拟环境
python -m venv crawler_env
# 激活虚拟环境 #
#Windows: crawler_env\Scripts\activate # macOS/Linux: source crawler_env/bin/activate
1.2 核心爬虫库安装
Python 爬虫的高效开发依赖成熟的第三方库,分为基础必备库和进阶工具库,所有库均可通过pip包管理器安装
以下是爬虫常用的四个库(win+r打开命令提示符运行下列代码):requests、beautifulsoup、scrapy、selenium
pip install requests beautifulsoup4 scrapy selenium
二、爬虫核心原理与基础流程
2.1 爬虫的核心工作闭环
无论简单还是复杂的爬虫,本质都是完成「模拟请求→获取响应→解析数据→存储数据」的闭环流程,四个步骤的核心目标如下:
- 模拟请求:伪装成浏览器,向目标服务器发送符合规范的 HTTP 请求,携带必要的身份信息;
- 获取响应:接收服务器返回的响应内容,包括网页 HTML 源码、JSON 接口数据、二进制文件等;
- 解析数据:从响应内容中过滤、提取我们需要的结构化数据,剔除无关的冗余内容;
- 存储数据:将提取的有效数据按照需求保存到本地文件或数据库中,方便后续使用。
2.2 HTTP 协议基础
爬虫的核心是 HTTP 请求,必须掌握以下基础概念,才能应对后续的反爬与复杂场景:
-
核心请求方法
GET:最常用的请求方法,用于从服务器获取资源,参数直接拼接在 URL 中,无请求体,适合普通网页、接口数据获取;POST:用于向服务器提交数据,参数放在请求体中,安全性更高,适合登录、表单提交、加密接口请求。
-
关键请求头字段请求头是服务器识别客户端身份的核心依据,也是反爬校验的重点,新手必须掌握以下关键字段:
User-Agent客户端标识,记录浏览器版本、操作系统等信息,是最基础的反爬校验项,必须携带
Referer记录当前请求的来源页面,用于校验请求是否来自网站自身,应对防盗链、来源校 验反爬
Cookie存储用户会话信息、登录状态,用于需要登录才能访问的页面,维持会话连续性 Accept声明客户端可接收的内容类型,如text/html、application/json
常见响应状态码服务器通过状态码告知请求结果,可通过状态码快速定位问题:
200 OK:请求成功,服务器正常返回内容;403 Forbidden:服务器拒绝访问,大概率触发了反爬机制;404 Not Found:请求的资源不存在,URL 错误或页面已下架;429 Too Many Requests:请求频率过高,触发了服务器限流规则;500 Internal Server Error:服务器内部出错,与爬虫无关。
2.3 HTML 网页结构基础
网页的核心是 HTML(超文本标记语言),由嵌套的标签组成,形成 DOM 树结构,爬虫解析数据的本质就是从 DOM 树中定位目标标签,提取标签内的文本或属性。
基础 HTML 结构示例:
html
预览
<!DOCTYPE html>
<html>
<head>
<title>测试页面</title>
</head>
<body>
<div class="news-list">
<div class="news-item">
<a href="https://example.com/news/1" class="news-title">第一条新闻标题</a>
<span class="news-date">2026-03-05</span>
</div>
<div class="news-item">
<a href="https://example.com/news/2" class="news-title">第二条新闻标题</a>
<span class="news-date">2026-03-04</span>
</div>
</div>
</body>
</html>
在这个示例中,我们需要提取的新闻标题和链接,就存放在<a>标签的文本和href属性中,通过 BeautifulSoup 或 XPath 即可快速定位。
三、基础网页爬取实战
本节从 0 到 1 实现 3 个渐进式的爬虫案例,所有案例均基于公开合规的测试场景,新手可直接复制代码运行,理解每一步的核心逻辑。
3.1 案例 1:第一个极简爬虫(获取网页源码)
核心目标:使用 requests 库发送 GET 请求,获取目标网页的 HTML 源码,理解请求与响应的核心流程。
import requests
# 配置请求参数
url = "http://example.com"
# 配置请求头,携带User-Agent,模拟浏览器访问
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"
}
# 3. 发送GET请求,捕获异常
try:
# 发送请求,设置超时时间10秒
response = requests.get(url, headers=headers, timeout=10)
# 校验请求是否成功,状态码非200则抛出异常
response.raise_for_status()
# 设置响应编码,避免中文乱码
response.encoding = response.apparent_encoding
# 4. 处理响应结果
print("请求成功,状态码:", response.status_code)
print("="*50)
# 打印网页HTML源码
print(response.text)
# 可选:将源码保存到本地文件
with open("example.html", "w", encoding="utf-8") as f:
f.write(response.text)
print("="*50)
print("网页源码已保存到example.html")
except Exception as e:
print("请求失败,错误信息:", e)
4.1 需求与网站分析
- 爬取目标:豆瓣电影 Top250 所有电影的结构化数据,包括排名、电影名称、导演、主演、上映年份、国家、类型、评分、评价人数、简介;
- URL 规律:豆瓣 Top250 分页 URL 为
https://movie.douban.com/top250?start={offset}&filter=,每页 25 条数据,offset 从 0 开始,每次 + 25,共 10 页; - 反爬应对:携带完整请求头、添加随机延迟、使用会话维持 Cookie。
4.2 完整代码实现
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random
from fake_useragent import UserAgent
# 初始化配置
ua = UserAgent()
session = requests.Session()
# 基础URL
base_url = "https://movie.douban.com/top250"
# 存储所有电影数据
all_movies = []
# 请求头配置
def get_headers():
return {
"User-Agent": ua.random,
"Referer": "https://movie.douban.com/",
"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,en;q=0.8",
"Connection": "keep-alive",
"Host": "movie.douban.com"
}
# 发送请求获取页面源码
def get_page_html(url):
try:
# 随机延迟2-4秒,严格控制频率
time.sleep(random.uniform(2, 4))
response = session.get(url, headers=get_headers(), timeout=15)
response.raise_for_status()
response.encoding = "utf-8"
return response.text
except Exception as e:
print(f"页面请求失败{url}:", e)
return None
# 解析单页数据
def parse_movie_list(html):
if not html:
return []
soup = BeautifulSoup(html, "lxml")
# 定位电影列表
movie_items = soup.find_all("div", class_="item")
page_movies = []
for item in movie_items:
try:
# 提取排名
rank = item.find("em").get_text(strip=True)
# 提取电影名称
title_tag = item.find("span", class_="title")
title = title_tag.get_text(strip=True) if title_tag else ""
# 提取其他名称
other_title = item.find("span", class_="other").get_text(strip=True).replace(" / ", "") if item.find("span", class_="other") else ""
# 提取评分
rating = item.find("span", class_="rating_num").get_text(strip=True) if item.find("span", class_="rating_num") else ""
# 提取评价人数
comment_num = item.find("div", class_="star").find_all("span")[-1].get_text(strip=True).replace("人评价", "") if item.find("div", class_="star") else ""
# 提取简介
quote = item.find("span", class_="inq").get_text(strip=True) if item.find("span", class_="inq") else "无简介"
# 提取导演、年份、国家、类型信息
info_tag = item.find("div", class_="bd").find("p", class_="")
info_text = info_tag.get_text(strip=True, separator="\n") if info_tag else ""
# 分割信息行
info_lines = info_text.split("\n")
# 第一行:导演/主演
director_line = info_lines[0] if len(info_lines) > 0 else ""
director = director_line.split("导演:")[-1].split("主演:")[0].strip() if "导演:" in director_line else ""
# 第二行:年份/国家/类型
year_line = info_lines[1] if len(info_lines) > 1 else ""
year_info = year_line.split("/")
year = year_info[0].strip() if len(year_info) > 0 else ""
country = year_info[1].strip() if len(year_info) > 1 else ""
movie_type = year_info[2].strip() if len(year_info) > 2 else ""
# 存入字典
movie_info = {
"排名": rank,
"电影名称": title,
"别名": other_title,
"导演": director,
"上映年份": year,
"国家": country,
"类型": movie_type,
"评分": rating,
"评价人数": comment_num,
"简介": quote
}
page_movies.append(movie_info)
print(f"已提取:排名{rank} - {title}")
except Exception as e:
print(f"单条电影数据解析失败:", e)
continue
return page_movies
# 主函数:循环爬取所有页面
def main():
print("开始爬取豆瓣电影Top250")
print("="*80)
# 循环10页,offset从0到225,步长25
for offset in range(0, 250, 25):
page_url = f"{base_url}?start={offset}&filter="
print(f"\n正在爬取第{int(offset/25 + 1)}页,URL:{page_url}")
# 获取页面源码
html = get_page_html(page_url)
if not html:
print(f"第{int(offset/25 + 1)}页获取失败,跳过")
continue
# 解析页面数据
page_movies = parse_movie_list(html)
if page_movies:
all_movies.extend(page_movies)
print(f"第{int(offset/25 + 1)}页爬取完成,成功提取{len(page_movies)}条数据")
else:
print(f"第{int(offset/25 + 1)}页未提取到有效数据")
print("\n" + "="*80)
print(f"所有页面爬取完成,共提取{len(all_movies)}条电影数据")
# 保存数据到CSV文件
if all_movies:
df = pd.DataFrame(all_movies)
df.to_csv("豆瓣电影Top250.csv", index=False, encoding="utf-8-sig")
print("数据已保存到 豆瓣电影Top250.csv")
# 执行主函数
if __name__ == "__main__":
main()
5.3 运行说明
- 提前安装所需依赖:
pip install requests beautifulsoup4 lxml pandas fake_useragent; - 直接运行代码,程序会自动爬取 10 页数据,控制台实时打印爬取进度;
- 爬取完成后,会在代码同级目录生成
豆瓣电影Top250.csv文件,可用 Excel 打开查看完整数据。
六、爬虫数据存储方案
爬取到的结构化数据,需要根据数据量和使用场景选择合适的存储方式,以下是 3 种最常用的存储方案,覆盖绝大多数入门场景。
6.1 TXT 文本存储
适合少量、简单的文本数据,优点是操作简单、无需额外依赖,缺点是不支持结构化查询。
python
运行
# 写入TXT文件
with open("data.txt", "w", encoding="utf-8") as f:
for item in data_list:
# 每条数据一行,用分隔符分割字段
f.write(f"{item['标题']}|{item['链接']}|{item['发布时间']}\n")
# 读取TXT文件
with open("data.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
title, link, date = line.strip().split("|")
print(title, link, date)
五、爬虫避坑指南与进阶学习路线
5.1 新手必看避坑指南
- 法律红线绝对不能碰:严禁爬取个人隐私、涉密数据、付费内容,严禁破解网站防护、DDoS 攻击服务器,否则将承担民事甚至刑事责任;
- 优先使用官方 API:如果目标平台提供了官方 API 接口(如天气、电商开放平台),优先使用 API 获取数据,比爬虫更稳定、合规;
- 异常处理必须完善:爬虫运行中会遇到网络超时、页面结构变化、反爬拦截等各种问题,必须添加 try-except 异常捕获,避免单条数据错误导致整个程序崩溃;
- 先小范围测试,再大规模爬取:先爬取 1-2 页测试解析规则和反爬应对,确认无误后再全量爬取,避免大规模请求后发现规则错误,浪费时间和 IP 资源;
- 尊重网站服务器:严格控制请求频率,避免高频并发请求,不要因为爬虫导致网站服务器瘫痪,这既是合规要求,也是程序员的基本素养。
更多推荐



所有评论(0)