ARTICLE DETAIL

资讯详情

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

AcFun硬核榜单爬虫实战:从页面解析到数据存储全流程

AcFun硬核榜单爬虫实战:从页面解析到数据存储全流程 我们直接聊这个AcFun硬核榜单爬虫项目。作为一个常年混迹各大社区的爬虫爱好者我一看到“硬核榜单”这几个字就来劲了。AcFun的“硬核榜单”不是那种单纯的播放量堆砌而是综合了多项用户互动指标后计算出来的结果能上榜的内容基本代表了当前社区里最受硬核用户认可的一批作品。如果能在指定时间点把这个榜单全量抓下来横向对比往期数据你会看到很多有意思的趋势——比如某个区突然批量冒出高赞投稿、某些UP主连续霸榜、或者选题风向的周期性变化。这篇文章就把我如何实现AcFun全站硬核榜单“收割机”的完整过程写出来从页面结构分析、反爬策略、数据清洗到存储方案全部走一遍。适合想练手爬虫但不想总拿豆瓣、天气练手的人也适合对AcFun生态做观察研究的朋友参考。1. 项目整体设计与思路拆解1.1 为什么选AcFun的硬核榜单当目标我选爬虫练习目标有个标准数据有规律、页面结构有一定挑战性、内容本身有意思。AcFun的硬核榜单刚好三样全占。它不是传统意义上“按播放量排序”的简单榜单而是有专门的计算逻辑据我观察和社区讨论大致会综合“投蕉数”、“评论数”、“收藏数”以及一定时间窗内的数据变化幅度最终得出一个类似热度分的数值。这意味着爬下来的数据里除了排名和标题还能拿到这些原始指标方便我自己做二次加权计算这比直接下载一个现成的排行榜列表有意思得多。从技术实践的角度来说AcFun的页面属于典型的前后端混搭模式——部分数据直接渲染在HTML里部分数据通过接口异步加载视频列表页与详情页的信息构成差异也很大。这意味着只写一个简单的requests.get加BeautifulSoup解析很可能不够你需要根据实际返回的HTML结构动态调整解析逻辑。这个过程刚好能练习“页面结构分析”的核心能力。另外AcFun对爬虫并不算特别友好但也没有到那种必须用无头浏览器硬刚的地步属于“稍微处理一下请求头就能跑”的级别非常适合用来学习如何伪装请求。1.2 技术选型从requests到BeautifulSoup再到pandas很多新手一上来就喜欢堆框架什么Scrapy、Selenium一起上。我的原则是能用简单工具解决的事不整复杂框架。AcFun硬核榜单这个项目的数据量级撑死了也就几百条记录用requests手动管理会话搭配BeautifulSoup做HTML解析完全够用。如果你只是想抓榜单import requests加import re就能做完80%的工作再加一个BeautifulSoup把提取逻辑写得更优雅。对于后续的数据处理我习惯用pandas做结构化最后统一导出到Excel或者CSV。选requests而不是httpx或aiohttp原因很简单项目逻辑是串行的不需要高并发。AcFun的服务器请求频率过快容易触发IP临时限制串行请求反而能减少风险。BeautifulSoup则胜在API直观对HTML结构不理想的页面处理能力也强。如果目标页面变成了纯JavaScript渲染的SPA我才会考虑加上Selenium或者Playwright但那属于“作战方案B”不是首选。1.3 数据存储方案Excel、CSV和SQLite怎么选抓下来的榜单数据最终要落盘。如果你只需要一次性看个结果CSV是最方便的但如果要做长期跟踪、定时抓取我强烈建议用SQLite。原因很简单CSV在追加数据和去重时会很麻烦而SQLite天然支持“按主键去重”和“增量写入”。我做这个项目时采用了双轨制——原始数据先存SQLite备份再导出CSV供日常查看。这样即使某次抓取数据不完整也不会污染已有的历史数据。存储字段我设计得比较宽除了排名、标题、UP主、播放量、评论数、投蕉数、收藏数、发布时间之外还把抓取时间的快照字段也存了。这个字段很有用因为同一部视频在不同日期的榜单上可能都会出现只有带时间戳的快照才能还原当时的排名情况方便做时间序列分析。2. 核心细节解析与实操要点2.1 榜单页面的URL规律和参数含义AcFun的榜单入口有几个最核心的是“硬核榜”页面URL大致结构是https://www.acfun.cn/bangumi/...之类的路径但实际上榜单的入口往往隐藏在“排行榜”频道里。你打开页面按F12打开开发者工具切到Network面板刷新一下就能看到真正的数据请求URL。我这次抓的是https://www.acfun.cn/rank/list这个路径下的榜单数据它的核心参数就三个scopeType范围类型比如全站还是分区、rankType排序维度比如硬核榜、channelId分区编号。这三个参数直接决定了返回的是“全站硬核榜”还是“某个分区”的硬核榜。需要特别提醒的是AcFun的榜单接口返回的数据格式不止一种。有的接口直接返回渲染好的HTML片段有的接口返回JSON。我这次研究的是HTML片段模式因为它在服务端直接把排名数据嵌入到了模板中解析相对固定。如果你看到自己的请求返回的是JSON不要慌JSON结构通常更清晰解析反而更容易。关键是先在浏览器里确认你用的URL和参数确实能拿到想要的数据。2.2 请求头伪装与Cookie策略AcFun对请求头的校验不算严格但如果你用默认的requests头去请求大概率会碰到两种结果要么返回哭笑不得的验证页面要么直接给你返回一个空壳HTML。我实测下来的经验是最少要设置User-Agent和Referer这两个字段。User-Agent建议用最新版Chrome的UA别用那些老掉牙的Python-requests/2.x这等于把“我是爬虫”写在脸上。Referer也很关键很多站点的后端会校验请求来源如果你直接请求/rank/list但Referer是空的或者不对接口会拒绝返回数据。Cookie方面AcFun有些接口会检查一个叫_did的匿名用户ID。正常浏览器打开网站时会自动种下这个Cookie你直接用requests访问时没有这个Cookie某些接口就会返回空数据。解决办法有两种一种是第一次请求时先访问首页让服务器种下Cookie后续请求带着这个Cookie走另一种更稳直接拿浏览器里的Cookie粘到代码里用。我当时用的是第一种实现起来很简单加一个requests.Session()对象先session.get(https://www.acfun.cn)再请求榜单URL这样就自动带上了。实测这个方法能拿到完整数据也不需要维护登录态。2.3 榜单数据的HTML解析思路拿到HTML之后解析逻辑不能一把梭。我建议先把返回的HTML存成本地文件用编辑器打开仔细观察结构再写解析代码。AcFun榜单页的HTML结构其实比较规整主要数据都躺在一个列表容器里每个榜单项的结构类似div classrank-list div classrank-item span classrank-index1/span a classrank-title href/video/ac1234567视频标题/a span classrank-authorUP主名/span span classrank-score12345/span /div /div实际类名可能不同这里只是举例说明思路使用BeautifulSoup解析时可以先定位.rank-list再遍历每个.rank-item用find提取具体字段。这种思路比直接写正则表达式要稳健得多因为只要页面结构不发生大规模改动代码就能继续用。需要注意的是有些字段可能不存在比如某些视频未开放评论时就没有评论数这时要设置默认值防止None值污染后续的数据处理。3. 实操过程与核心环节实现3.1 搭建基础爬虫框架我习惯先把框架搭出来再填细节。这个项目的骨架就是“请求—解析—存储”三步走。下面这段代码是我第一版爬虫的雏形import requests from bs4 import BeautifulSoup import pandas as pd import time 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, Referer: https://www.acfun.cn/ } url https://www.acfun.cn/rank/list params { scopeType: all, rankType: hardcore, channelId: 0 } session requests.Session() session.get(https://www.acfun.cn/, headersheaders, timeout10) resp session.get(url, headersheaders, paramsparams, timeout10) resp.encoding utf-8 print(resp.status_code)这里先发一个首页请求建Cookie再带着Cookie去请求榜单接口是很多站点通用的请求策略。resp.encoding utf-8这行别漏了AcFun页面是UTF-8编码requests有时会自动推断成其他编码导致中文乱码。你如果发现解析出来的标题全是乱码十有八九就是编码没手动指定。3.2 解析榜单HTML并提取字段拿到HTML后先做个快速检查确认响应里确实包含了榜单数据。可以打印len(resp.text)看一下长度如果只有几千字节说明可能被拦了正常情况一个榜单页怎么也得几十KB以上。确认无误后开始解析。我这里用BeautifulSoup提取核心字段soup BeautifulSoup(resp.text, html.parser) rank_items soup.select(.rank-list .rank-item) # 根据实际HTML结构调整 data_list [] for item in rank_items: rank item.select_one(.rank-index).get_text(stripTrue) title item.select_one(.rank-title).get_text(stripTrue) author item.select_one(.rank-author).get_text(stripTrue) score item.select_one(.rank-score).get_text(stripTrue) video_url item.select_one(.rank-title)[href] if not title: continue data_list.append({ rank: rank, title: title, author: author, score: score, video_url: video_url, crawl_time: time.strftime(%Y-%m-%d %H:%M:%S) })这里有几个细节值得展开说。第一get_text(stripTrue)会自动去掉字符串两端的空白字符避免把HTML里的换行和空格一起存进数据。第二select_one在找不到对应元素时会返回None如果直接对None调用get_text会报错所以最好先判断一下。第三video_url里的值是一个相对路径后续如果要拼接完整链接需要手动加上域名前缀。3.3 翻页与全站硬核榜单覆盖AcFun的硬核榜单“全站”模式通常只展示前几十名如果你想把内容覆盖得更全涉及到分页参数。我们需要确认榜单页面是否支持分页。如果不支持那就需要切换不同的scopeType或channelId来获取分区榜单再汇总成全站数据。我测试时发现AcFun榜单接口存在page参数在params里加上page: 1、page: 2就能翻页。不过翻页后每页的数据量会减少有时候第二页只有个位数的数据量这是因为整个榜单本身数据量就不大。所以实际操作时我会写一个循环从第1页开始请求直到解析出的列表为空为止。这样既不会漏数据也不会无限请求下去。pages [] page 1 while True: params[page] page resp session.get(url, headersheaders, paramsparams, timeout10) resp.encoding utf-8 soup BeautifulSoup(resp.text, html.parser) items soup.select(.rank-list .rank-item) if not items: break pages.extend(items) print(fPage {page}: {len(items)} items) page 1 time.sleep(2) # 控制请求间隔这里我特意加了time.sleep(2)不管服务器允不允许高速抓取自己先把自己限制住这是爬虫的基本素养。实测下来如果连续快速翻页大概十几个请求后就会触发频控导致后续所有请求都返回验证页面。加上休眠后整个抓取过程就稳定多了。3.4 数据清洗与Excel报表生成抓下来之后原始的数据列表还不能直接用。比如分数那一列可能带有“热度”或“赞”等中文单位需要清洗成纯数字标题里的空格和特殊符号也要统一处理。我用pandas来处理这些数据非常顺手df pd.DataFrame(data_list) df[score_clean] df[score].apply(lambda x: extract_number(x)) df.sort_values(rank, inplaceTrue) df.to_excel(acfun_hardcore_rank.xlsx, indexFalse)这里的extract_number是一个自己写的小函数作用是把“1.2万”这种字符串转换成“12000”这样的浮点数主要是考虑到AcFun可能返回简化后的格式。如果分数是纯数字直接用正则提取即可import re def extract_number(text): if not text: return 0 match re.search(r[\d.], str(text)) if not match: return 0 return float(match.group())写完这版爬虫后我跑了一次把全站硬核榜的数据完整抓了下来文件打开后是规整的表格排名、标题、UP主、分数、视频链接、抓取时间。到这一步项目已经算跑通了但实际操作中遇到的问题远不止这些。4. 常见问题与排查技巧实录4.1 页面数据为空或返回验证页怎么定位问题爬虫最让人头大的就是“数据为空”和“返回验证页”。这两个问题的排查思路完全不同。先说数据为空如果你打印resp.text发现里面有数据但用BeautifulSoup解析后列表是空的那问题多半出在CSS选择器上。AcFun前端偶尔会改版类名一变老选择器就失效。解决办法是把HTML存成文件在编辑器里搜索“rank”关键词看看实际类名变成了什么然后更新选择器。如果是返回验证页也就是响应内容里出现了一大段JavaScript和特殊验证逻辑那就说明你的请求被反爬机制识别了。优先检查User-Agent是否是常见的浏览器UAReferer是否设置正确有没有带Cookie。如果这些都没问题还出现验证页建议降低请求频率并在请求之间加入随机延时让抓取行为更接近人的操作节奏。4.2 翻页抓取的时候出现重复数据怎么去重全站榜单一共有多少条数据是可以预期的。如果你发现翻页后不同页码返回的数据有重叠大概率是榜单接口的排序算法导致某个条目的排名在翻页过程中发生了变化。比如第1页的最后一名和第2页的第一名因为数据更新而交换了位置。解决方案很简单在数据合并时以video_url为唯一标识做去重。df df.drop_duplicates(subsetvideo_url)这个去重逻辑不能省略。你不去重后续做历史对比时同一部视频会被计算两次百分比统计就会失真。4.3 请求频率过高被临时封IP怎么破AcFun对爬虫的限制不是一刀切更像是一个基于频率的动态阀值。我做过一次测试连续不加间隔地请求100次在差不多第30次左右就开始出现验证页面。虽然页面里没有直接说封IP但之后很长一段时间内所有请求都不正常。解决办法是控制好请求间隔我最终采用的是time.sleep(random.uniform(1, 3))让延时更自然。如果你需要大量抓取可以再加一层代理IP池但不建议一上来就堆IP池先把自己的请求频率降下来大部分情况下就够用了。4.4 代码突然报错怎么快速定位爬虫项目最忌讳“能用就行”因为页面一改就会出问题。我的习惯是每一步都打印关键日志比如请求的状态码、响应长度、解析到的条目数。这样哪里出问题一目了然。另外建议在代码里加异常处理请求失败后自动重试三次重试间隔递增而不是直接崩掉。for retry in range(3): try: resp session.get(url, headersheaders, paramsparams, timeout10) resp.raise_for_status() break except Exception as e: print(fRetry {retry 1} failed: {e}) time.sleep(3 * (retry 1))这段代码虽然简单但在实战中能省你很多事。不用每次出现偶发错误都手动重启脚本。5. 从榜单爬虫到数据观察扩展思路与合规提醒5.1 如何扩展到分区榜单与历史数据追踪这个项目只做了“全站硬核榜”的抓取但AcFun的榜单体系里还有动画、音乐、游戏等不同分区。如果你对某个特定内容领域感兴趣可以用同样的方式修改channelId参数抓取分区榜单。如果你想做历史数据追踪可以把这个脚本挂到定时任务里每天固定时间抓一次存到SQLite里。日积月累你就能看到一部作品从入榜、上升、登顶再到跌出榜单的完整生命周期。这种数据观察比只盯一眼新鲜榜单有意义得多。5.2 分布式爬虫与更大规模的数据抓取当你把视角放大到全站所有视频数据时单机爬虫就不够用了。不过我不建议一开始就上分布式。先用这个榜单项目把单机版跑得足够稳定理解爬虫的完整链路之后再考虑引入Scrapy、RabbitMQ队列或者Celery来做任务分发。分布式爬虫的核心不是“让更多机器一起跑”而是“如何合理分配任务并汇总结果”。榜单项目的数据量小不需要分布式但它适合做分布式爬虫的“控制实验”往消息队列里推送一批“榜单页URL”多个worker并行拉取最后把结果汇总到同一个存储里。5.3 一定要聊的爬虫边界与合规底线这个项目是纯技术学习用途。抓取公开榜单数据用于个人观察本身问题不大但如果你要对外发布数据报告需要注意几点第一数据来源要标明AcFun尊重平台第二不要抓取用户非公开数据榜单页上出现的用户名本身是公开的但不要额外去爬用户的私有信息第三控制请求频率不给服务器添麻烦。我在整个项目里只使用了轻量请求也不会做大规模并发抓取更不会用抓来的数据做任何商业用途。这既是技术上的优雅也是爬虫从业者该有的自觉。5.4 给后续扩展留出的小技巧最后分享一个我后期摸索出来的小技巧在抓取榜单页时可以顺便把每个榜单条目的video_url保存下来然后写一个二级爬虫去抓取每个视频详情页里的描述、标签、发布时间。这样你手里的数据就从一个单纯的排名榜单扩展成了“带内容元数据的视频库”。后续无论你是做内容分类、画数据趋势图还是做用户兴趣分析都有了原材料。这个扩展思路是基于我自己的实践补强的但逻辑是通顺的榜单页只给你结果详情页才能告诉你结果背后的原因。我也踩过这方面的坑。第一次写详情页爬虫时傻乎乎地直接请求所有视频链接结果访问没几个就被频控卡住后来才意识到必须把详情页的请求也串行化同时加上请求间隔。另外详情页里有些字段可能在页面源码里找不到比如部分数据是通过接口异步加载的这时候就需要在Network面板里找到对应的XHR请求模拟接口请求拿数据。这一类问题解决起来不难关键是有意识地记录自己的踩坑过程下次遇到类似网站就能更快定位。写在这里的体会这次实操给我最大的感受是AcFun硬核榜单这个项目特别适合作为综合性爬虫练习因为它涉及了请求伪装、页面解析、翻页处理、数据清洗、存储设计和反爬应对这五个爬虫最核心的环节而每个环节的难度都很适中。你在做这个项目的过程中积累起来的内功后面去抓其他网站时会发现完全能迁移。我当时第一次跑通全流程看到Excel里整整齐齐的榜单数据时心里还是有点小兴奋的。这种成就感来自“把网上一个看似很随意的页面转化成结构化数据”的掌控感。尤其当你拿着抓下来的历史数据画出某个UP主连续几周霸榜的趋势图时会觉得自己做的东西不仅仅是一段代码而是观察一个社区文化的一把钥匙。当然技术这条路没有终点。AcFun会持续改版爬虫代码也可能某天突然失效。但只要你掌握了分析的思路无论页面怎么变都只是换个选择器的事。这也是我希望这篇文章能带给你的东西不是一段能跑一时的代码而是一种遇到任何榜单类页面都能下手的稳定方法论。
返回列表