Python 爬虫案例:爬取豆瓣电影 Top250 数据

一、案例背景与目标

豆瓣电影 Top250 是国内权威的电影评分榜单之一,包含电影名称、评分、评价人数、导演、主演、上映年份、国家 / 地区、类型等关键信息。本案例将使用 Python 编写爬虫,实现以下目标:

  1. 自动请求豆瓣电影 Top250 的 10 个分页(每页 25 部电影);
  2. 解析页面 HTML 结构,提取每部电影的 8 项核心信息;
  3. 数据清洗(处理异常字符、统一格式);
  4. 将最终数据保存到 Excel 文件,方便后续分析。

二、技术栈选择

本案例使用轻量级且易上手的技术组合,适合爬虫初学者:

工具 / 库作用
requests发送 HTTP 请求,获取网页源代码
BeautifulSoup4解析 HTML 文档,提取目标数据(非结构化→结构化)
pandas数据清洗、整理,并将数据写入 Excel
time控制请求间隔,避免触发网站反爬机制
user-agent伪装浏览器请求头,绕过基础反爬

三、完整代码实现

# 1. 导入所需库
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time# 2. 定义核心配置
# 豆瓣电影 Top250 分页 URL 规律:start 参数从 0 开始,每次加 25(0、25、50...225)
BASE_URL = "https://movie.douban.com/top250?start={}&filter="
# 伪装浏览器请求头(避免被识别为爬虫)
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
}
# 存储所有电影数据的列表
movie_list = []# 3. 定义页面解析函数(提取单页电影数据)
def parse_movie_page(html):# 初始化 BeautifulSoup 解析器(指定 lxml 解析器,效率更高)soup = BeautifulSoup(html, "lxml")# 定位所有电影项的父容器(每个 li 对应一部电影)movie_items = soup.find_all("li", class_="item")for item in movie_items:# 3.1 提取电影名称(默认取第一个中文名称)title_tag = item.find("span", class_="title")movie_name = title_tag.get_text(strip=True) if title_tag else "未知名称"# 3.2 提取评分rating_tag = item.find("span", class_="rating_num")rating = rating_tag.get_text(strip=True) if rating_tag else "0.0"# 3.3 提取评价人数(处理格式,如 "123.4万人评价" → "1234000")comment_tag = item.find("span", text=lambda x: x and "人评价" in x)comment_count = comment_tag.get_text(strip=True).replace("人评价", "").replace("万", "0000") if comment_tag else "0"# 3.4 提取导演和主演(格式:"导演: 张艺谋 主演: 沈腾, 马丽")info_tag = item.find("div", class_="bd").find("p", class_="")info_text = info_tag.get_text(strip=True).split("\n") if info_tag else ["", ""]director_actor = info_text[0].strip() if len(info_text) > 0 else "未知信息"# 3.5 提取上映年份、国家/地区、类型(格式:"2023 / 中国大陆 / 喜剧, 剧情")detail_text = info_text[1].strip() if len(info_text) > 1 else "未知 / 未知 / 未知"detail_list = detail_text.split(" / ")release_year = detail_list[0].strip() if len(detail_list) > 0 else "未知年份"country = detail_list[1].strip() if len(detail_list) > 1 else "未知国家"genre = detail_list[2].strip() if len(detail_list) > 2 else "未知类型"# 3.6 提取电影简介(处理可能的空值)quote_tag = item.find("span", class_="inq")intro = quote_tag.get_text(strip=True) if quote_tag else "无简介"# 3.7 将单部电影数据存入字典movie_dict = {"电影名称": movie_name,"评分": rating,"评价人数": comment_count,"导演&主演": director_actor,"上映年份": release_year,"国家/地区": country,"类型": genre,"简介": intro}movie_list.append(movie_dict)# 4. 定义主爬虫函数(循环请求所有分页)
def crawl_douban_top250():# 循环 10 个分页(start=0,25,...,225)for page in range(10):start = page * 25url = BASE_URL.format(start)print(f"正在爬取第 {page+1} 页,URL:{url}")try:# 4.1 发送 GET 请求(添加超时控制,避免无限等待)response = requests.get(url, headers=HEADERS, timeout=10)# 4.2 检查请求是否成功(状态码 200 表示正常)response.raise_for_status()  # 若状态码非 200,抛出 HTTPError 异常# 4.3 解析当前页面数据parse_movie_page(response.text)# 4.4 控制请求间隔(1-2 秒),避免给服务器造成压力,降低反爬风险time.sleep(1.5)except requests.exceptions.RequestException as e:print(f"爬取第 {page+1} 页失败,错误原因:{str(e)}")continue  # 跳过失败页面,继续爬取下一页# 5. 定义数据保存函数(保存到 Excel)
def save_to_excel():if not movie_list:print("无数据可保存!")return# 5.1 将列表转换为 DataFrame(pandas 数据结构,便于处理)df = pd.DataFrame(movie_list)# 5.2 数据清洗:处理评价人数的数值格式(如 "123.4000" → 1234000)df["评价人数"] = pd.to_numeric(df["评价人数"].str.replace(".", ""), errors="coerce").fillna(0).astype(int)# 5.3 保存到 Excel(index=False 表示不保存行号)excel_path = "豆瓣电影Top250数据.xlsx"df.to_excel(excel_path, index=False, engine="openpyxl")print(f"数据已成功保存到:{excel_path}")print(f"共爬取到 {len(movie_list)} 部电影数据")# 6. 程序入口(执行爬虫流程)
if __name__ == "__main__":print("开始爬取豆瓣电影 Top250 数据...")crawl_douban_top250()  # 1. 爬取数据save_to_excel()        # 2. 保存数据print("爬取任务完成!")

四、代码解析(关键步骤拆解)

1. 环境准备(安装依赖库)

在运行代码前,需要确保所有必要的 Python 库都已正确安装。这些库分别承担不同的功能:

  • requests:用于发送 HTTP 请求,获取网页内容
  • beautifulsoup4:用于解析 HTML 文档,提取所需数据
  • pandas:用于数据处理和分析
  • openpyxl:作为 pandas 的依赖,用于写入 Excel 文件
  • lxml:作为 BeautifulSoup 的解析器,提供高效的 HTML 解析能力

安装命令:

pip install requests beautifulsoup4 pandas openpyxl lxml

提示:如果是在国内网络环境,建议使用国内镜像源加速安装,例如:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests beautifulsoup4 pandas openpyxl lxml

2. 反爬机制规避(核心细节)

网络爬虫需要尊重目标网站的规则,同时也要采取适当措施避免被网站识别并封锁。本代码中采用了多种反爬策略:

2.1 伪装请求头
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
}

这是最基础也最重要的反爬措施。网站服务器通过User-Agent字段识别访问者身份,默认情况下,requests库的请求头会显示为 "python-requests/xx.x.x",很容易被识别为爬虫。通过设置一个真实的浏览器User-Agent,可以模拟正常用户的浏览器访问。

你可以通过访问https://httpbin.org/get查看自己浏览器的User-Agent并替换。

2.2 控制请求频率
time.sleep(1.5)

这行代码的作用是在爬取完一页后暂停 1.5 秒再继续。短时间内发送大量请求是爬虫最明显的特征之一,通过添加合理的延迟,可以模拟人类浏览网页的行为,降低被网站识别的概率。

延迟时间可以根据实际情况调整,一般建议在 1-3 秒之间。对于反爬严格的网站,可能需要更长的延迟。

2.3 异常处理机制
try:# 发送请求的代码
except requests.exceptions.RequestException as e:print(f"爬取第 {page+1} 页失败,错误原因:{str(e)}")continue

这段异常处理代码可以捕获所有与请求相关的异常,包括网络连接错误、超时、HTTP 错误状态码等。当某一页爬取失败时,程序不会崩溃,而是会打印错误信息并继续爬取下一页,保证了程序的健壮性。

response.raise_for_status()方法会在 HTTP 请求返回错误状态码(4xx 或 5xx)时抛出异常,让我们能够及时发现并处理请求错误。

3. HTML 解析逻辑(如何定位数据)

解析 HTML 是爬虫的核心步骤,需要仔细分析网页结构,找到目标数据所在的位置。我们可以通过浏览器的开发者工具(F12)来查看网页的 HTML 结构。

3.1 分析网页结构

豆瓣电影 Top250 的页面结构具有一定的规律性:

  • 所有电影条目都包含在<ul class="grid_view">标签中
  • 每个电影条目对应一个<li class="item">标签
  • 每个条目中包含了电影的各种信息:名称、评分、评价人数等
3.2 提取电影列表
movie_items = soup.find_all("li", class_="item")

这行代码使用find_all方法查找所有class为 "item" 的li标签,每个标签对应一部电影的信息。返回的movie_items是一个列表,包含了当前页面所有电影的信息。

3.3 提取单个电影信息
3.3.1 提取电影名称
title_tag = item.find("span", class_="title")
movie_name = title_tag.get_text(strip=True) if title_tag else "未知名称"

电影名称位于class为 "title" 的span标签中。get_text(strip=True)方法用于获取标签内的文本内容,并去除前后的空白字符。通过if title_tag else "未知名称"的判断,可以处理标签不存在的情况,避免程序出错。

3.3.2 提取评分
rating_tag = item.find("span", class_="rating_num")
rating = rating_tag.get_text(strip=True) if rating_tag else "0.0"

评分信息位于class为 "rating_num" 的span标签中。同样使用了条件判断来处理可能的缺失情况。

3.3.3 提取评价人数
comment_tag = item.find("span", text=lambda x: x and "人评价" in x)
comment_count = comment_tag.get_text(strip=True).replace("人评价", "").replace("万", "0000") if comment_tag else "0"

评价人数的提取相对复杂一些,因为它没有特定的class名称。这里使用了一个 lambda 函数作为筛选条件,查找文本中包含 "人评价" 的span标签。

提取到文本后,还需要进行处理:

  • 去除 "人评价" 字符串
  • 将 "万" 转换为 "0000",以便后续转换为数字
3.3.4 提取导演和主演
info_tag = item.find("div", class_="bd").find("p", class_="")
info_text = info_tag.get_text(strip=True).split("\n") if info_tag else ["", ""]
director_actor = info_text[0].strip() if len(info_text) > 0 else "未知信息"

导演和主演信息位于class为 "bd" 的div标签下的第一个p标签中。这里的find("p", class_="")表示查找没有class属性的p标签。

获取文本后,使用split("\n")按换行符分割,取第一部分作为导演和主演信息。

3.3.5 提取上映年份、国家 / 地区、类型
detail_text = info_text[1].strip() if len(info_text) > 1 else "未知 / 未知 / 未知"
detail_list = detail_text.split(" / ")
release_year = detail_list[0].strip() if len(detail_list) > 0 else "未知年份"
country = detail_list[1].strip() if len(detail_list) > 1 else "未知国家"
genre = detail_list[2].strip() if len(detail_list) > 2 else "未知类型"

这部分信息位于上一步中分割得到的info_text的第二部分,格式为 "年份 / 国家 / 地区 / 类型"。我们使用split(" / ")按 "/" 分割,得到一个包含三个元素的列表,分别对应年份、国家 / 地区和类型。

每个字段都添加了条件判断,以处理可能的缺失情况,保证程序的稳定性。

3.3.6 提取电影简介
quote_tag = item.find("span", class_="inq")
intro = quote_tag.get_text(strip=True) if quote_tag else "无简介"

电影简介位于class为 "inq" 的span标签中。同样添加了条件判断,处理没有简介的情况。

3.3.7 存储电影数据
movie_dict = {"电影名称": movie_name,"评分": rating,"评价人数": comment_count,"导演&主演": director_actor,"上映年份": release_year,"国家/地区": country,"类型": genre,"简介": intro
}
movie_list.append(movie_dict)

将提取到的各项信息存入一个字典,然后将字典添加到movie_list列表中。这样处理后,movie_list将包含当前页面所有电影的信息。

4. 数据清洗与保存

4.1 数据转换
df = pd.DataFrame(movie_list)

使用 pandas 库将列表转换为 DataFrame,这是一种二维表格数据结构,便于进行数据处理和分析。

4.2 数据清洗
df["评价人数"] = pd.to_numeric(df["评价人数"].str.replace(".", ""), errors="coerce").fillna(0).astype(int)

这行代码对 "评价人数" 进行清洗和转换:

  • str.replace(".", ""):去除字符串中的小数点,处理 "123.4 万" 这种格式
  • pd.to_numeric(..., errors="coerce"):将字符串转换为数值类型,无法转换的将设为 NaN
  • fillna(0):将 NaN 值替换为 0
  • astype(int):转换为整数类型

经过这些处理,"评价人数" 字段将成为干净的整数,便于后续的统计分析。

4.3 保存到 Excel
excel_path = "豆瓣电影Top250数据.xlsx"
df.to_excel(excel_path, index=False, engine="openpyxl")

使用 pandas 的to_excel方法将数据保存到 Excel 文件:

  • index=False:表示不保存 DataFrame 的索引列
  • engine="openpyxl":指定使用 openpyxl 库作为引擎,支持.xlsx 格式

保存完成后,会打印保存路径和爬取到的电影数量,方便用户确认结果。

5. 主程序流程

if __name__ == "__main__":print("开始爬取豆瓣电影 Top250 数据...")crawl_douban_top250()  # 1. 爬取数据save_to_excel()        # 2. 保存数据print("爬取任务完成!")

这是程序的入口点,使用if __name__ == "__main__":确保只有在直接运行该脚本时才会执行以下代码,而在被导入为模块时不会执行。

五、运行结果与验证

  1. 运行代码:执行程序后,控制台会输出爬取进度(如 “正在爬取第 1 页...”);
  2. 生成文件:程序结束后,当前目录会生成 豆瓣电影Top250数据.xlsx 文件;
  3. 验证数据:打开 Excel 文件,可看到 250 行数据(若部分页面爬取失败,行数可能少于 250),列包含 “电影名称”“评分” 等 8 项信息,数据格式统一、无乱码。

六、拓展与注意事项

1. 功能拓展

  • 多线程爬取:使用 threading 或 concurrent.futures 库实现多线程,提升爬取速度(注意控制线程数,避免给服务器造成过大压力);
  • 数据可视化:用 matplotlib 或 seaborn 绘制评分分布直方图、类型占比饼图等;
  • 增量爬取:记录上次爬取的最后一部电影,下次只爬取更新的数据。

2. 注意事项

  • 遵守网站 robots 协议:豆瓣电影的 robots.txt(https://movie.douban.com/robots.txt)允许爬取 Top250 数据,但需控制频率;
  • 反爬升级应对:若出现 “验证码” 或 “403 禁止访问”,可尝试添加 Cookie(模拟登录状态)、使用代理 IP 池;
  • 法律风险:不得将爬取的数据用于商业用途,遵守《网络安全法》《数据安全法》等法律法规。

通过本案例,可掌握爬虫的核心流程(请求→解析→清洗→保存),理解 HTML 结构分析、反爬规避、数据处理的关键技巧,为后续爬取更复杂网站(如动态加载、需要登录的网站)打下基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/97607.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/97607.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SPA安全警示:OAuth2.0致命漏洞

OAuth2.0在SPA应用中的安全陷阱SPA&#xff08;单页应用&#xff09;通常采用隐式授权&#xff08;Implicit Flow&#xff09;或PKCE&#xff08;Proof Key for Code Exchange&#xff09;授权模式&#xff0c;但存在以下安全隐患&#xff1a;隐式授权模式的漏洞访问令牌直接暴…

table表格字段明细展示

文章目录1、字段渲染2、异步请求展示明细3、hover展示问题3.1 基本逻辑3.2 hover时长判断3.3 renderhover表格字段明细展示&#xff0c;属于比较小的需求&#xff0c;但是也有一定交互细节&#xff0c;本文选取部分场景。 1、字段渲染 render和渲染组件是有区别的。render常见为…

主网上线后生态极速扩张的 Berachain 生态,有哪些值得关注的项目?

Berachain 是典型的将 DeFi 思维嵌入到共识机制中的 Layer1&#xff0c;其核心是 PoL&#xff08;Proof of Liquidity&#xff09;共识。PoL 要求验证者在获得区块奖励前&#xff0c;必须将流动性导入白名单协议&#xff0c;并由市场决定资金流向。这样&#xff0c;验证者的权重…

claude-code对比GitHub-Copilot

Claude Code 文档日期&#xff1a;2025 年 08 月 20 日 定位 项目级开发助手&#xff0c;专注于全局视野和复杂任务的处理。 特点 超长上下文支持&#xff1a;支持 200k 超长上下文&#xff0c;适合处理复杂项目。丰富的自定义命令&#xff1a;提供灵活的命令配置&#xff0c;满…

Roo Code自定义Mode(模式)

什么是自定义模式&#xff1f; 简单来说&#xff0c;自定义模式就像是给Roo Code穿上不同的"职业装"。你可以创建针对特定任务或工作流程量身定制的模式&#xff0c;让Roo在不同场景下表现出专业的行为。 这些模式分为两种类型&#xff1a;全局模式&#xff08;在所有…

Next.js渲染模式:SSR、SSG与ISR揭秘

Next.js 核心渲染模式深度解析&#xff1a;SSR、SSG 与 ISR 在构建现代 Web 应用时&#xff0c;性能和用户体验是至关重要的考量。Next.js 作为 React 生态中一个备受推崇的框架&#xff0c;其强大的服务端渲染&#xff08;SSR&#xff09;、静态站点生成&#xff08;SSG&#…

Veo Videos Generation API 对接说明

本文介绍了如何对接 Veo Videos Generation API&#xff0c;通过输入自定义参数生成Veo官方视频。 下面将详细阐述 Veo Videos Generation API 的对接流程。 申请流程 使用 API 前&#xff0c;需前往 Veo Videos Generation API 页面申请服务。进入页面后&#xff0c;点击「…

YOLO 目标检测:YOLOv3网络结构、特征输出、FPN、多尺度预测

文章目录一、YOLOV31、网络结构1.1 整体结构1.2 主干网络1.3 特征输出1.4 特征融合FPN&#xff08;Feature Pyramid Networks&#xff09;FPN 融合上采样融合2、多尺度预测3、损失函数4、性能对比一、YOLOV3 YOLOv3&#xff08;You Only Look Once v3&#xff09;是YOLO系列中…

【GIS图像处理】有哪些SOTA方法可以用于将1.5米分辨率遥感图像超分辨率至0.8米精度的?

针对将1.5米分辨率遥感图像超分辨率至0.8米的需求,当前主流方法可分为以下几类,结合最新研究进展和实际应用场景,具体技术方案及SOTA方法如下: 一、基于Transformer的高效建模 1. Top-k标记选择Transformer(TTST) 核心机制:通过动态选择前k个关键标记(token),消除冗…

【电力电子】逆变器控制策略:PQ Droop下垂控制、电压电流双环控制与SPWM调制

逆变器中的 PQ Droop 控制。 1. PQ Droop 控制的定义 PQ Droop(有时也称为功率下垂控制,Power Droop Control)是微电网、并联系统或逆变器并网运行中常用的一种分布式功率控制方法。 P-Droop(有功下垂):通过调节逆变器输出频率与有功功率之间的关系实现功率分配。 Q-Dro…

【LeetCode 热题 100】5. 最长回文子串——中心扩散法

Problem: 5. 最长回文子串 文章目录整体思路完整代码时空复杂度时间复杂度&#xff1a;O(N^2)空间复杂度&#xff1a;O(1)整体思路 这段代码旨在解决经典的 “最长回文子串” (Longest Palindromic Substring) 问题。问题要求在一个给定的字符串 S 中&#xff0c;找到一个最长…

六、练习3:Gitee平台操作

练习3&#xff1a;Gitee平台操作 练习目标 掌握Gitee平台的基本操作&#xff0c;包括创建仓库、推送代码、团队协作等。 练习步骤 步骤1&#xff1a;Gitee账号准备 访问 gitee.com注册账号&#xff08;如果还没有&#xff09;登录Gitee 步骤2&#xff1a;配置SSH密钥 # …

Git软件版本控制

软件版本控制作用&#xff1a;软件源码版本管理、多人协作开发、版本多分支开发、代码回滚&#xff08;回退&#xff09;等功能。集中式版本控制&#xff1a;将代码仓库放在一台服务器上&#xff0c;开发时要依赖这台服务器。优点&#xff1a;简单、方便管理、适合中小型项目缺…

生产环境Spark Structured Streaming实时数据处理应用实践分享

生产环境Spark Structured Streaming实时数据处理应用实践分享 一、业务场景描述 我们所在的电商平台需要实时监控用户行为数据&#xff08;如点击、下单、支付等&#xff09;&#xff0c;基于事件级别的流式数据进行实时统计、会话聚合、漏斗分析&#xff0c;并将结果推送到Da…

海康相机开发---HCNetSDK

HCNetSDK&#xff08;Hikvision Network Software Development Kit&#xff09;是海康威视专为旗下安防监控设备打造的二次开发工具包&#xff0c;是连接上层应用与海康设备的核心桥梁。其封装了设备底层通信协议&#xff08;包括私有协议与部分标准协议&#xff09;&#xff0…

构建无广告私人图书馆Reader与cpolar让电子书库随身携带

文章目录前言&#xff1a;告别书荒&#xff0c;拯救灵魂的“摸鱼神器”1、关于Reader&#xff1a;小而美的开源在线阅读器2、Docker部署3、简单使用reader和添加书源4.群晖安装Cpolar工具5.创建reader阅读器的公网地址6.配置固定公网地址前言&#xff1a;告别书荒&#xff0c;拯…

amd cpu是x86架构吗

是的&#xff0c;AMD CPU属于x86架构‌&#xff0c;其64位扩展&#xff08;x86-64&#xff09;最初由AMD设计并成为行业标准。‌ ‌AMD与x86架构的关系‌ ‌技术渊源‌&#xff1a;AMD自1976年起通过技术授权成为x86架构的合法制造商&#xff0c;与英特尔共同主导x86市场。2003…

vercel上线资源无法加载

背景&#xff1a;在本地跑开发服务器没问题&#xff0c;但是部署到 vercel 上就有问题上一次出现类似问题是在更新游戏引擎方法后本地可以跑但是上线没有成功&#xff0c;当时是因为 runner.html 是在部署时通过脚本从远端仓库拉取的&#xff0c;所以解决方案&#xff1a;1.更新…

Node.js 的模块化规范是什么?CommonJS 和 ES6 模块有什么区别?

目录 一、为什么需要模块化&#xff1f; 二、Node.js 的模块化规范 三、CommonJS 模块化 1. 基本语法 2. 特点 3. 缺点 四、ES6 模块&#xff08;ESM&#xff09; 1. 基本语法 2. 特点 3. 在 Node.js 中的使用 五、CommonJS 和 ES6 模块的区别 六、实际开发中的选择…

设计模式:代理模式(Proxy Pattern)

文章目录一、代理模式的定义二、实例分析三、示例代码一、代理模式的定义 代理模式是一种结构型设计模式&#xff0c;它为某个对象提供一个代理或占位符&#xff0c;以控制对这个对象的访问。简单来说代理对象在客户端和目标对象之间起到中介作用&#xff0c;客户端并不会直接操…