ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python爬虫入门实战:从零抓取豆瓣电影评论并做数据分析

Python爬虫入门实战:从零抓取豆瓣电影评论并做数据分析 不知道你有没有过这样的体验想学 Python 爬虫但一打开教程就是“安装 requests发送请求解析网页结束”。你会了这几行却依旧不知道拿到网页之后那个评论到底藏在 HTML 的哪个角落里为什么有时候请求能成功有时候又突然被拦。我遇到过很多人拿着别人的脚本跑了一遍换一部电影就失效换个网站更是直接懵掉。说白了爬虫真正值钱的部分从来不是那几行请求代码而是你理解网页、理解数据、理解反爬机制的过程。如果你想找一个“难度适中、页面结构不复杂、又有真实反爬场景”的练手项目豆瓣电影评论真的是一个非常合适的起点。它的网页结构对于新手很友好评论数据又属于公开可见的内容不需要登录就能看到部分短评。更重要的是它有一些基础的反爬机制比如 User-Agent 校验、请求频率限制能让你在入门阶段就建立正确的采集观念而不是像很多培训课那样教你绕过验证码爬取各种需要登录的平台——那既不安全也带坏节奏。这篇文章我会从零开始讲清楚怎么用 Python 写一个抓取豆瓣电影评论的爬虫。包括环境搭建、网页结构分析、代码逐段拆解、真实踩坑记录以及爬完之后如何做简单的数据分析。整个过程按照公开页面小批量学习抓取来设计不碰登录、不碰验证码、不搞大规模并发这既是安全边界也足够让你掌握爬虫的完整链路。1. 为什么拿豆瓣电影评论当爬虫练手项目这才是第一步要搞明白的事1.1 豆瓣评论这个页面天生适合当爬虫“教学标本”很多人选择练手项目时有个误区觉得越复杂越能学到东西一上来就盯上了需要模拟登录的电商平台、需要处理 JavaScript 渲染的资讯网站。结果写了两天代码连数据都没拿到心气先没了。豆瓣电影评论页面恰好避开了这些坑。它属于服务端渲染的页面也就是说你用 requests 去请求时返回的 HTML 里直接就包含评论内容不需要额外去解析接口、渲染 JS。它的页面结构在几大主流站点里算得上干净每条评论集中在一个div.comment-item里作者、评分、时间、内容都放在明确标签下非常适合作为你第一次接触解析逻辑的对象。还有一个很重要的点豆瓣短评是公开内容不需要登录就能看到一部分。这意味着你可以在完全合规的范围内把学习目标聚焦在“请求”“解析”“存储”“分析”这四件事上而不是被什么签名算法、加密参数搞得一头雾水。入门阶段你真正需要建立的能力是对 HTTP 请求和 HTML 结构的敏感度这些能力在豆瓣页面练熟了后面换任何网站你都知道应该从哪里下手。1.2 动手之前先给自己定三条规矩我见过不少初学者代码跑着跑着就“上头”了本来只想抓一页发现能抓就忍不住翻几千页最后 IP 被封了再来问我怎么解决。在爬虫这件事上技术能力是一方面边界感是另一方面。我自己实践时会给自己约定几条底线也建议你开写之前就明确只抓公开、免费、无需登录即可浏览的数据不碰个人隐私信息和需要授权才可访问的接口。控制请求频率不搞并发轰炸。一个纯学习脚本一两秒请求一次已经非常快了。抓下来的数据只用于个人学习和技术验证不用于商业传播也不用来构建什么所谓的“舆情库”。如果页面提示访问频繁或出现验证码立即停止而不是想办法绕过。你可能会觉得这些规矩太“虚”但实际项目中吃过亏就知道这四条不是道德说教是让你能把爬虫长期玩下去的基本操作。很多技术本身没有问题问题出在采集的方式和用途上。这篇文章的示例会刻意控制在小批量、低频次的范围既是安全实践也能完整覆盖爬虫学习的所有环节。2. 环境准备打开电脑到成功跑出第一行爬虫代码2.1 Python 安装与环境变量老生常谈但是最容易被忽视如果你已经装好了 Python可以跳过这一小节。但如果你是从零开始我想提醒一个细节Windows 下安装 Python 时第一个安装界面底部有一个“Add Python to PATH”的复选框很多人忽略掉它装完发现命令提示符里敲python显示“不是内部或外部命令”。勾选这个选项本质上是把 Python 的安装路径写入系统环境变量让系统知道去哪里找 Python 解释器。没勾选的话你只能打开 Python 安装目录里的 IDLE很多后续的操作流程都会变得别扭。装好之后打开终端验证一下python --version pip --version能显示出版本号说明环境变量没有问题。如果你用的是 Linux 系统大多数发行版会自带 Python 3你只需要再确认一下 pip 是否存在缺少就通过系统包管理器安装python3-pip。macOS 用户则建议直接去 Python 官网下载安装包或者用 Homebrew 安装不要用系统自带的旧版本。2.2 创建虚拟环境这一步能帮你省掉大量后期麻烦很多初学者会有个习惯打开终端就pip install requests直接把依赖包装在全局环境里。早期项目少的时候感觉不到问题等到你写的项目多了每个项目依赖的库版本可能会冲突。比如项目 A 需要 pandas 1.x项目 B 需要 pandas 2.x装来装去就乱套了。虚拟环境的本质是把每个项目的依赖包隔离到独立目录。它在爬虫初学者眼里可能显得多此一举但这是专业开发最基本的工作习惯越早养成越好。你可以先创建一个工作目录然后在终端里执行mkdir douban_spider cd douban_spider python -m venv .venv创建好之后激活环境Windows 终端里执行.venv\Scripts\activatemacOS 或 Linux 终端里执行source .venv/bin/activate终端提示符前面出现(.venv)字样就说明你已经进入虚拟环境了。接下来我再安装本篇文章需要的库pip install requests beautifulsoup4 pandas lxml这四个库分别负责什么我简单说清楚requests用来发送 HTTP 请求拿到网页内容。beautifulsoup4用来解析 HTML定位评论所在的节点。lxml是 BeautifulSoup 的解析引擎解析速度比 Python 内置的 html.parser 快不少。pandas用来整理数据、保存 CSV、后续做简单统计分析。如果安装速度很慢可以使用国内镜像来加速比如在 pip 命令后面加上镜像源参数pip install requests beautifulsoup4 pandas lxml -i https://pypi.tuna.tsinghua.edu.cn/simple这一步做完你的环境就准备好了。2.3 编辑器选哪个不影响大局但调试能力是第一位的编辑器这块我用过 PyCharm后来长期使用 VSCode。哪个更好这种问题其实没有标准答案我更想强调的一点是爬虫调试过程中你会频繁地查看变量内容、查看响应文本、测试 CSS 选择器所以在项目开始前务必把编辑器的调试功能跑通。如果你用 VSCode需要安装 Python 扩展然后按CtrlShiftP输入Python: Select Interpreter选择刚才创建好的虚拟环境。这一步做完你在终端里执行.venv下的 Python和在编辑器里点击运行按钮时用的就是同一个解释器不会出现“终端能 import requests编辑器却找不到模块”的尴尬情况。PyCharm 的配置逻辑类似在 Settings 中找到 Project Interpreter选择已经存在的.venv目录即可。至此环境搭建完成。接下来进入正题搞清楚豆瓣评论页面的结构。3. 剖析豆瓣短评页面结构URL 规律与 HTML 布局3.1 先搞懂 URL 里每个参数是干什么的打开豆瓣电影随便点进一部电影的短评页你会发现 URL 长这样https://movie.douban.com/subject/1292052/comments?statusPsortnew_score拆开看subject/1292052里面的1292052是电影的豆瓣 IDcomments表示进入短评页面。后面的查询参数里statusP表示只看看过用户的评论sortnew_score表示按最新排序。如果你手动在浏览器里访问这个地址从地址栏上你可以轻松看到第一页短评内容。这个页面的 HTML 是服务端渲染后直接返回的因此用 requests 请求后响应文本里就已经包含了评论数据。如果你想爬取其他电影的评论只需要替换 URL 中的电影 ID 即可。比如换一部电影的 IDURL 会变成https://movie.douban.com/subject/XXXXXXX/comments其他结构基本不变。还有另一个值得注意的点这个页面支持分页方式是在 URL 中加入start参数比如start0表示第一页start20表示第二页每页 20 条。之所以是 20是因为豆瓣短评页一页固定输出 20 条数据。我在设计代码时就会利用这个规律进行翻页。不过这里也要多说一句豆瓣对未登录用户能访问的短评页数有限制我建议把采集控制在前面几页内既能学到东西又不会触发太强的风控。3.2 打开开发者工具找到评论数据的坐标拿到 HTML 后下一步就是弄明白评论到底在哪个标签里。我建议你打开浏览器右键点击某条短评正文选择“检查”观察高亮区域所在的标签结构。豆瓣短评页的传统结构中每条评论都包裹在一个div.comment-item里字段大致是这样分布的评论者昵称在div.comment-item下的span.comment-info里进一步找到a标签。评分在评论信息区域的span.rating标签上通过 class 属性来表示分值比如allstar50表示五星allstar40表示四星。评论时间在span.comment-time标签内通常包含title属性和文本。有用数量在span.vote_count标签里显示有多少人认为这条评论有用。评论正文在p.comment-content标签下的span里这是整条评论最核心的部分。我先展示一段经过简化的结构帮助你建立直观认识div classcomment-item div classcomment h3 span classcomment-info a hrefhttps://www.douban.com/people/xxx/某位用户/a span classallstar50 rating title力荐/span span classcomment-time title2024-01-01 12:00:002024-01-01/span /span /h3 p classcomment-content span这是一条非常精彩的评论。/span /p /div /div不要死记这条结构因为豆瓣改版频率不低标签层级随时可能微调。你要学会的是方法拿到 HTML 后先自己搜索一下某个评论里的唯一文本看看它藏在哪个标签下然后再写选择器去提取。有一个调试的小技巧你可以先在 Python 交互环境里把响应文本加载进 BeautifulSoup然后通过soup.select(div.comment-item)验证能否选中评论块。如果选不中请不要盲目改选择器先回头打印resp.text的前几百个字符确认自己到底拿到的是什么内容。4. 一步一步写出完整爬虫请求、解析、翻页、保存4.1 构造一个带请求头的请求避免被拒之门外到了真正写代码的时候了。先创建douban_spider.py文件然后从最基础的部分开始。我们打开一个普通的网页时浏览器会自动携带一大堆请求头信息其中最关键的就是User-Agent它告诉服务器“我是一个浏览器”。而如果你用程序直接发请求默认的User-Agent会把它自己标识为某个 Python 库版本很多网站会因此判断你不是正常访问直接拒绝响应。所以构造请求时我们通常会自己指定一个常见浏览器的 User-Agent。示例代码import requests from bs4 import BeautifulSoup import time import pandas as pd BASE_URL https://movie.douban.com/subject/1292052/comments 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, Referer: https://movie.douban.com/ }这里的BASE_URL是《肖申克的救赎》的短评地址你可以换成任何你想分析的电影 ID。Referer表示请求来源页面部分服务端会校验这个字段加上它会更接近正常的访问路径。然后我们先做一个最简单的请求并把响应文本打印出来def fetch_page(start0): params { start: start, limit: 20, status: P, sort: new_score } resp requests.get(BASE_URL, headersHEADERS, paramsparams, timeout10) resp.encoding utf-8 print(resp.status_code) print(resp.text[:500])如果状态码是 200而且打印出来的内容里包含评论信息恭喜你请求已经通了。假如遇到 403不要急着直接加反反爬措施先确认自己的 User-Agent 是否正确、请求频率是否过快。我们后面会专门总结这些坑。4.2 用 BeautifulSoup 把评论字段提取出来请求没问题之后就开始解析。先加载整个页面soup BeautifulSoup(resp.text, lxml) comments soup.select(div.comment-item)select方法接收 CSS 选择器div.comment-item会选中页面中所有 class 为comment-item的 div。这些 div 的数量理论上应该等于每页的评论条数通常是 20 条。然后遍历这些评论节点提取我们需要的字段def parse_comments(soup): result [] items soup.select(div.comment-item) for item in items: try: author item.select_one(.comment-info a).get_text(stripTrue) rating_span item.select_one(.comment-info .rating) rating_class rating_span.get(class, ) if rating_span else # rating_class 形如 [allstar50, rating] content item.select_one(.comment-content).get_text(stripTrue) time_tag item.select_one(.comment-time) comment_time time_tag.get(title, ) if time_tag else vote_tag item.select_one(.vote_count) vote_count vote_tag.get_text(stripTrue) if vote_tag else 0 result.append({ author: author, rating_class: rating_class, content: content, time: comment_time, vote_count: vote_count }) except AttributeError: # 个别评论可能缺少某个字段跳过总比报错中断好 continue return result这段逻辑里有几个关键的细节我展开解释一下。select_one和select的区别在于前者只返回第一个匹配元素后者返回所有匹配元素。提取某一个字段时用select_one就好。rating_span.get(class, )返回的是一个列表因为 HTML 的 class 属性可能包含多个值比如[allstar50, rating]。我知道allstar50这个类名放在第一位所以后续可以直接把列表转为字符串再判断。这种设计有一个好处就算豆瓣改版时把评分从五星改成了十分制你依然可以通过 class 判断来调整映射不需要重构整个代码。comment_time提取时必须注意span.comment-time的可见文本可能是“2024-01-01”但完整时间戳存在title属性里。想拿更精确的评论时间就必须从属性里取而不是从文本里拿。很多初学者会卡在这一步因为他们只看页面显示的内容没想过更完整的数据藏在属性里。4.3 加一个评分映射把 allstar40 转成人话提取出rating_class后它目前还是类似于allstar50的字符串直接保存虽然能用但不够直观。我们可以写一个小映射把它转成 5 分、4 分这样的数值RATING_MAP { allstar50: 5, allstar45: 4.5, allstar40: 4, allstar35: 3.5, allstar30: 3, allstar25: 2.5, allstar20: 2, allstar15: 1.5, allstar10: 1 } def parse_rating(rating_class): if isinstance(rating_class, list) and rating_class: key rating_class[0] return RATING_MAP.get(key, -1) return -1这样处理过后后续做评分分布统计就简单了。如果豆瓣页面结构里找不到评分标签rating_class的某个位置可能是空遇到这种情况先返回 -1再清洗数据时统一处理不要直接抛异常导致整段代码挂掉。4.4 分页抓取与 CSV 落地既然每条 URL 通过start参数控制页数翻页逻辑就很简单。我们用一个for循环从 0 开始每次让start加 20抓前面 3 到 5 页作为演示。完整代码如下import time import requests from bs4 import BeautifulSoup import pandas as pd BASE_URL https://movie.douban.com/subject/1292052/comments 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, Referer: https://movie.douban.com/ } RATING_MAP { allstar50: 5, allstar45: 4.5, allstar40: 4, allstar35: 3.5, allstar30: 3, allstar25: 2.5, allstar20: 2, allstar15: 1.5, allstar10: 1 } def fetch_page(start0): params { start: start, limit: 20, status: P, sort: new_score } resp requests.get(BASE_URL, headersHEADERS, paramsparams, timeout10) resp.encoding utf-8 if resp.status_code ! 200: print(f请求失败, 状态码: {resp.status_code}, start{start}) return [] soup BeautifulSoup(resp.text, lxml) return parse_comments(soup) def parse_rating(rating_class): if rating_class and isinstance(rating_class, list): return RATING_MAP.get(rating_class[0], -1) return -1 def parse_comments(soup): result [] items soup.select(div.comment-item) for item in items: try: author item.select_one(.comment-info a).get_text(stripTrue) rating_span item.select_one(.comment-info .rating) rating_class rating_span.get(class, ) if rating_span else content_el item.select_one(.comment-content) content content_el.get_text(stripTrue) if content_el else time_tag item.select_one(.comment-time) comment_time time_tag.get(title, ) if time_tag else vote_tag item.select_one(.vote_count) vote_count vote_tag.get_text(stripTrue) if vote_tag else 0 result.append({ author: author, rating: parse_rating(rating_class), content: content, time: comment_time, vote_count: vote_count }) except AttributeError: continue return result if __name__ __main__: all_comments [] # 抓取前5页start 从0开始每次增加20 for page in range(5): start page * 20 print(f正在抓取第 {page 1} 页, start{start}) page_comments fetch_page(start) all_comments.extend(page_comments) time.sleep(1.5) # 控制频率避免请求太快导致被限流 df pd.DataFrame(all_comments) df df.drop_duplicates(subset[author, content, time]) df.to_csv(douban_comments.csv, indexFalse, encodingutf-8-sig) print(f抓取完成共保存 {len(df)} 条评论)这段代码有几个选型上的用意需要解释。page从 0 到 4 意味着我们最多请求 5 次页面。为什么只抓 5 页而不是把整部电影的评论全部抓完一是豆瓣短评对未登录访问本来就有可见范围限制二是自用学习完全没必要追求全量数据抓太多反而增加了被封风险。拿到一两百条评论做分析已经足够体验完整流程。time.sleep(1.5)是请求间隔。这个间隔并不是拍脑袋定的一次正常用户浏览短评页不可能在 0.1 秒内连续翻页。1.5 秒的间隔既不会让等待时间太长又能很好地降低服务端风控的触发概率。drop_duplicates不是刻意去重而是因为你抓取过程中可能因为网络重试、代码手动暂停等原因抓到重复数据。在保存之前对“作者 评论正文 时间”三个字段做去重能保证后续数据质量。CSV 保存时使用utf-8-sig编码而不是普通的utf-8。这个细节在 Windows 上特别重要直接用utf-8保存的中文 CSV用 Excel 打开会乱码而utf-8-sig会在文件开头加上 BOM 标识Excel 就能正确识别中文。4.5 运行与观察结果在终端执行python douban_spider.py正常情况会看到每页的抓取日志最后输出一个 CSV 文件。用文本编辑器打开文件你会看到类似这样的表格内容authorratingcontenttimevote_count某某用户5这是一条好评论……2024-01-02 10:15:0020某某用户24电影整体不错……2024-01-01 22:30:003到这里一个可用的爬虫脚本已经跑通了。但如果只是跑到这里就结束那和网上随便抄的脚本没有什么区别。爬虫里真正的技术沉淀恰恰发生在“脚本失败”的时候。我在反复调试这个项目的过程中踩过几个坑下面挑最典型的分享出来。5. 真实踩坑记录为什么你的接口偶尔 403解析结果又时常为空5.1 请求被拒 403并不是所有“访问太快”都能靠延时解决403 状态码表示服务器拒绝了你的请求。我见过很多新人走极端一遇到 403 就把错误原因归纳为“抓太快”然后疯狂调大time.sleep但问题依旧。其实 403 最常出现的根源是你根本没有设置User-Agent或者你使用的默认User-Agent暴露了“这是一个脚本”的事实。判断方法很简单第一次请求时就把resp.status_code和响应里的前 200 个字符打印出来。如果状态码是 403通常说明请求头不完整如果状态码是 200 但页面内容是一段验证提示说明请求频率可能触发了风控。学会区分这两种情况你在反爬问题上就不会病急乱投医。另外一个很容易被忽略的点是Referer头。豆瓣会对请求来源做一些校验如果直接裸请求评论页而没有带来源页偶尔也会被拒绝。把请求头组里的Referer设置为https://movie.douban.com/能更贴近正常路径。5.2 响应里没有评论内容你可能打印的是“验证页”而不是“页面”这个坑比 403 更隐蔽。有时你的状态码是 200但解析出来的div.comment-item列表是空的。这时候不要急着检查 CSS 选择器先打印resp.text的内容看一下大概率你会看到的是一个验证页面或一个跳转提示页。我把这个知识点放在踩坑部分而不是前面的基础部分是因为新手真的很常遇到但不会排查。请求返回 200不代表服务器给了你想要的内容。有些反爬机制会给你返回一个 200 状态的验证页面页面里没有任何评论数据表面上看起来是解析问题实质上是风控机制在发挥作用。遇到这种情况直接调大间隔、减少抓取页数过一段时间再试即可。5.3 评论正文提取出来为空注意看标签是“直接子节点”还是“嵌套子节点”BeautifulSoup 选择器写错是最常见的解析问题。豆瓣页面的评论正文一般是p classcomment-content span评论文字/span /p如果你误写成item.select_one(.comment-content).get_text()其实也能拿到文字因为get_text()会提取节点下的所有文本所以这个问题不大。更容易踩的坑是取评分时不是所有评论都带有评分区域。有的评论只是“看过”状态但没有点亮星标这时item.select_one(.comment-info .rating)会返回None你再对None调get_text()就会抛 AttributeError。这种时候 try-except 是必要的兜底但你也需要理解为什么会缺字段才能正确决定是跳过还是补默认值。我在代码里遇到缺评分时会返回 -1后续分析时统一过滤掉这样既保留了评论主体又不会让统计失真。5.4 评分明明在页面上显示五颗星为什么提取出来是空如果你已经在浏览器开发者工具里看到了评分元素但在代码里提取不到最常见的原因是你看到的 HTML 和 requests 拿到的 HTML 不是同一个版本。网站有时会根据访问端类型或登录状态返回不同的页面结构。建议你先把resp.text保存成debug.html再用浏览器打开这个文件检查里面是否有评分元素。这能确认你代码里的选择器和实际拿到的 HTML 是否匹配。with open(debug.html, w, encodingutf-8) as f: f.write(resp.text)这个小技巧帮我节省了太多排查时间。浏览器里看到的页面和代码里拿到的页面中间隔着“UA 判断”和“登录状态判断”两层不确定性你只有直接查看自己实际拿到的 HTML才能做出正确判断。5.5 CSV 存入 Excel 后中文全是乱码编码格式问题很多教程喜欢用utf-8编码保存 CSV这个选择本身没问题但如果你用 Excel 打开文件时会发现中文变成了一堆乱码。原因是 Excel 默认以 ANSI 编码打开文件而utf-8和它不兼容。解决方案是用上面代码里已经写到的utf-8-sig。这个编码会在文件开头添加一个 BOM 头让 Excel 主动识别为 UTF-8。如果你后续用 pandas 读取文件做分析也建议加上df pd.read_csv(douban_comments.csv, encodingutf-8-sig)6. 爬虫不是终点从评论数据到可视化分析6.1 电影口碑的直观画像爬虫的价值不在“爬到数据”而在“用好数据”。就拿刚才保存的douban_comments.csv来说你可以先做一个最简单的评分分布统计import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(douban_comments.csv, encodingutf-8-sig) rating_count df[rating].value_counts().sort_index() plt.rcParams[font.sans-serif] [SimHei] # Windows 下使用黑体 plt.rcParams[axes.unicode_minus] False rating_count.plot(kindbar) plt.title(短评评分分布) plt.xlabel(评分) plt.ylabel(条数) plt.tight_layout() plt.savefig(rating_distribution.png, dpi200)这段代码用rating字段做统计画出柱状图。你会发现一部电影的短评评分不是平均分布的而是明显聚集在某几个分数段。这个聚集形态比电影总分的单一数字更能反映观众的真实态度。matplotlib 中文显示是一个经典问题。Linux 系统下如果没有SimHei字体图上的中文会变成方框。遇到这种情况可以安装中文字体也可以改用系统支持的中文字体名称。这个细节说出来很小但我在 Linux 服务器上第一次画图时真的被它卡了很久。6.2 做一张影评关键词词云让内容变成“一眼看懂”的摘要评分能回答“电影好不好”的问题但回答不了“大家在讨论什么”。如果你想快速了解评论聚焦在什么话题上可以用 jieba 分词加 wordcloud 生成一张词云。import jieba from wordcloud import WordCloud text .join(df[content].dropna().tolist()) words jieba.cut(text) words_str .join(words) wc WordCloud( font_pathpath/to/your/chinese_font.ttf, width800, height600, background_colorwhite ).generate(words_str) wc.to_file(comment_wordcloud.png)关键点有两个。一是font_path必须指向一个中文字体文件否则词云上的中文全都会变成方块二是在做词云前最好先剔除一些无意义的停用词比如“电影”“一个”“我们”这类高频但无分析价值的词否则它们会占据画面主体淹没有效信息。6.3 基于评论时间绘制热度曲线抓取的数据里保留了评论时间字段你可以把时间转换成日期然后按天统计评论条数。这个维度能看出电影的哪些节点会引发讨论潮——是刚上映的集中爆发现象还是随着时间推移逐渐走低的规律。对学习数据分析来说这是一个很好的练手案例。df[time] pd.to_datetime(df[time]) df[date] df[time].dt.date daily_count df.groupby(date).size() daily_count.plot() plt.title(每日评论数量趋势) plt.savefig(daily_trend.png, dpi200)如果时间范围不够长、样本数量太少趋势会很不稳定。所以这个分析更适合样本量较大的数据集否则只能看到几个零星的点。这也是为什么我建议你抓取时至少要积累 3 到 5 页、总计上百条评论的原因。6.4 爬虫能力后续可以扩展的方向拿豆瓣练完手之后你的爬虫能力已经覆盖了静态页面的请求、HTML 结构解析、字段提取、翻页、数据持久化、以及后续的基础分析。这些能力占爬虫日常工作的八成以上。后面如果想进阶可以朝这些方向去并发抓取把请求改成协程或线程池在保证请求频率的前提下提升效率。动态页面处理遇到数据靠 JavaScript 动态加载的网站时学习用浏览器模拟工具去加载渲染后的页面。代理池与速率控制在合规合法的前提下理解大型爬虫系统如何管理海量 IP 与限流策略。解析框架升级了解一下 Scrapy 这类爬虫框架它帮你把请求、解析、中间件、管道拆成标准模块适合更工程化的项目。不过我想给你的建议是不要急着去追求这些“高级”内容。先把 requests 加 BeautifulSoup 这个组合练熟直到你面对任意一个静态页面都能轻松拆解再考虑学习框架很多高级概念都是建立在这些基础能力之上的。爬虫这条路我见过太多人走偏了。有人沉迷于研究各种绕过验证码的方法有人一上来就爬社交数据做分析最后要么被平台警告要么给自己惹上麻烦。拿豆瓣电影评论这样的公开数据做个人技术练习是我目前觉得最安全也最有效的入门方式希望这篇文章能让你少走一些我走过的弯路。
返回列表