微信公众号的正确使用方式

2021-08-15 ⏳5.3分钟(2.1千字) 🕸️

个人博客最不好解决的问题就是用户触达。某一篇文章可能写得不错,也可能在社交平台大范围传播,但用户看完就走了,没法订阅作者后续的内容更新。但另一方面,开放互联网苦微信久矣。微信是流量黑洞,许进不许出。作为个人内容创作者,多少有点互联网情怀,不愿意为其贡献内容。我很早就注册了公众号,但一直没有使用。如果把它当成一个内容创作平台,当然会有很多限制。比如不能在文章内容随意插外链,文章必须指定封面图等。但如果把它当成一个消息推送通道,也就是 RSS 的替代品,那公众号确实是不错的工具。今天就来说一下如何用 RSS 的方式运营公众号。

那个人博客应该怎样跟微信公众号结合起来呢?答案是使用图文消息!图文消息可以指定消息内容和原文链接🔗。我们可以将文章的摘要以图文消息的形式推送给读者。如果读者对内容感兴趣,可以通过阅读原文链接来继续阅读。使用原文链接还有一个好处,是微信不会再提示恼人的「非微信官方网页」。

但有一个问题,图文消息需要封面图。我们要选什么样的封面图呢?这个问题一直困扰了我好长时间。虽然人是视觉动物,但我不想为了吸引读者的眼球放图片,更瞧不上那些用擦边色图当封面的行为。

我最希望的方式是发一条纯文本消息,将文章的标题、摘要和原文链接推送给读者。公众号确实在后来支持文本消息,但文本消息不支持添加原文链接。

后来,我想了一个办法。就是上传一张固定图片,所有文章都引用这个封面。其实也不是我的原创,而是受上海发布这个公众号启发。比如,上海发布会给所有的新冠疫情发布信息加一个「情况通报」封面。我试了一下,如果是发单条消息,封面占据的可视面积太大了,人眼甚至会忽略文章的标题。如果所有文章都用一个封面,肯定会造成视觉疲劳,而且还浪费了用户宝贵的注意力。

一计不成,再生一计。能不能根据文章摘自动生成封面呢?答案是肯定的。经过一番折腾,我开发了一个文本转图片的小工具,还写了Go语言实现文本转图片这文章。

慢着,我这是要在写完博客后再到公众号平台写一遍图文消息吗?显然不能够呀!怎么办?用公号平台的接口。

微信还是很贱的,大多数关键接口都不开放给普通用户。如果想用,必须通过官方认证。这个认证要每年做一次,一次的费用是三百。花钱💰还是小事,关键是要有法人身份,最少也得是个体户。这就太麻烦了。

因为太麻烦,我也就没再折腾。但后来我发现,创建图文消息的接口是开放给所有用户的。艾马🐴,怎么早没看到呀。搞起来。

在开始之前,需要获取公众号的开发者ID(AppID)和开发者密码(AppSecret),这个在后台可以查看,忘记了可以重置。然后,你就会碰到微信另一个比较贱的地方——IP白名单。

调用微信API之前需要先获得所谓的 access_token。而调用获取 token 的接口需要在后台指定IP白名单。也就是说,你没法在家庭网络或者办公网络获取 token,因为这些网络的IP会经常变。总之,对个人开发者非常不友好。好在我有个人服务器,有固定IP。

获取 access_token 的接口调用非常简单,指定 appid 和 secret 两个参数就好了。

API_ROOT=https://api.weixin.qq.com/cgi-bin
curl "$API_ROOT/token?grant_type=client_credential&appid=$id&secret=$secret"

获取的 access_token 有效期为两个小时,接口还有限频,不能调用太快。最简单的办法就是设置一个定时任务,每小时运行一次,然后把结果(json)保存到一个文件。保存好 json 文件之后,我们需要提取 token 内容。简单的内容可以直接使用 grep 提取,但复杂的内容就需要用到 jq 就个工具了。jq 的用法可以参考我的另一篇文章如何在命令行中优雅地处理JSON

总之,我们可以通过 jq -r '.access_token' token.json 来提取 access_token 的内容。为方便后面引用,我们可以直接把它设到环境变量中:

export WX_TOKEN=$(jq -r '.access_token' /tmp/wechat/token.json)

然后,我们需要生成文章摘要的封面图,需要使用 txtimg 工具,Go语言实现文本转图片有详细介绍。

bash $root/1p.sh $1 txt | \
        txtimg -fontfile /root/fang.ttf \
        -width 940 -height 400 \
        -padding 10 \
        -chars 20 \
        -spacing 1.1 > /tmp/tmp.png

我这里使用了一个叫 1p.sh 的脚本,主要作用是提取 markdown 文件的第一段,而且要跳过前面的 metadata 部分。因为不是所有人都用 markdown,就不展开讨论了。有需要的可以加联系我。

生成好图片,就需要上传到公众号后台。这个接口在官方文档中叫新增其他类型永久素材,可以使用 curl 完成:

API_ROOT=https://api.weixin.qq.com/cgi-bin
mediaid=$(curl "$API_ROOT/material/add_material?access_token=$WX_TOKEN&type=image" \
        -s \
        -F "media=@\"/tmp/tmp.png\";filename=\"$imgname\"" | \
        jq -r '.media_id')

curl 使用 -F 指定表单上传参数。参数的名字必须是media,等号后面使用**@**指定图片的路径,分号后面的filename用来指定图片素材的名字,不指定则直接使用文件路径中的名字。这部分内容腾讯的官方文档没写,说是让自己查。我是从StackOverflow找到的。

接口调用成功后可以通过 jq -r '.media_id 获取素材ID,生成图文消息的时候需要用到这个ID。

有了图片,我们就可以生成图文消息了,对应 新增永久图文素材接口。在调接口之前,我们需要准备一个 json,结构如下:

article=$(cat << EOF
{
  "articles": [
    {
      "title": $(echo $title | jq -R),
      "content": $(echo $content | jq -R),
      "thumb_media_id": "$mediaid",
      "show_cover_pic": 0,
      "content_source_url": "$newsname",
      "need_open_comment":1
    }
  ]
}
EOF
)

这里使用了 heredoc 语法。需要指定的是四个字段:

还有一个点,因为是 json,所以 title/content 的内容都需要转义,不然可能破坏 json 的结构。这个可以用 jq 工具实现,非常方便。准备好 json 数据,就可以调用接口了,同样非常简单:

API_ROOT=https://api.weixin.qq.com/cgi-bin
curl $API_ROOT/material/add_news?access_token=$WX_TOKEN \
        -s \
        -H 'content-type:application/json' \
        -d "$article" | \
        jq -r '.media_id'

好了,到现在,我们就创建了一条图文消息。

然而,腾讯没有开放群发消息的接口,需要我们登录公众号后台手工群发。贱!不过,考虑到图文消息已经准备好,手工发一下也不是太大的负担,忍了吧。

以上只是核心处理逻辑。如果要达到实用的水准,还得结合素材列表接口删除永久素材接口。这部分逻辑因人而异。我的处理方式是根据原文链接查询图文消息,如果有则删除,然后创建新的图文消息。大家可以根据自身情况制定相关逻辑,此处就不展开了。

最终,我的微信公众号开张了。公众号的名字就是 taoshu。其实我想用 taoshu.in,但点是特殊字符,需要提交商标注册证,没办法了。本文的图文消息可以点击这里体验。