Python爬虫实战:用requests和BeautifulSoup抓取番剧更新日历

发布时间:2026/9/13 23:04:44
Python爬虫实战:用requests和BeautifulSoup抓取番剧更新日历 1. 项目概述与核心思路1.1 追番党的痛点为什么需要这个爬虫追番的人最怕什么不是新番太少没得看而是记不住更新日历。每个季度的新番动画三十部起步分布在周一到周日的各个时段再加上有些剧是周更、有些是半月更光靠脑子记根本不现实。我自己就经历过好几次周五晚上兴致勃勃打开视频平台想看某部番的最新一集结果发现它其实是周四更新的一整个星期都在等错日子。这个项目的想法很简单粗暴——与其每天手动去翻aqy的番剧页面不如写一个Python爬虫把番剧更新日历的数据自动抓下来整理成一张清晰的表格。星期几更新、更新到第几集、距下次更新还有几天全部一目了然。我给它起名叫“追番党的数据神器”因为拿到这份数据之后你连点开App看更新列表的动作都省了。这个爬虫能给谁用首先是追番数量超过五部的深度用户其次是做动漫资讯二次创作的内容作者需要快速掌握各平台的新番排期再就是纯粹想练手Python爬虫的新人。如果你刚学完Python基础语法想找一个真实项目把requests、解析HTML、数据持久化这些技能串起来这个项目也非常合适。1.2 技术选型为什么是 requests BeautifulSoup而不是 Scrapy 或 playwright动手之前我认真比过一轮技术方案因为工具选不对后边全是在给自己挖坑。第一梯队是 requests BeautifulSoup 组合这也是最终采用的方案。它的优势非常明显依赖少、上手快、运行轻量。整个项目只需要两个第三方库一个负责发HTTP请求一个负责解析HTML结构逻辑完全可控遇到报错你也能一眼看出问题出在哪一步。对于“抓一个页面、解析列表数据”这种量级的任务它就是最合适的选择。第二梯队是 Scrapy 这种重量级框架。Scrapy 确实强大支持分布式、中间件、并发抓取但代价是引入了一套完整的项目结构和配置体系。你可能要创建 spiders、pipelines、middlewares 这些文件光是把框架跑起来就需要额外学习成本。用它来抓一个单页面属于“用大炮打蚊子”过度设计了。第三梯队是 playwright 或 Selenium 这类浏览器自动化工具适合处理大量动态渲染的页面。但如果目标页面的更新数据可以通过请求直拿或者直接在HTML源码里就能解析到那就没必要启动一个完整的浏览器实例。一个浏览器进程吃几百MB内存跑起来慢、部署也麻烦对服务器资源的要求高出一大截。当然我后来也碰到过页面结构完全由 JavaScript 动态生成的情况requests 直接拿不到数据。这种时候我会优先检查页面里有没有内嵌的 JSON 数据或 XHR 接口实在不行才考虑上 playwright。后边第 4 节我会专门说这个排查思路。1.3 整体流程拆解一条数据从网页到我们手上的完整路径这个爬虫的完整工作流程可以拆成四个环节发送请求 - 获取响应 - 解析数据 - 持久化输出发送请求这一步核心是构造一个带请求头的 GET 请求。很多新手直接 requests.get(url) 一把梭结果拿到的是平台的拦截提示页面。原因是平台能识别出这是爬虫请求——没有浏览器指纹、没有Cookie、User-Agent 还是 Python 默认的。这个问题在实战中几乎是第一道关卡我后文会给出完整的请求头伪装方案。获取响应之后先别急着解析。我的习惯是先保存一份原始HTML到本地用浏览器打开对比确认拿到的内容和在浏览器里看到的一致。这个步骤看起来多此一举实际上能帮你省掉大量排查时间因为你可能踩的坑在请求阶段就已经埋下了。解析数据是整个项目的核心环节。用 BeautifulSoup 定位到番剧卡片所在的HTML节点然后逐个提取剧名、更新状态、更新时间这些字段。这个过程不复杂但特别考验耐心因为你需要先搞清楚页面结构是什么样的才能写出正确的选择器。第 2 节我会专门讲怎么用浏览器开发者工具高效地做这件事。最后是持久化输出。我选择了 JSON 和 Markdown 两种格式JSON 方便后续程序读取和二次处理Markdown 方便直接贴到笔记软件或者公众号文章里。你还可以按自己的需求扩展成 CSV、Excel 或者直接推送到手机通知。这四个环节串联起来就是一个完整的爬虫闭环。2. 目标页面分析与数据定位2.1 如何快速找到番剧更新日历的真实数据地址爬虫和普通网页访问最大的区别在于你得先搞清楚数据到底是从哪里来的。很多人打开网页看到内容就直接开始写解析代码但实际上你看到的页面内容可能有三种不同的加载方式服务端直接渲染在HTML里、页面加载后通过Ajax请求异步获取、由前端JavaScript本地生成。这三种情况对应的爬虫方案完全不同。我之前抓过某个动漫资讯网站页面刷新后内容确实显示了但仔细看HTML源码里根本没有数据所有条目都是空壳。找了一圈发现数据其实是通过一个公开的JSON接口返回的页面只是把接口返回的数据塞进了HTML模板。这类情况就是典型的异步加载。我在动手写解析代码之前第一件事永远是打开浏览器的开发者工具切到 Network 面板刷新页面看看到底发出了哪些请求。重点关注两类XHR 请求和 JS 请求。如果番剧更新数据是异步加载的你会在 XHR 请求列表里看到名字类似 calendar、schedule、bangumi 的接口直接在响应里就能看到结构化的JSON数据比从HTML里解析省事太多了。2.2 页面资源分析搜索关键词定位数据块有一个非常高效的定位方法我屡试不爽在开发者工具的 Elements 面板里直接用 CtrlFMac 上是 CmdF搜索页面里一个你确定会出现的关键词。举个例子你在页面上能看到某部番剧叫“凡人修仙传”那就直接搜索这个名称。浏览器会直接帮你定位到包含这个文本的HTML节点你顺着这个节点往上层找就能找到整个番剧卡片的容器结构。然后你要观察这个卡片里还包含了哪些数据字段——通常会有剧名、封面图、更新集数、更新日期有些卡片还会标注“全集”或者“连载中”。找到容器之后再看它的 class 或 id 命名。正常平台的页面结构通常有一定规律比如所有番剧卡片共用同一个类名这样就可以用 find_all 一次性把所有卡片都提取出来。我记得当时光是把这一步做出来整个爬虫的工作量就完成了一半。2.3 解析逻辑的两种写法HTML解析和JSON解析对比这里我想多写一点因为解析逻辑是整个爬虫的“心脏”写的好坏直接决定代码的健壮性和后续维护成本。HTML解析方案适用于数据直接渲染在页面源码里的情况。用 BeautifulSoup 的 find 和 find_all 配合 CSS 选择器把数据块从HTML结构里筛出来。优点是直观、你看到什么样就解析什么样缺点是强依赖页面结构平台只要改个class名或者调整布局你的解析代码立刻失效。JSON接口解析方案适用于平台有独立数据接口的情况。直接用 requests 请求这个接口拿到的是干净的JSON数据解析起来就是简单的字典取值操作。优点是稳定、逻辑清晰不受HTML结构调整影响缺点是需要你找到这个接口的地址和请求参数有一些反爬手段会校验这个请求是否来自真实浏览器。这两种方案在实战中可以灵活切换甚至在同一个项目里并存。我后来做的版本里加了一处容错逻辑优先尝试JSON接口如果接口请求失败或者返回异常就回退到HTML解析方案。这样即使其中一条路断了另一条还能兜底爬虫的可用性大幅提升。3. 核心流程实现与完整代码3.1 环境准备与依赖安装开发环境是 Python 3.9操作系统无关Windows、macOS、Linux 都能跑。如果你还没有安装Python先去官网下载对应系统的安装包安装时记得勾选“Add Python to PATH”选项这样后续在命令行里才能直接使用 python 命令。项目依赖只有两个库安装命令非常简单pip install requests beautifulsoup4io这里多一句嘴建议你安装前先确认一下自己的Python环境是否干净。如果是在公司电脑或者公共服务器上操作最好先建一个虚拟环境避免污染全局环境。命令是python -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate虚拟环境这一步很多新手容易忽略但实际踩了坑之后就会明白它真的能省掉很多依赖冲突的麻烦。3.2 请求头伪装写好一个不会被拦的GET请求拿到了第一步的URL之后还不能直接请求。直接 requests.get(url) 的请求头很简单很多平台一眼就能识别出这是非浏览器请求。要模拟真实浏览器的访问关键是把 User-Agent、Referer、Accept 这些头带上。我用的是一个标准请求模板实测下来成功率很高import requests def get_page(url): 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://www.aqy.com/, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/avif,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, } resp requests.get(url, headersheaders, timeout10) resp.encoding utf-8 return resp有几个细节值得注意User-Agent 一定不要用默认的 Python-requests就这一小步可以规避掉大量基础反爬拦截Referer 字段表明你的请求是从平台内部页面跳转过来的很多平台会校验这个字段Accept 字段可以帮助模拟浏览器的完整请求头虽然作用不如前两个大但凑齐了好歹更真实timeout 参数一定要加。不加的话如果目标服务器响应异常你的爬虫可能会一直挂在那里看起来像死循环3.3 数据解析从HTML中提取番剧更新信息这一步是核心中的核心。我假设目标页面已经把番剧信息渲染在HTML里每部番剧是一张卡片。解析这部分需要两步先用 BeautifulSoup 打开HTML然后用选择器定位到卡片容器。from bs4 import BeautifulSoup def parse_bangumi(html): soup BeautifulSoup(html, html.parser) cards soup.find_all(div, class_bangumi-card) result [] for card in cards: title_tag card.find(h3, class_title) status_tag card.find(span, class_update-status) date_tag card.find(span, class_update-date) if title_tag is None: continue title title_tag.get_text(stripTrue) status status_tag.get_text(stripTrue) if status_tag else 未知 update_date date_tag.get_text(stripTrue) if date_tag else 未知 item { title: title, status: status, update_date: update_date, } result.append(item) return result这段代码里的很多class名称是我根据常见页面结构假设的你实际抓取时肯定需要对应当前真实页面的class。如果页面结构和我上面写的不一样不要硬套你只需要找到卡片容器的选择器然后准确提取你需要的字段就行。对了get_text(stripTrue) 这个写法是从HTML节点中提取纯文本strip 参数会把首尾空白字符去掉。如果你遇到页面上标题带了很多空格的情况处理完之后就干净了。3.4 数据整理与输出把爬到的日历变成能用的表格数据解析出来之后是Python的列表和字典直接打印出来看没问题但如果你想方便后续使用就不能只停留在打印这一步。我通常会做两层输出第一层导出为JSON文件方便程序读写。JSON格式化之后长这样[ { title: 凡人修仙传, status: 连载中, update_date: 2025-01-15 20:00 }, { title: 斗破苍穹, status: 连载中, update_date: 2025-01-16 10:00 } ]第二层导出为Markdown表格方便阅读和分享。我之前的做法是用Python代码直接拼出Markdown表格def to_markdown(data): lines [| 番剧名称 | 更新状态 | 最近更新 |, | --- | --- | --- |] for item in data: lines.append(f| {item[title]} | {item[status]} | {item[update_date]} |) return \n.join(lines)然后把Markdown存进文件或者直接打印出来复制到备忘录里都行。如果你是程序员还可以把JSON数据推送到自己的服务器或者数据库里但这已经超出爬虫本身的范畴属于数据应用了。3.5 定时运行用简单方式让爬虫每天自动执行爬虫写完之后你不可能每天手动运行一次那就失去“数据神器”的意义了。定时运行有两个方案。Windows 任务计划程序用图形界面就能配置好。打开任务计划程序新建任务触发器设置为每天固定时间比如每天早上9点操作选择运行Python脚本脚本参数是你的 .py 文件路径。Linux 或者 macOS 用户可以用 crontab写一行配置搞定0 9 * * * cd /path/to/project /usr/bin/python3 crawler.pyPython脚本内部定时用 time.sleep() 做循环定时适合脚本需要一直运行不关闭的场景。但这种方式不太优雅一是脚本不能退出二是重启之后容易遗忘。我更推荐第一种方案。4. 常见问题与排查技巧实录4.1 请求直接被平台拦截怎么办这是爬虫新手最容易遇到的问题具体表现是用requests请求返回的页面内容和浏览器看到的完全不一样很多情况下是一段JavaScript验证代码或者是平台的安全拦截页。我的排查顺序是这样的先看响应内容里有没有“验证”“异常”这类的关键词。有的话说明被风控了那就得换一种请求姿势。先检查自己的请求头是否完整尽量把浏览器请求时的完整请求头都搬过来包括 User-Agent、Referer、Accept-Language、Sec-Fetch-Site 这些字段。如果加了请求头仍然不行看看是不是需要携带Cookie。简单的方式是手动在浏览器里登录一次从开发者工具里找到 Cookie 值粘贴到爬虫代码里。这种方式适合个人使用但Cookie有时效性过期了需要重新更新。最后的手段是降低抓取频率。不要连续请求加个随机延迟。平台的拦截逻辑很多是基于请求频率的间隔3到5秒基本不会触发。4.2 页面结构调整后爬虫失效的应对策略爬虫这行有个铁律你今天写好的解析代码明天可能就不能用了。页面结构调整、class名称变化、甚至某个字段格式改变都会让你的爬虫瞬间“失明”。遇到这种情况不用慌按照下面几步排查第一步是先把最新的页面源码下载下来存放在本地文件里然后逐步找数据到底去哪了。用 BeautifulSoup 打开本地文件重复一遍最初的解析过程看是哪里解析不到数据。这一步能帮你确认是自己的选择器失效了还是数据本身的呈现方式变了。第二步是重新用开发者工具定位新的DOM结构更新选择器和字段信息。改动通常不大可能就是class名从 bangumi-card 变成了 bangumi-item。第三步是做好防御性编程。写解析逻辑时不要用那种“能跑就行”的硬编码方式尽量做到容错。比如提取字段时判断一下如果某个字段找不到赋值一个默认值或者跳过不要直接在字段取值时报 KeyError 或者 AttributeError 把整个脚本打崩。4.3 请求频率控制与数据量控制爬虫写得好不好除了看能不能拿到数据还要看会不会给目标服务器造成压力。这里我认为有一条道德底线爬虫只是提取公开数据不代表你可以随意高频率请求把别人的服务器打挂。这不光是技术问题也是职业操守问题。实操层面我给自己定了几条硬性约束请求间隔不低于 2 秒最稳妥的是 3-5 秒加随机抖动不做并发请求尽量串行访问真需要并发的时候控制在 2-3 个并发以内抓取数据量大的任务强制分批次执行每批之间暂停一段时间这是我做这个追番日历项目时的实际日志2025-01-05 09:00:02 开始抓取页码1 2025-01-05 09:00:05 获取到28条数据 2025-01-05 09:00:08 开始抓取页码2 2025-01-05 09:00:11 获取到30条数据看看这个时间间隔基本保持在 3 秒左右一次请求抓完所有页面也就几分钟的事对目标站点完全谈不上压力。反过来讲如果你用 0.1 秒间隔去刷可能要不了几分钟就会触发平台的反爬机制你的IP被临时封禁爬虫任务直接中断。得不偿失。4.4 常见问题速查表我整理了一份速查表基本涵盖了这类爬虫项目90%的常见问题问题表现可能原因解决方案请求返回403缺少或错误的User-Agent伪造完整浏览器请求头页面有大量异步加载数据不在HTML中检查XHR接口改用接口解析中文乱码页面编码判断错误手动指定编码如 resp.encoding utf-8某天数据突然为空页面结构调整重新定位DOM结构更新选择器请求超时网络不通或服务器慢增加timeout参数和重试机制被平台临时封禁IP请求频率过高降低频率增加随机延迟字段缺失报错数据结构不完整使用 get 方法取值并设置默认值5. 项目的后续扩展方向写到这里基础的追番日历爬虫已经能跑通了但这个项目本身的潜力远不止于此。如果你想继续往深入做有几个方向我觉得很值得尝试。一个是加通知推送。把爬到的更新日历数据推送到你自己的微信、邮箱或者Telegram每天定时收到当天有什么番更新的提醒。这本质上是在爬虫外面套了一层自动化流程不用人工去看表格数据直接触达你。另一个是把抓取范围扩展。现在只抓 aqy 一家的数据但追番爱好者往往同时关注多家平台。你可以把同样的思路复制到其他视频平台把多个源的数据合并成一份综合更新日历。当然实际做的时候需要注意各平台页面结构的差异以及适配不同平台的反爬策略这会是一个更完整的实战项目。还有就是数据可视化。把每天抓到的更新数据累计起来用 matplotlib 或者前端图表库做一张按星期分布的更新热度图看看哪一天更新的番剧最多哪个时间段竞争最激烈。这个听起来有点做数据分析的意思了但技术上都是水到渠成的事因为你的数据来源已经固化了。不过这些都是加分项。回到最初的需求上这个爬虫最核心的价值就一条让追番的人再也不用靠记忆力去追几十部番的更新日历打开手机看一眼表格就行。我自己的使用感受是把这份日历整理出来之后哪怕是再冷门的老番续作只要它在日历里出现过一次我就不会错过开播时间这种“数据掌控感”确实让人舒服。