B 站小站爬虫:用 Playwright 遍历发现 72 个兴趣社区
之前那段时间,我在浏览 B 站的时候偶然发现了一个叫“我的世界小站”的新功能。说是小站,其实它并不是一个独立的网站,而是嵌套在 B 站整体框架下的一个社区模块。当时舆论场上不少人都把它看作是 MCBBS 的替代品,因为那个老牌的我的世界中文论坛在前几年已经黯然倒闭了,很多 MC 玩家都流离失所,四处寻找新的聚集地。可是当我真正点进去体验了一番之后,心里却冒出了不一样的想法——我觉得 MC 玩家群体真正缺失的根本不是另一个论坛,而是那些由国人制作的各种优质资源,比如皮肤、材质包、模组、地图存档,还有能够一起联机、一起探险、一起建房子的玩伴。论坛这种形式在如今这个快节奏的互联网时代,其实已经显得有些古老和笨重了,光靠一个论坛很难把散落在各处的玩家重新凝聚起来。
尤其让我在意的是地址栏的样式,怎么看都像是类贴吧的那种结构,一层套一层的。当我偶然翻到其他小站的地址,发现里面确实有真人在活跃的时候,这种感觉就更强烈了。原本我觉得小站应该是一个独立自主的网站,有自己的域名、自己的页面风格、自己的运营规则,可现在它给我的整体感觉更像是闹得热热嚷嚷的,表面上看起来声势浩大,实际上所有人都挤在一个大屋子里,连个像样的隔间都没有。和贴吧那种个人论坛比起来,贴吧好歹每个吧都有自己的吧规、吧务团队和独特的文化氛围,可B站搞的这个小站反而显得更加寒酸了,连基本的个性化定制都做得很有限,像是流水线上批量生产出来的产品,少了些人情味和归属感。
我的朋友小芬之前特意在 B 站私信里艾特我,让我去看看这个小站长什么样。我当时看完之后给她的评价很简单,就是“不懂但是尊重”——这四个字概括了我所有的感受。我看不懂为什么 B 站要花力气做这样一个功能,也看不懂这个小站到底解决了什么痛点,但我尊重那些在里面玩得开心的玩家,毕竟每个人都有自己选择聚集地的自由。可是经过上面那一番关于论坛和资源的思考之后,我忽然对一件事产生了强烈的好奇心:B 站到底做了多少个小站?如果一个个手动点进去看,且不说网络请求可能会出现问题,光是那无穷无尽的数字编码,看到天荒地老都不一定能看完。更麻烦的是,我还需要知道每个数字编码到底对应着什么样的小站,这显然不能靠手工一个个去试。
作为一个技术爱好者,我骨子里就习惯用代码的方式去解决问题,这种批量遍历的事情根本难不倒我。稍微观察了一下小站的地址格式,我就发现它的规律非常简单,就是主站地址加 /bubble/home/1 这样的模式,末尾的数字从 1 开始依次递增。我只需要写一段程序,把末尾的数字不断改大,然后依次访问每一个地址,就能知道总共有多少个小站。只需要提取 div.name 元素,就可以知道每个小站的名字是什么了。这个思路简单直接,没有任何花里胡哨的地方,完全可以用自动化脚本来实现。想到这一点,我立刻打开了电脑,准备用我最熟悉的方式来搞定这件事,毕竟在这种重复性的工作面前,人的耐心永远比不上机器的效率。
知道了地址规律之后,我立刻动手,使用 DeepSeek TUI 编写了一个简单的爬虫脚本。为了不被 B 站的反爬机制拦截,我特意给脚本加上了 Firefox 浏览器的 UA,让它假装自己是 Windows 用户。可是脚本跑起来之后,结果却让我大失所望——控制台打印出来的内容完全不是我预想中的那种整齐的HTML结构。这说明这个小站网站并不是传统的动态网站,那种网站是后端直接把完整的HTML吐给浏览器的,不需要额外的渲染步骤。相反,它很可能使用了现代化的前端框架,比如 Vue 或者 Next.js,这些框架采用的是客户端渲染的方式,页面骨架先加载出来,具体的内容要靠 JavaScript 再去请求接口然后动态填充,普通的HTTP请求根本拿不到渲染后的完整内容。
既然知道了网站可能是用现代化 APP 引擎做的,需要 JS 执行完毕后才能看到完整的内容结构,但同时我也注意到一个关键的信息——我们在浏览器的开发者工具控制台里是能够看到完整的 HTML 结构的。这说明页面确实是有内容的,只是那些内容不是直接返回给原始 HTTP 请求的,而是需要浏览器内核真正去执行 JS 之后才会出现在 DOM 树里。AI 助手很快帮我分析了这个情况,提醒我可以直接使用一个完整的浏览器内核去完成这个任务,让程序像真人一样打开浏览器、加载页面、等待 JS 执行完毕,然后再从渲染好的页面里提取需要的信息。它向我推荐了 Playwright 这个工具,说这个库最近非常热门,功能强大而且文档齐全,于是我很快就写好了下面这段代码:
1 | #!/usr/bin/env python3 |
关于代码开源的事情,有人可能会问我为什么不把这个脚本上传到 GitHub 上,让更多人受益。答案其实很简单,就是我懒得写双语版的 README 文档。上次我做的那个邮件提醒文章的项目,双语版的 README 从头到尾都是 AI 帮我翻译和润色的,我本人的英语水平可以说是相当炸裂,写个中文说明还行,一碰到英文就头皮发麻。除了脚本本身之外,还需要一个依赖文件,就是那个 requirements.txt,里面列了一长串第三方库,这些库各自负责不同的功能,有的是做 HTML 解析的,有的是处理网络请求的,其中最核心的就是 Playwright,它是整个爬虫的发动机:
1 | beautifulsoup4==4.14.3 |
这个脚本的运作模式其实非常简单直接,说白了就是用一个下载好的浏览器内核去批量地、自动化地访问一个个小站的地址。脚本会从数字 1 开始,依次访问每个数字对应的小站页面,等待页面加载完毕,然后从渲染好的 HTML 中提取出 div.name 元素里的文字内容。如果某个页面加载超时了,脚本就会自动停止,不再继续往后访问,因为小站的编号是连续的,一旦遇到不存在的编号就不会再有后面的了,这个超时机制实质上就替代了标准的 HTTP 404 状态码的判断逻辑。我这里使用的是 Chromium 浏览器内核,和我日常使用的 Brave 浏览器内核差不多。如果需要安装这个内核的话,需要配置好环境变量,把浏览器的安装路径指向当前项目目录下:
1 | export PLAYWRIGHT_BROWSERS_PATH = $PWD/.playwright-browsers |
根据当前脚本的运行结果,B 站目前一共有 72 个小站。号码第一的是艾尔登法环小站,从内容能看出来法环的玩家群体确实很活跃;排在第二位的是 Switch 小站,任天堂的粉丝们也有了自己的聚集地;而排在最后一个也就是第 72 位的,是一个叫佛学学习分享的小站,这个倒是挺出乎意料的,谁能想到 B 站的小站里还有一个专门讨论佛学的地方呢。这些小站的名称在输出结果中都没有带空格,比如“艾尔登法环小站”就是连续的七个字,“Switch小站”也是连续的,中间没有任何多余的空格或标点符号。既然输出的格式已经够整齐了,我也就不打算再花时间去修改日志的打印格式了,保持现状就挺好的,反正核心的信息都已经完整地呈现在了控制台上:
1 | 开始爬取 Bilibili bubble home 页面(Playwright 引擎)... |
看了上面这份小站名单,不知道有没有你喜欢的那个圈子呢?如果你喜欢这个脚本,觉得它对你探索 B 站小站有帮助的话,不妨把这个博客地址收藏起来,等以后什么时候想再看看小站的变化,或者想自己跑一遍脚本看看有没有新增的小站,都可以随时翻出来用。如果你对这个脚本有什么改进的建议,或者在使用过程中遇到了什么问题想要评论的话,请记得在留言的时候填入你的名字和邮箱。这算是一个小小的忠告,因为如果没有留下邮箱地址的话,我即使想回复你的评论也没有办法通知到你,到时候你可能就收不到回复提醒了,那就太可惜了。希望这个小工具能帮到你,也欢迎你和我交流更多关于爬虫技术的心得。






