开发记录:豆瓣电影榜单爬虫

发布时间:2026/9/18 4:09:38

开发记录:豆瓣电影榜单爬虫 概述旨在爬取豆瓣电影榜单https://movie.douban.com/chart中各电影的详细信息包括名称、年份、片长、类型、导演、演员和剧情简介并将数据保存为 CSV 文件。开发过程中逐步完善了请求头、XPath 解析、异常处理、数据持久化及反爬策略。版本迭代记录v0.1 (2026-07-20) - 基础框架搭建文件01_网络机器人-电影榜单.py主要更新定义基础请求头User-Agent、Referer 等。实现榜单页请求与状态码检查。使用lxml解析 HTML通过 XPath 定位电影条目//table[width100%]。预留get_movie_info()和save_all_movies()函数仅pass占位。遍历电影条目提取详情页链接并打印未调用详情函数。存在问题未实现详情页数据提取all_movie列表始终为空。缺少异常处理与重试机制。无随机延时容易被反爬。v0.2 (2026-07-22) - 详情页解析与数据保存文件02_网络机器人-电影榜单.py主要更新完善get_movie_info()发送详情页请求解析名称、年份、类型、导演、描述使用固定 XPath。实现save_all_movies()将数据写入 CSV 文件指定字段名。扩展全局HEADERS加入 Cookie、Accept-Encoding 等模拟真实浏览器。主函数中调用详情函数并打印调试信息。遗留缺陷关键 bugall_movie列表未被填充未执行append导致 CSV 始终只有表头。XPath 路径脆弱仅依赖单一表达式豆瓣页面结构变化时易失效。无请求失败重试网络波动可能中断程序。v0.3 (2026-07-25) - 健壮性与容错增强文件03_网络机器人-电影榜单.py主要更新修复核心 bug在main()循环中将获取到的movie_info通过all_movie.append(movie_info)正确添加到列表。增加异常处理对requests.get()捕获异常避免程序崩溃。增加内容长度校验详情页响应小于 1000 字节时视为被反爬打印前 500 字符辅助调试。扩展 XPath 备选路径针对名称、年份、类型、导演、描述均提供多种定位方式提高适应性。引入随机延时每部电影请求后time.sleep(random.uniform(1.0, 2.5))降低请求频率。自动创建 CSV 输出目录os.makedirs避免路径不存在错误。效果程序可完整获取榜单中所有电影的详情数据并正确写入 CSV。面对页面结构调整或临时反爬时容错性显著提升。v0.4 (2026-07-28) - 字段扩展与数据丰富文件04_网络机器人-电影榜单.py主要更新新增片长v:runtime和演员字段丰富电影信息维度。演员提取采用主演标签后的a文本多个演员用 / 连接。更新 CSV 列名[名称, 年份, 片长, 类型, 导演, 演员, 描述]。优化描述提取优先级优先使用v:summary其次span[classall]最后旧版路径。改进意义采集的数据更加全面满足后续分析或展示需求。字段结构更贴近电影主页实际内容。v0.5 (2026-07-30) - 最终稳定版本内容同 v0.4文件05_网络机器人-电影榜单.py说明此版本与 v0.4 代码完全一致未做功能改动。命名调整可能为了版本管理统一实际以 v0.4 为最终发行版。最终成果总结import requests import csv from lxml import html import os import time import random MOVIE_LIST_FILE csv_data/movie_list.csv DOUBAN_BASE_URL https://movie.douban.com DOUBAN_TOP_URL https://movie.douban.com/chart 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, Cookie: ll118201; bidmV59O_L0Z88; _pk_id.100001.4cf6906f4c077c4e286a.1784944501.; _vwo_uuid_v2DA6D5EB58DC057096520FFE47A8EECEFD|78ce2ecada7a16f9034a20c3961fe216; dbcl2296323525:ylL/ts6TrE; push_noty_num0; push_doumail_num0; cksfI2; _pk_ref.100001.4cf6%5B%22%22%2C%22%22%2C1785149957%2C%22https%3A%2F%2Fcn.bing.com%2F%22%5D; _pk_ses.100001.4cf61; __utma30149280.570823089.1784944501.1784944501.1785149957.2; __utmb30149280.0.10.1785149957; __utmc30149280; __utmz30149280.1785149957.2.2.utmcsrcn.bing.com|utmccn(referral)|utmcmdreferral|utmcct/; __utma223695111.164060955.1784944501.1784944501.1785149957.2; __utmb223695111.0.10.1785149957; __utmc223695111; __utmz223695111.1785149957.2.2.utmcsrcn.bing.com|utmccn(referral)|utmcmdreferral|utmcct/; ap_v0,6.0; frodotk_dbb2d4bee9cf2e9d30187e3cbd6d8bd790, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Accept-Encoding: gzip, deflate, br, Connection: keep-alive, Upgrade-Insecure-Requests: 1, Sec-Fetch-Dest: document, Sec-Fetch-Mode: navigate, Sec-Fetch-Site: same-origin, } def get_movie_info(movie_info_url): 获取单部电影的详细信息 print(f正在请求详情页: {movie_info_url}) try: movie_response requests.get(movie_info_url, headersHEADERS, timeout15) except Exception as e: print(f请求异常: {e}) return None if movie_response.status_code ! 200: print(f请求失败状态码: {movie_response.status_code}) return None if len(movie_response.text) 1000: print(内容过短可能被反爬前500字符) print(movie_response.text[:500]) return None movie_document html.fromstring(movie_response.text) # 提取字段使用多种备选 XPath # 名称 name_list movie_document.xpath(//h1/span[1]/text()) if not name_list: name_list movie_document.xpath(//*[idcontent]/h1/span[1]/text()) name name_list[0].strip() if name_list else # 年份 year_list movie_document.xpath(//h1/span[2]/text()) if not year_list: year_list movie_document.xpath(//*[idcontent]/h1/span[2]/text()) year year_list[0].strip() if year_list else # 时长 time_list movie_document.xpath(//div[idinfo]//span[propertyv:runtime]/text()) time time_list[0].strip() if time_list else # 类型 type_elems movie_document.xpath(//span[contains(text(), 类型)]/following-sibling::a/text()) if not type_elems: type_elems movie_document.xpath(//*[idinfo]/span[5]/text()) type_str ,.join([t.strip() for t in type_elems if t.strip()]) # 导演 director_elems movie_document.xpath(//span[contains(text(), 导演)]/following-sibling::a/text()) if not director_elems: director_elems movie_document.xpath(//*[idinfo]/span[1]/span[2]/a/text()) director director_elems[0].strip() if director_elems else # 演员 actor_elems movie_document.xpath(//div[idinfo]//span[contains(text(), 主演)]/following-sibling::span/a/text()) if actor_elems: actors / .join([name.strip() for name in actor_elems]) else: actors # 描述剧情简介 desc_elems movie_document.xpath(//span[propertyv:summary]/text()) if not desc_elems: desc_elems movie_document.xpath(//div[idlink-report]//span[classall]/text()) if not desc_elems: desc_elems movie_document.xpath(//*[idlink-report-intra]/span[1]/text()) description .join([d.strip() for d in desc_elems if d.strip()]) movie_info { 名称: name, 年份: year, 片长: time, 类型: type_str, 导演: director, 演员: actors, 描述: description, } print(movie_info) # 控制台显示当前电影信息 return movie_info def save_all_movies(all_movies): 保存所有电影信息到 CSV 文件自动创建目录 dir_name os.path.dirname(MOVIE_LIST_FILE) if dir_name and not os.path.exists(dir_name): os.makedirs(dir_name) print(f已创建目录: {dir_name}) print(f准备写入 {len(all_movies)} 条数据到 CSV) # 调试显示数据条数 with open(MOVIE_LIST_FILE, modew, newline, encodingutf-8) as file: writer csv.DictWriter(file, fieldnames[名称, 年份,片长, 类型, 导演, 演员,描述]) writer.writeheader() if all_movies: writer.writerows(all_movies) print(f成功写入 {len(all_movies)} 条数据) else: print(警告没有数据可写入仅创建了表头) def main(): print(正在获取榜单页...) try: response requests.get(DOUBAN_TOP_URL, headersHEADERS, timeout20) except Exception as e: print(f请求榜单页异常: {e}) return print(f状态码: {response.status_code}, 内容长度: {len(response.text)}) if response.status_code ! 200 or len(response.text) 100: print(榜单页获取失败或内容为空) return document html.fromstring(response.text) # 定位电影条目多种备选 movie_list document.xpath(//table[width100%]) if not movie_list: movie_list document.xpath(//div[classitem]) if not movie_list: movie_list document.xpath(//*[idcontent]/div/div/div/div/table[width100%]) print(f找到 {len(movie_list)} 个电影条目) all_movie [] # 用于收集所有电影数据 for idx, movie in enumerate(movie_list, 1): # 提取详情页链接 url_elements movie.xpath(.//a[classnbg]/href) if not url_elements: url_elements movie.xpath(.//a/href) if not url_elements: print(f第 {idx} 个条目未找到链接跳过) continue movie_info_url url_elements[0] if not movie_info_url.startswith(http): movie_info_url DOUBAN_BASE_URL movie_info_url # 获取电影信息 movie_info get_movie_info(movie_info_url) if movie_info: all_movie.append(movie_info) # --- 关键修复添加数据到列表 print(f当前已收集 {len(all_movie)} 部电影) else: print(f第 {idx} 个详情页获取失败返回 None) # 随机延时避免请求过快 time.sleep(random.uniform(1.0, 2.5)) # 保存数据 save_all_movies(all_movie) if __name__ __main__: main()功能稳定爬取豆瓣电影榜单当前榜单页所有电影的 7 项信息并保存为csv_data/movie_list.csv。技术要点请求头模拟真实浏览器含 Cookie降低反爬风险。多 XPath 备选策略适配页面结构变化。异常捕获与超时设置增强鲁棒性。随机延时控制请求频率避免 IP 被封。自动目录创建提升用户体验。已知限制仅处理榜单第一页/chart未实现分页爬取。Cookie 可能过期需定期更新。描述字段可能包含过长文本CSV 显示需注意。后续优化建议实现多页榜单爬取通过?start...参数。将 Cookie 独立为配置文件便于更新。增加日志记录模块替代print调试输出。使用代理池轮换 IP进一步提高稳定性。
延伸阅读

更多相关文章

2026/9/18 4:09:37

Linux下PHY寄存器访问:从原理到实战的调试指南

1. 项目概述:为什么要在Linux下访问PHY寄存器?搞嵌入式或者网络驱动开发的朋友,应该都跟PHY芯片打过交道。PHY,这个负责把数字信号和物理线路上的模拟信号互相转换的小东西,是任何有线网络设备的基石。在Linux系统里&a…

2026/9/14 8:07:47

电容式传感器原理、电路设计与工程实践全解析

1. 从“触摸”到“感知”:电容式传感器的核心价值你可能每天都在和它打交道,却未必真正了解它。从智能手机的触摸屏,到汽车门把手的无钥匙进入,再到工厂里精确测量液位的传感器,背后都有一个共同的技术核心——电容式传…

2026/9/11 2:55:05

STM32程序下载全解析:串口ISP、ST-LINK调试与Utility烧录实战指南

1. 项目概述:STM32程序下载的三种核心路径对于每一位STM32开发者来说,给芯片“灌入”程序是项目从代码到实物的第一步,也是最基础、最频繁的操作。我刚接触STM32时,面对五花八门的下载方式也犯过迷糊:为什么有的要用串…

2026/9/18 4:06:19

同一把 TaoToken Key:Agent 技能验证在 FLAWED 下的消耗

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 4:06:19

【ComfyUI】Wan2.2 Animate 动作迁移重绘视频生成

今天为大家带来一个ComfyUI强大的 Wan2.2 Animate 全局动作迁移与视频重绘视频生成。该工作流融合了视频帧重建、动作迁移、图像重绘和音频合成等多种 AI 技术,打造了一个可以将参考视频与图像进行动作与风格融合,并生成高质量新视频的全流程解决方案。通过视觉特征提取、模型…

2026/9/18 4:06:19

【ComfyUI】Wan2.2 智能关键词驱动图像超分视频生成

这次为大家演示的,是一个基于 Wan2.2 的原图与关键词智能润色视频生成工作流。它通过对输入图像进行特征抽取、尺寸适配与编码,再结合自动生成的中文描述和翻译后的英文关键词,让模型以更贴近原图风格的方式完成从图到视频的生成。整个流程会…

2026/9/18 4:06:19

DBeaver 连接数据库完整教程:零基础 3 步连上你的第一张表

DBeaver 连接数据库完整教程:零基础 3 步连上你的第一张表 【免费下载链接】dbeaver Free universal database tool and SQL client 项目地址: https://gitcode.com/GitHub_Trending/db/dbeaver DBeaver 是一款免费的多数据库管理与 SQL 客户端,一…

2026/9/18 4:01:19

Linux命令拾遗-top中的%nice是啥

简介# 这是Linux命令拾遗系列的第八篇,本篇主要介绍top命令中nice%这个指标的含义以及进程优先级相关内容。 在各种查看CPU使用率的工具中(如top),一般都有us%、sy%、ni%等,us%与sy%含义是比较容易理解的,一个是用户态CPU使用率…

2026/9/16 12:52:37

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/18 0:01:09

Google Colab 实战:运行模型、数据加载与报错排查

1. 为什么我劝你先搞懂 Colab 的运行模型1.1 Colab 到底是什么,跟本地跑代码差在哪Google Colab 简单说就是一台跑在浏览器里的 Linux 虚拟机,你打开一个 Notebook,背后就连上了一台带 GPU 的远程机器。你在单元格里敲的每一行 Python&#x…

2026/9/18 0:01:09

C语言数据类型与表达式详解

1. C语言数据与数据类型概述在C语言编程中,数据是程序处理的核心对象。理解数据的分类和特性是掌握C语言的基础。C语言中的数据主要分为四大类:常量、变量、表达式和函数。这些数据类型构成了C语言程序的基本元素,每种类型都有其独特的特性和…

2026/9/18 0:01:09

SQL时间字段指定时间段查询:区间语义、索引与时区避坑

上周排查一个线上问题&#xff0c;用户反馈"昨天的订单一条都没查到"&#xff0c;但数据库里明明躺着两千多条。最后定位下来&#xff0c;不是数据丢了&#xff0c;也不是接口挂了&#xff0c;而是那个查询条件把时间段写成了> 2024-05-20 00:00:00 AND < 2024…

2026/9/16 22:55:57

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/16 22:56:09

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/16 22:56:16

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码