JavaScript 如何帮助我买到梦想之船
编程是一种超能力。只要稍加想象,程序员就能做到其他人难以企及或成本高昂的事情。我曾用它开发过一些或多或少有用的东西,最近我和家人决定买艘船时,我又有机会再次运用它。由于这是我们的第一艘船,我们没有任何购船经验,对市场也不甚了解。为了弥补这些不足,我求助于软件开发。
这个想法
虽然我租过几次船,但我完全不知道该怎么买。我决定最好的学习方法就是多看看船,了解有哪些船型可供选择,价格又是多少。
找不同的经销商,查看他们的库存,这倒是个办法。但我几乎立刻就放弃了,因为这太费时费力了,库存有限,而且价格似乎也虚高。相比之下,Craigslist 看起来是个更好的选择。人们和经销商每天都会在上面发布广告,所以各种各样的船型源源不断。缺点是,很多帖子质量不高,或者在我看来没什么意思。
于是,我想到了这个主意:开发一个应用程序,抓取 Craigslist 上的帖子,过滤掉那些明显不感兴趣的,然后筛选剩下的帖子。筛选过的帖子即使重新发布或更新也不会再次出现。下载的帖子即使 Craigslist 上的原帖被删除,也应该可以访问。有了这样的应用程序,我就可以看到类似的船型,了解不同的型号和配置,还能比较价格。
技术概述
在对要构建的功能有了大致了解之后,我开始考虑如何实现。我需要定期(例如每天)拉取帖子。这可以通过 cron 轻松实现。它需要一台服务器来运行,但幸运的是,我已经有一台树莓派,它负责家里的一些小任务,比如让我用手机打开车库门。这台树莓派可以运行我的新应用程序。
我需要一个数据库来存储帖子和精选结果。起初,我考虑过 MySQL 或 PostgreSQL,但考虑到我的需求非常简单,我意识到 SQLite 就足够了。
我决定在 Docker 容器中运行我的应用程序,以便于管理。我将数据与应用程序分离,将 SQLite 数据库文件存储在一个单独的 Docker 卷上。这样,在更新应用程序时,我可以轻松地维护历史数据:我只需启动一个包含新版本的容器,然后挂载包含数据库文件的卷即可。
下图展示了我的解决方案的架构:
我使用 TypeScript 实现了用于拉取帖子和应用程序的脚本,并使用 NodeJS 来运行它们。
细节
拔掉柱子
拉取帖子比我预想的要困难得多。我知道 Craigslist 很久以前就关闭了 API,但我以为可以通过发送简单的 HTTP 请求来获取帖子。一开始,我尝试使用 python-craigslist 封装库,但没能成功。经过一番研究,我发现用 HTTP 请求获取帖子库 是行不通的。帖子库的工作原理是下载一些 JavaScript 文件,这些文件会获取额外信息来动态构建 DOM。我不想放弃我的想法,于是我想到可以用 Puppeteer(一个无头 Chrome 浏览器)来下载帖子库(单个帖子仍然可以通过 fetch 下载)。这确实解决了问题,但需要编写比我计划的更多的代码。基于 Puppeteer 的方案速度也很慢(尤其是在老款 Raspberry Pi 上)。不过这倒也无伤大雅——使用 Puppeteer 的脚本由 cron 定时任务每天凌晨 2 点执行,在后台运行最多几分钟。
虽然在我的MacBook上使用Puppeteer非常顺利,但在树莓派上运行却费了不少功夫。我 为此专门写了一篇文章, 因为这其中缘由比较复杂。
我认为可能有更多的人对通过编程方式访问 Craigslist 帖子感兴趣,所以我将 我的解决方案开源 ,并将其发布为 npm 包。
注:我最近检查过,现在可以通过简单的 HTTP 请求再次获取 Craigslist 的帖子库。从这个角度来看,不再需要使用 Puppeteer 了。好消息是文档结构没有改变,我的 npm 包仍然可以正常工作。
帖子策划
Web应用程序
我需要开发一个应用程序来展示搜索结果并允许用户手动整理帖子。我使用了 Express 框架来实现这一点。虽然这是我第一次使用 Express,但网上的教程和资源让上手变得非常容易。说它的用户界面简洁都算是轻描淡写了——它非常简陋。尽管如此,它具备了我所需的所有功能。以下是它的界面:
- 没有使用 https,因为没有必要。该应用程序仅在我的本地网络上运行。
- 该应用程序运行在我的树莓派上。
- 转发和更新次数。
- 要价。
- 价格范围。
- 这张船的照片让我迅速判断这是否是我想要的那种船。图片同时也是指向 Craigslist 帖子链接的链接。
- 收藏按钮。点击它会将帖子隐藏并添加到不感兴趣的帖子列表中。
有了这样的条件,我相信找到合适的机会只是时间问题。果不其然,几个月后,我找到了一艘心仪的船,最终把它买了下来。
学习
我的日常工作是开发处理海量数据的后端系统。我花大量时间进行系统设计,主要使用 C++ 编写代码,并确保我们的服务流畅运行。这个业余项目让我有机会学习一些我以前很少甚至从未接触过的技术。我分享了在此过程中学到的知识。以下是列表。
- 这是使用 Puppeteer读取 Craigslist 帖子 的第一个原型。
- craigslist -automation npm 包 及其代码
- 在树莓派上用 Docker 容器运行 Puppeteer 的历程
- 我试图避免在 Docker 容器内运行应用程序,因为
root
最后,是把所有功能连接起来的代码:https://github.com/moozzyk/boat-scraper
💙 如果你喜欢这篇文章……
我每周都会发布一份面向软件工程师的简讯,帮助他们提升职业发展。我会分享我过去20年作为软件工程师所犯的错误以及吸取的经验教训。
点击这里订阅,即可将我的文章发送到您的邮箱。
文章来源:https://dev.to/moozzyk/how-javascript-helped-me-buy-my-dream-boat-4ipa


