5

我在 Notion 里做了一个 GameJam 游戏库

 1 year ago
source link: https://sspai.com/post/74002
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

我在 Notion 里做了一个 GameJam 游戏库

1
我在 Notion 里做了一个 GameJam 游戏库

Matrix 首页推荐 

Matrix 是少数派的写作社区,我们主张分享真实的产品体验,有实用价值的经验与思考。我们会不定期挑选 Matrix 最优质的文章,展示来自用户的最真实的体验和观点。 
文章代表作者个人观点,少数派仅对标题和排版略作修改。


当 Notion 遇到游戏,你觉得会撞出怎样的火花?在我这里,两者撞出了一个游戏库。

作为一个游戏爱好者,我发现自己总会被那些小巧的游戏作品吸引到。比如玩家们口中常说的独立游戏、或是那些诞生于 GameJam 的作品。

所谓 GameJam,可以理解为一种快节奏、鼓励创意表达的游戏开发活动,参加者或单人或组队抱团,需要在指定时间内从零开始制作出一个游戏,尽可能在游戏中表达一个特定的主题(通常由活动举办方指定),最终评选出优秀作品。(详情可以参考叶梓涛的 这篇介绍

我曾在一次线下的游戏展会试玩过 GameJam 中诞生的作品,虽然完成度很难比得上 Steam 上陈列的那些游戏,但大多有巧妙的玩法设计,时不时就能遇到眼前一亮的宝藏作品,让我惊呼于开发者的创意和才能。

但线下的展会终归是有限制的,受限于路程、开放时间、人流量等各种因素,我很难自由试玩自己感兴趣的游戏,这也给我埋下了遗憾,总是忍不住关注类似的 GameJam 活动,想着多玩一些活动中诞生的游戏,但又会因各种原因无法如愿。

直到前不久,我在 机核网 的 App 里看到在推送一个叫 BOOOM 的活动,我突然回想起来,这就是那个给我埋下遗憾的 GameJam。我一个激动,便给自己定下了「体验完所有游戏」的目标。

但要体验所有的游戏,首先我得知道总共有哪些,这样才能持续追踪进度。经过随后的一系列折腾,我成功在当天内搭建好了一个 Notion 游戏库,收录完了这届 BOOOM 中所有游戏的信息。

1

在 Notion 中搭建的游戏库,收录了机核网今年 BOOOM 所有作品的信息

在这篇文章中,我将回顾自己搭建这个游戏库的历程,如果你对数据收集、效率提升或信息管理感兴趣,或许也能为你解锁一些新知识,或是你熟知工具的新用法。

评估实现方案

如何收集数据?

在机核已经提供了 BOOOM 游戏列表 的情况下,数据的来源可以说是很明确了,直接从官方的页面中获取就可以。摆在开头的问题是:如何收集这些数据?收集后又要如何储存和呈现?

1

BOOOM 官方页面的游戏列表

如果游戏数量不多,比如只有十几个,那我还可以考虑人工收集一下,但扫一眼 BOOOM 的页面便知,这次总共征集到了百余款作品。如果人工收集一个游戏要 1 分钟,怎么说也得两小时,而且这是一个高度机械重复的工作,很难保证做到中途会不会丧失动力和兴趣,因而我最好考虑更高效的方案。

恰好我对 Python 爬虫略有了解,便想到用爬虫来收集数据,这样不单单能了解「有多少个作品」,连每个作品相关的名称、类型、链接等信息都能一并收录。但是否能爬、如何爬,取决于目标网页的情况。

为此,我需要从爬虫开发的角度评估 BOOOM 的活动页面,我通常会关注的点包括:

  • 需要哪些数据:比如文本、链接、图片,这部分会影响到数据提取的方式,以及后续如何储存这些数据
  • 选用哪一种爬虫库:取决于页面数据的加载方式(静态/动态)、是否需要登录、爬取逻辑的复杂度(加载更多/自动翻页/跳转新页面)等,我通常考虑的库有 scrapy、selenium 和 requests
  • 是否有可能不用写爬虫:比如如果能通过 Chrome Network 调试找到发送数据的请求、又比较方便手动构造是最好的,因为能拿到干净的 JSON 数据,而且又省事
1
1

写爬虫之前,我会先打开 Chrome 浏览器的开发者模式,审查页面元素在 html 中的位置,或是在 Network 分页中定位请求找到原始数据

经过一番观察,我有了初步的认知:

  • 官方的 BOOOM 游戏列表表现为垂直滚动、动态刷新,似乎还带有随机排序
  • 列表刷新是有限的,拖到最底部几次后就完全到底、不会再有新的出来
  • 列表中每个游戏的信息,涵盖了标题、封面图(静态/动态)、标签,点击可以跳转游戏详情页
  • 游戏的详情页,包含更多的图片(甚至视频)、文字描述(游戏介绍、下载方式、致谢词)、下载按钮(有的没有)、开发者信息(有的收录不全)

结论来说,可以爬,不过得想办法让爬虫模拟人滚动列表的操作,因为这部分的数据是动态加载、每次滚到最下面才会刷新。(具体做法见会在下面展开讲)

我也明确了要爬的信息,以及预想的用途:

  • 游戏名称
  • 封面图:便于视觉上快速辨别,作为封面也好看
  • 标签:为寻找自己感兴趣的作品提供参考,或许也可以用于分析
  • 链接:便于后续打开详情页看介绍、下载游戏和写评论
1

需要收集的信息,基本就是每个游戏卡片中的这些

如何储存管理数据?

收集数据是可以交给爬虫了,但数据存在哪里?怎么查看和使用?

我很快想到了自己常用的 Notion,(少数派这里应该大多知道,但以防万一还是介绍一下)一款瑞士军刀般的笔记软件,集写作、计划、管理于一体,其中的数据库功能,提供了丰富的数据类型和视图预设,也支持筛选、排序、搜索,几乎完美匹配我对 BOOOM 游戏信息的管理需求。

1

从社区的教程主题来看,Notion 也已经被玩出花了,写笔记、做计划、任务管理、习惯打卡不在话下

定好了数据收集和储存的方案,我也列出了接下来要做的事:

  1. 编写爬虫收集数据
  2. 将数据导入 Notion
  3. 在 Notion 中配置视图

编写爬虫收集数据

前面我也提到过,因为官方的游戏列表是每次滚到最下面才会刷新的,我得想办法让爬虫模拟人滚动列表的操作,这样才能确保收集到全部的游戏数据。

1

BOOOM 官方的游戏列表是动态刷新的

我因此而选择了 selenium 库,一个常用于模拟人为操作、测试网页的库,用它来爬取动态页面简直不能更合适。

明确了技术方案后,我没有直接开始写代码,而是先自上而下拆解了任务,就像项目管理中的工作拆解结构(Work Breakdown Structure,WBS),我从一个脚本的目的起步,拆解出了每一步要解决的问题:

  1. 打开 BOOOM 网页
  2. 模拟滚动页面,加载完所有数据
  3. 遍历列表,提取所需的信息
  4. 将数据存入本地文件

明确了每一步的任务后,启动 Visual Studio Code(用来写代码的软件),新建了一个 Python 文件,然后用注释写明了脚本的目的、每一步要解决的问题。这部分参考了 Google 的 Python 代码注释规范,经过个人的实践,发现确实能避免不少回顾代码时的一脸懵逼。

1

在脚本开头用文档注释写明整个脚本的用途,其余部分分块注释写明局部代码的用途

有了这样大致的框架,接着就要逐个解决每步的问题了,具体的技术细节这里略过,基本是面向搜索引擎编程,考虑到可能有人会感兴趣,这里概括一下最终是如何实现的:

  • 打开 BOOOM 网页:用 selenium 启动一个 Chrome 浏览器,打开 BOOOM 的活动页
  • 模拟滚动页面,加载完所有数据:用 selenium 执行 JavaScript 脚本,获取网页滚动高度并模拟滚动,直至滚动高度不再增加
  • 遍历列表,提取所需的信息:用 Xpath 表达式(一种用于在 XML 树状结构中定位节点的语言)定位网页中的每一个信息块,逐个遍历并继续用 Xpath 提取文本、链接等信息,存入列表套字典的结构里
  • 将数据存入本地文件:用 pandas (一个常用于数据处理的库)将数据导出至 CSV 文件

最终写了 50 多行的爬虫代码(其中有不少是注释和排版用的空行),运行后便收集完了此次 BOOOM 所有游戏的数据。

1

爬虫代码可能并没有你想象得那么复杂,一般几十行就能搞定了

爬到的数据导出到了本地的 CSV 文件,包含了 113 个游戏的这些数据:

  • title:文本,游戏名称
  • tags:列表,游戏打上所有标签
  • game_url:文本,游戏详情页的链接
  • img_url:文本,游戏封面图的链接
1

爬虫导出到 CSV 的数据

爬完了数据,按前面的计划,下一步就是把这些数据导入 Notion 了。

将数据导入 Notion

用过 Notion 的朋友可能会知道,Notion 的数据库功能是支持直接导入 CSV 的,导入后会自动补全不存在的列、设定好匹配的数据类型,但可惜的是我不能用这个功能。

问题就在于我收集的数据格式,有些是无法被 Notion 识别的,比如标签和图片链接。图片链接直接导入 Notion 会被识别为链接(URL 属性),而不是我希望看到的图片(Files & media 属性),这也意味着我之后要手动设置 100 多次图片数据,而不巧我是一个极度厌倦重复劳动的人。

1

CSV 直接导入 Notion,标签会变成文本、图片链接也没法显示对应的图片

于是新的问题摆在了面前,如何避免重复劳动将这批数据导入 Notion。我很快想到了 Notion API,Notion 官方为了方便开发者编写程序,将 Notion 与第三方工具打通、实现自动化而公开提供的一套接口。这时的我已经积累了一些使用经验、也打包了常用的函数,新写一个导入数据的脚本并不是什么难事。

1

Notion 官方对其 API 的介绍:打通 Notion 页面、数据库与你日常使用的工具,创建强大的工作流

类似写爬虫,我也拆解了这一环节的步骤,将数据导入 Notion 需要经历两步:

  1. 从本地文件读取数据
  2. 逐条遍历数据,在指定 Notion 数据库中新建页面

之后,针对每个步骤写代码实现:

  • 从本地文件读取数据:用 pandas 读取 CSV 文件,得到 DataFrame 结构的数据
  • 逐条遍历数据,在指定 Notion 数据库中新建页面:遍历每一条数据,提取各项信息并包装成 Notion 可接受的数据格式,用于新建页面

这里面比较头疼的是数据格式的转换,读取到的原始数据是一个个单独的变量,但为了让 Notion API 能正常使用这些数据,必须严格按照官方要求、重新包装成字典/列表层层嵌套的格式。

1

代码里包装后的数据格式,明显多出了很多层层嵌套、看得人眼花缭乱

好在 Notion 为使用 API 的开发者提供了相对完善的文档,比如 这篇文档 就全面列举了各种数据类型的格式范例,让我了解了如何通过 Files 属性在 Notion 数据库中插入图片。

但写代码哪有一次就能跑通的,我也在插入图片这步踩了坑,的确是参考官方文档写的,但一个页面都没有添加成功,最后排查下来发现是图片链接有问题,Notion API 那边无法使用带后缀的图片链接,于是我又加了一步正则匹配处理,才得以解决。

1

爬到的封面图链接跟着一串后缀,看上去是用来裁剪缩放原始图片的

1

正则提取到图片文件名的后缀为止,图片链接就可以被 Notion API 识别了

在多次测试、修复完各种大小问题后,最终成功将数据导入了 Notion。

1

成功导入 Notion 的游戏数据

在 Notion 中配置视图

至此,Notion 的数据库中已经保存了这些信息:

  • 游戏详情页链接
  • 封面图链接

尽管游戏库所需的数据都已经导入,但实际用起来还是会有不同的使用案例,因而还要从不同需求出发、设计对应的数据视图。

我从「体验完这届 BOOOM 所有游戏」的目标出发,列出了这些使用案例:

  1. 围绕体验进度跟踪作品
  2. 随机浏览作品、找找灵感
  3. 查看已体验作品的评分

列完后,我发现还需要建新的数据库,因为使用案例 1 和 3 都涉及到个人试玩作品的评分,而现有数据库管理的对象是游戏作品、不是评分,如果硬要将评分数据存在这边的数据库,会使得信息管理起来过于臃肿。

于是我又新建了一个「测评记录」数据库,根据试玩需要设计了数据模型:

  • 游戏:关系,绑定到另一个数据库中对应的游戏,可以通过关系互相查表
  • 表现力:数值,打分用
  • 创新:数值,打分用
  • 符合主题:数值,打分用
  • 喜爱程度:数值,打分用
  • 开始测评:时间,记录用
  • 结束测评:时间,记录用
  • 总评:文本,概括玩法+优缺点评价+总结
  • 测评用时:公式输出数值,用开始和结束时间计算游玩了多少分钟
  • 总分:公式输出数值,综合上面的几项打分计算总分,各项权重暂定均等
  • 总分-图标化:公式输出文本,将总分转为 N 颗⭐的文本
1

一条测评记录会包含的数据/属性

再回到游戏的数据库,参考前面罗列的使用案例,通过组合 Notion 中的视图、筛选、排序、可见属性,我最终创建了 4 个不同的数据视图:

  • 随机漫步:满足「随机浏览作品、找找灵感」的需求,以卡片呈现,显示封面、标题、标签、链接,伪随机排序(每分钟更新)
  • 测评看板:满足「围绕体验进度跟踪作品」的需求,看板按进度分组,显示封面、标题、标签
  • 已完成:满足「查看已体验作品的评分」的需求,以表格呈现,筛选已完成的、评分降序,显示所有属性
  • 总表:临时搜索用,以表格呈现,显示所有属性
1

随机漫步

1

测评看板

1

已完成

1

总表

在随机漫步视图中,我用到了一套拍脑袋想出来的伪随机算法,刚好实现了每分钟重置一次列表排序。原理也很简单,每个作品的链接中有唯一的数字 ID(用正则从中提取),我在公式中代入当前的时间戳(精度是毫秒,但每分钟更新),用时间戳除 ID 取余数,最终每个作品就都会有一个每分钟更新、顺序不固定的数字,再用这个值来排序就可以

1

用 ID 计算出伪随机数

1

实现伪随机的 Notion 公式

分享到社区

到了这一步,我自己试玩所需的数据库已经算是搭好了,但我还准备额外做一个分享版,因为想起了自己用官方页面的痛点:

  • 找特定的某个作品很难,往往要刷新出完整列表再 Ctrl+F(这时还不知道可以用机核的站内搜索)
  • 浏览的连续性易被打断,随机排序时不时作品顺序就变了

既然我会有这样的痛点,说不定还有其他人也会有相同的体验,而这套游戏库应该也能帮到他们,发挥更大的价值。

很快,我复制了一份现有的数据库,重新配置了一套视图:

  • 卡片:期望解决浏览不连续的痛点,卡片呈现,固定排序,显示封面、标题、标签、链接
  • 随机漫步:满足随机探索需求,沿用现有的不变(老实说这又回到了官方的展示逻辑)
  • 表格:满足搜索需求,表格呈现,显示所有属性
1

分享版游戏库的卡片视图

接着,通过 Notion 的分享功能,我将这个新游戏库公开分享到了网络,开启了评论、搜索引擎检索,然后在机核发了条动态带上分享链接,将其分享了出来。

1

当时分享游戏库的机核动态

在发完那条动态后,我也有了一些意料之外的收获。

我收到了来自这届 BOOOM 开发者的点赞,游戏《Cato》的开发者 Blasin-Ree 在动态下评论,说这套 Notion 版的游戏库比官方的方便,让我着实高兴了好一会。

1来自 GameJam 开发者的点赞

之后,《TRAiLS》的开发者 SleepyJeff 也找到了我,他帮我把这套游戏库的链接转发到了 BOOOM 开发者的群里,但发现有一个作品被漏掉了,可能是这组提交的比较晚、导致没被爬虫收集到。

1

收到反馈说有作品没被收录,当时第一反应是自己写的代码有问题

我了解后,也去排查了一波,确认当时的官方列表里依然没收录到这个作品,于是帮忙手动补录了信息。这个作品是《斯巴拉西》,我之后试玩到发现美术很棒、完成度也很高的一个音游作品,希望这波补录能帮到他们。

1

如果你喜欢音游或是搞怪的游戏题材,推荐去玩一玩《斯巴拉西》,很有趣的一个音游作品

还有一个意外收获,就是被一个叫西蒙的人关注了,我后来才知道,他是机核的创始人。

回顾这次的 BOOOM 游戏库搭建,我学到了这些:

  • 爬虫收集的数据若需要持续访问使用,量级不大时可以考虑导入 Notion
  • 在代码注释中点明目的,比点明做了什么更有助于帮助回顾
  • 将围绕某个使用场景的常用函数打包,能让后续的开发更省事
  • 涉及到重复操作 Notion 数据库时,可以考虑用 Notion API 做自动化
  • 个人项目的产物可能也对他人有所帮助,多考虑分享

感谢 Blasin-Ree 的点赞、SleepyJeff 的热心联系,还有西蒙的关注,这次实践后,我发现自己不仅在知识输出上迈出了一步,也和独立游戏社区里的人们建立了更紧密的联系。

如果你也对这届 BOOOM 感兴趣,想试玩其中的游戏作品,可以访问 机核的活动页面,或通过我收录的 游戏库 寻找心仪的游戏。

这也是我在少数派的第一篇文章,如果这篇文章对你有所帮助,希望能点赞收藏一下,这是对我持续创作的最大支持。如果有其他想讨论的,也欢迎在评论区留下你的看法。

> 下载 少数派 2.0 客户端、关注 少数派公众号,解锁全新阅读体验 📰

> 实用、好用的 正版软件,少数派为你呈现 🚀


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK