杜郎俊赏 - dujun.io

友情链接模块发布

新增友情链接页面,入口在电脑端的侧边栏或手机端的搜索页的“友链”。

1. 前言

建站七年了,一直没有做友情链接的模块。诚然,博客这种古典互联网产品,友链是最典型的应用,缺失有点遗憾。期间也反复想过要做,但是有两方面问题没有找到满意的方案。

1.1 没有满意的友链样式

网上常见的友链有这些样式:

  • 网站名称文字链接
  • 头像加网址、网站描述
  • 网站链接加最新 feed

头像、网站描述都是静态的,我觉得无趣。于是我尝试过抓取 feed,然后就有两个问题:

  • rss 地址发现,需要匹配各种未知规则,除非手动填写地址;
  • 有些网站没有 rss,如果直接爬取页面,匹配内容又很麻烦。

所有长期以来,友情链接的表现样式就把我卡住了。

1.2 没有满意的友链规则

相比样式,友链的规则逻辑是让我更想不好的。典型的交换友链方式是,博友之间直接联系,互相提供文字、链接、头像、截图等。我很不喜欢这样的流程,因为有恼人的几个因素:

  • 友链需要手动维护,这很不酷;
  • 友链如何排序?按评论数排序可以方便回访最亲密的博友,但常规来说应该按加入时间排序;
  • 如何监控网站有效性?失效的友链如何处理?手动删除不免令人感伤。

2. 契机

上面两方面问题困扰了我,直到最近遇到两个契机,让我下决心开发了友链模块。

2.1 开发友链的必要性

obaby 在 9 月 14 号《魔咒》的文章中提到给我加了友链。我挺不好意思。但是也重新考虑开发友链这件事。

2.2 找到满意的参考样式

正好Teacher Du在 9 月 20 号发表了文章《关于友情链接的一些事》,我认真看了杜老师的友情链接页面,惊喜地发现这就是我喜欢的样式:

这给我很大启发,网站截图比 feed 更加生动形象!

3. 实现

有了思路之后,实现起来倒不是难事。

3.1 抓取网站截图

借助 puppeteer 完成网站截图。该项目依赖 Chromium,安装时需要科学上网,或者用国内源:

sudo npm install -g cnpm --registry=https://registry.npm.taobao.org
sudo cnpm install puppeteer

关键 js 代码如下:

const
    puppeteer = require('puppeteer');
let
    args = process.argv.slice(2),
    isMobile = 'mobile' === args[0],
    waitUntil = 'strict' === args[1] ? 'networkidle0' : 'domcontentloaded',
    fetchUrl = args[2],
    putFile = args[3];

(async () => {
    const browser = await puppeteer.launch({
        args: [
            '--disable-gpu',
            '--disable-dev-shm-usage',
            '--disable-setuid-sandbox',
            '--no-first-run',
            '--no-sandbox',
            '--no-zygote',
            '--single-process'
        ]
    });

    const page = await browser.newPage();

    if (isMobile) {
        await page.setViewport({"width": 390, "height": 844, "isMobile": true});
    } else {
        await page.setViewport({"width": 1440, "height": 900, "isMobile": false});
    }

    await page.goto(fetchUrl, {'timeout': 60000, 'waitUntil': waitUntil});

    await page.content();

    await page.screenshot({path: putFile, fullPage: true, quality: 100});

    await browser.close();
})();

调用示例:

node /node/puppeteer.js mobile strict https://dujun.io /tmp/1.jpg

其中,waitUntil 是个关键参数。networkidle0 代表在 500ms 内没有任何网络连接,domcontentloaded 代表 domcontentloaded 事件触发。要做这个等待是因为有些网站是缓加载的,如果不等待,截图会是一个空白框架。networkidle0 是一个更严格的检查,像瀑布流加载的网站有可能超时,造成抓取失败,所以用 domcontentloaded 做二次抓取。

我需要生成电脑端、手机端两套截图,对应不同设备访问。

3.2 自动维护友链

我让友链的维护自动化,避免任何人工干预。

  • 发表过评论并填写了网址的,加入抓取列表;
  • 网址有效(header 200 OK)并能被 Chrome Headless 解析,否则过滤;
  • puppeteer 能够成功保存截图,否则过滤;
  • 按对应评论数从高到低排序;
  • 每天重建友链列表。

这就解决了网站有效性检查、删除无效网站,以及添加和排序的所有问题。

4. 成品

4.1 电脑端

电脑端浅色模式

电脑端深色模式

4.2 手机端

手机端浅色模式

手机端深色模式

标签: 开发
日期:2022-10-06