惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Forbes - Security
Forbes - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Palo Alto Networks Blog
Martin Fowler
Martin Fowler
T
Threatpost
D
Docker
S
Schneier on Security
M
MIT News - Artificial intelligence
G
Google Developers Blog
L
LINUX DO - 热门话题
J
Java Code Geeks
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
IT之家
IT之家
博客园 - Franky
C
Cyber Attacks, Cyber Crime and Cyber Security
K
Kaspersky official blog
Google DeepMind News
Google DeepMind News
N
News and Events Feed by Topic
V
Vulnerabilities – Threatpost
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
人人都是产品经理
人人都是产品经理
Spread Privacy
Spread Privacy
T
Tailwind CSS Blog
爱范儿
爱范儿
阮一峰的网络日志
阮一峰的网络日志
U
Unit 42
C
CERT Recently Published Vulnerability Notes
The GitHub Blog
The GitHub Blog
Simon Willison's Weblog
Simon Willison's Weblog
NISL@THU
NISL@THU
MongoDB | Blog
MongoDB | Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
H
Heimdal Security Blog
Recorded Future
Recorded Future
云风的 BLOG
云风的 BLOG
SecWiki News
SecWiki News
P
Privacy International News Feed
P
Proofpoint News Feed
O
OpenAI News
B
Blog
腾讯CDC
F
Full Disclosure
Apple Machine Learning Research
Apple Machine Learning Research
T
Tor Project blog
H
Hacker News: Front Page
Project Zero
Project Zero
Hugging Face - Blog
Hugging Face - Blog
C
Cisco Blogs
S
Security Affairs

少数派

派早报:Google 发布 Fitbit Air 等 - 少数派 「新人报到」確認需求,再開始 - 少数派 从 SOLO 独立开发者社区,我看到了越来越多开发者开始做自己的产品 - 少数派 我怎么管理那些"不常做,但总会忘"的生活事项 - 少数派 人形机器人量产元年,数据才是具身智能的“生死线” - 少数派 BuhoLaunchpad 高度还原 Mac 启动台:开发历程与思考 - 少数派 五年陪伴依然不舍,DIY 换壳后让罗技 MX Master 3 继续服役 - 少数派 新玩意 240|少数派的编辑们最近买了啥? - 少数派 一日一技|为什么你应该关闭 iOS 的键盘声音 - 少数派 我做了个插件和 Skills,一键提取任何网站的设计规范 Design.md - 少数派 住在三四线城市的你,该开始录播客了 - 少数派 甘南秘境,大白高国 - 少数派 AI的审美:谁让把我变成川内倫子 - 少数派 返工怎能不烦恼,打工人片单总有一部是你的「嘴替」 - 少数派 为了让「上厕所」更健康,我做了一个小工具 - 少数派 AI + Skill,能够让生成的文章去除 AI 味吗? - 少数派 新玩意|韶音OpenDots ONE 耳夹式耳机 - 少数派 《美满》| 在每一个春天的晚上相爱(362) - 少数派 新玩意|优篮子 PS01 MagSnap 磁吸支架 - 少数派 自我整合手记 | 我开始早睡了:用稳定规则,为自由托底 - 少数派 用龙虾(OpenClaw)两个多月,我最深的12个体会 - 少数派 听歌时间到,12 张你可能错过的 2025 华语乐坛好专辑 - 少数派 承诺能追吗 - 少数派 macOS 26启动台没了? 我做了个不一样的App启动器 - Keboard - 少数派 《四海为家的人》| INTJ对话INTJ(361) - 少数派 你发过的那些黑历史,是时候一次清干净了 - 少数派 新玩意:安安静静玩,越玩越专注:计客密码机 - 少数派 iPad 用户首次体验 Android 平板:vivo Pad6 Pro - 少数派 数据逻辑强 - 少数派 极北行+ | 一路向北,探访日本至北之地 | 001 - 少数派 万字剖析:千问App深度体验报告(2026) - 少数派 在2026年,如何真正防止别人抄袭你的作品 - 少数派 怎么用 50 块搭个 AI 语音助手?我踩了 3 天坑 - 少数派 YeeroAI:让 AI 对话真正成为知识管理的一部分 - 少数派 爬泰山 - 少数派 「旅图显影」 App 更新:这次,我们补上了一点「手感」 - 少数派 假期出门太折磨?我的 23 条经验帮你规划惬意旅行 - 少数派 工作流会变吗 - 少数派 Claude Opus 4.6 怎么用最省钱?我测了 5 种方案 - 少数派 GPT Image 2 让图文并茂不再稀罕 - 少数派 用户侧出发——什么是AI,我要不要学习? - 少数派 找片、转存、整理、播放一条龙!让你的付费网盘值回票价 - 少数派 欢迎试用!日课一问2.0插件 - 少数派 自己做的MDeditor,原本想购买 Typora 试了两次支付不成功,干脆自己做一个 - 少数派 vibe coding了一个 3MB 的小工具,让 ~/Downloads 彻底告别混乱 - 少数派 因为受不了 Mac 的风扇策略,我做了一个风扇控制工具 - 少数派 别只怪模型 - 少数派 Warp 终端的 AI 功能怎么用?我测了一周的体验 - 少数派 AI 写代码老是出 bug?这 5 个配置我后悔没早知道 - 少数派 「新玩意」苹果出相机可能就这样:Sigma BF + 45mm F2.8 DG Contemporary - 少数派 一个面向2030年的AI操作系统是什么样子的:浅谈cola这款有灵魂的Agent - 少数派 别只看写代码 - 少数派 每天解决10个问题,还是一口气攻坚解决400个? - 少数派 AI 交易机器人怎么搭?我用 Claude 跑了一周实盘 - 少数派 Maptoposter Online:把你爱的城市画成艺术海报 - 少数派 Function Calling 怎么用?我测了 3 个模型发现差距真大 - 少数派 Legend Talk:我做了个 AI 圆桌,让 160 位思想家围着你的问题转 - 少数派 如何找到自己的蓝方?在小县城寻找压力测试 - 少数派 语音输入与软件接口|2026年聊AI时,我们都聊些什么(上) - 少数派 混动已经卖爆,纯电又来补刀——钛7闪充版简直“不讲武德” - 少数派 本月玩什么|朋友收藏、识质存在、沙罗周期 - 少数派 为什么要每天坚持输出? - 少数派 Claude API 挂了好几个小时,你的项目有备用方案吗? - 少数派 Function Calling 没你想的复杂——我用它做了个有点用的工具 - 少数派 登录系统立即播放视频或者图片音乐的软件 - 少数派 我为什么创建 FlipHTML5 下载工具 - 少数派 残局没电?多品牌外设电量统一管理软件EasyBluetooth已支持RTSS游戏内显示以及AIDA64 - 少数派 前往通义路的路 - 少数派 太好看了,媲美Sun的个人导航页,NAS部署星云门户 - 少数派 乌黑嘴唇“一键检测”上线了 - 少数派 派早报:Claude AI 接入多个创意软件生态、FILCO 生产方接手品牌等 - 少数派 【更新】BearCLI、Claude 连接器与 MCP 服务器 - 少数派 记了上千条流水,还是看不懂财务?我做了一个让 AI 读懂账本的工作台 - 少数派 MINI R56 升级原厂 Sport 模式 - 少数派 新玩意 | 一棵柠檬树(仿真版) - 少数派 Momenta的“物理AI”野望,需迈过“含摩量”这道关 - 少数派 网页直接投屏控制手机!NAS一键部署PandaScrcpy,流畅丝滑可远程。 - 少数派 众测|邀你一同探索随身 AI 硬件入口 YoooClaw C·ONE - 少数派 2050大会:分享时间是真诚 参会记 - 少数派 iPad 赋能电影创作:国内首部宣纸手绘长片《燃比娃》的幕后故事 - 少数派 AI的审美:我用 8 个大模型给 100 张旅行照片打分 - 少数派 普通人如何破圈?去参加一个本地协会 - 少数派 把极空间的图标全换了,主题DIY全攻略打造你的专属NAS桌面 - 少数派 电子便签墙,帮你实现便签自由 - 少数派 我如何用三个 CLI 工具取代文档创建需求 - 少数派 原来真的有人可以玩一辈子 - 少数派 社区速递 139 | 派友热议三月买了啥、复古单反尼康 Df 体验 - 少数派 06 作品的赏析与评价 - 少数派 TDS REVIEW|索尼 WF-1000XM6 降噪真无线耳机体验 - 少数派 35.98万起售的第二代腾势D9,我看重的不是堆料,而是不凑合 - 少数派 鼠须管 Squirrel 皮肤配置指北 - 少数派 从watch ultra2换到redmi watch6 - 少数派 派早报:阿里巴巴发布视频生成模型 HappyHorse 1.0 等 - 少数派 别迷信1M - 少数派 家人们天塌了!网盘“大封杀”,多个渠道多条路,NAS部署PanHub - 少数派 AI与人勾心斗角!NAS一键部署AI狼人杀,假日休闲必备。 - 少数派 电商必备!Comfyui工作流批量生图插件,一次生成12张!支持Nano banana pro模型 - 少数派 Comfyui工作流配置Gpt-image-2模型教程,0.03/张 - 少数派 OpenClaw第三方APi怎么配置?可使用Gpt-image-2模型 - 少数派 会员社区话题精选 Ep. 103 - 少数派
妙用书签,将微信文章装进 Drafts - 少数派
2021-04-14 · via 少数派

编者注:本文涉及到 Bookmarklet 相关知识,如果你对该工具不熟悉,可以通过以下文章有所了解:


对于许多人来说,微信公众号是获取信息的重要来源。但是在微信封闭的环境里,没有这两个功能:文章关键词搜索和重要文段高亮,而且还有一个致命的问题:一旦文章被删除,以后想再找到就比较费劲了。

为了摆脱微信的束缚,更加方便地搜索文章,我们需要另寻出路来收藏微信公众号文章。我的主力笔记软件是 Bear,在文章被保存到 Bear 之前会先发送给 Drafts,对需要阅读的文章进行文段预处理和添加笔记标签。Drafts 有完善的 URL Scheme 支持,所以拿它来收集微信文章就再合适不过了1

但是微信文章怎么能让它支持 URL Scheme 呢? Bookmarklet 就在中间起到了桥梁的作用,沟通了这两个原本看似互不相干的事物。

注:同样的思路也可以用在其他支持 URL Scheme 的笔记软件中。例如同样对 URL Scheme 支持较全的印象笔记,只要在 Drafts 中选择将内容保存到印象笔记即可。

编写 Bookmarklet 代码

观看完上面的演示视频,或许你可以猜到这个 Bookmarklet 的作用就是将文章内容粘贴到 Drafts 中,分为三个步骤实现:

  1. 先把微信公众号文章在 Safari 中打开
  2. 在 Safari 中调用 Bookmarklet 拷贝文章内容到 Drafts 中
  3. 最后通过 x-success 自动跳回微信

本文的重点就在于第二步 Bookmarklet 代码的编写。

首先,构思一下我们需要 Bookmarklet 实现哪些功能:

  • 获取文章内容:通过 Bookmarklet 里面的 JavaScript 代码获取到文章内容
  • 拷贝文章内容:将获取到的文章内容拷贝到系统剪切板
  • 在 Drafts 打开并粘贴内容:通过 URL Scheme 打开 Drafts 并从剪切板新建草稿

本文会涉及到较多 HTML 知识点,我会尽可能通俗易懂地向大家解释清楚每一步的作用。

在此之前需要前往 Safari 设置 → 高级 → 勾选「在菜单栏中显示“开发”菜单」,只有勾选之后才能使用快捷键显示出网页检查器。

获取文章内容

首先,我们来认识一下 HTML 网页的基本结构,如下所示:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>网页标题</title>
</head>
<body>网页内容</body>
</html>

<!DOCTYPE html> 用于区分文档类型,<html> 声明这是一个 HTML 网页,<head> 标签用于给网页添加基本的配置信息,<meta> 用于存储相关的元数据,那么顾名思义 <title><body> 就是分别对应着文章的网页标题和网页元素了。

首先要做的事情就是获取 <body> 标签的内容,在 HTML 的世界里,每一个网页都可以被视为是一份文档(document)。JavaScript 提供了 document.body 这样一个元素接口用于返回当前文档中 <body> 元素内容。同理可得,也有 document.title 可以获得网页标题 。

现在通过实践验证一下,在 macOS 的 Safari 上任意打开一篇微信公众号的微信,按下快捷键 option+command+i 打开网页检查器,在控制台输入 doucument.title 可以看到控制台返回了文章的网页标题。

输入 document.body 后遗憾地发现,它并没有输出我们期待的正文内容,这是因为 document.body 返回的内容是 HTML 代码。

为了获取 HTML 代码中的文本内容,HTML 也提供了相应的 innerText 属性,输入 document.body.innerText 就可以看到控制台成功输出了正文内容。

截屏2021-04-05 下午10.24.58

细心的读者看到这里可能就会有疑问了:这样做可以获取到文章内容没错,但是配图不是都丢了吗?为什么会考虑使用纯文本保存文章?

这样做是出于以下两个原因: 

  1. 图片对阅读理解的影响较小:我阅读的 95% 以上的文章是不需要配图就可以正常阅读的,配图在文章中的作用更多是辅助理解,只有不到 5% 的文章需要我手动去添加图片。
  2. 图片过于占用储存空间:曾经看到一个群友使用印象笔记收集了 2000 篇文章占用了 10GB 存储空间,大量不必要的图片收藏不仅占用空间,而且如果有多台设备要进行初次同步,这个过程也是非常漫长的。目前我在 Bear 中保存了 1616 篇笔记,占用存储空间仅仅只有不到 600MB。

拷贝文章内容

第一步获取文章内容完成,第二步就是要把获取到的文章内容复制到剪切板为后续的操作做铺垫。使用 JavaScript 拷贝文本在 GitHub 上已经有非常稳定成熟的代码可供参考了,所以可以不必再重新造一遍轮子。以 bradleybossard 在 2016 年编写的 titleUrlMarkdownClip.js 代码为例进行说明,本文制作的 Bookmarklet 拷贝文章内容模块代码正是从此处借鉴来的,代码如下:

function copyToClipboard(text) {
   if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
        var textarea = document.createElement("textarea");
        textarea.textContent = text;
        textarea.style.position = "fixed";
        document.body.appendChild(textarea);
        textarea.select();
        try {
            return document.execCommand("copy");
        } catch(ex) {
            console.warn("Copy to clipboar failed.", ex);
            return false;
        } finally {
            document.body.removeChild(textarea);
        }
    }
}

可以看出,他将拷贝文本这个功能封装成了 copyToClipboard 函数,方便在其他地方调用,只要将需要拷贝到剪切板的内容作为参数传入这个函数,即可将其复制到剪切板。

看到第二行的 document.queryCommandSupported 方法,很容易可以猜出这个方法的用途是检测浏览器是否支持指定的编辑指令。此处的判断条件就是如果浏览器支持运行 copy 指令,则进入接下来的文本复制语句块。但是由于这个 Bookmarklet 是在 Safari 上使用的,而 Safari 是支持 copy 指令的,所以不必担心兼容性问题。

从第三行到第七行执行的操作依次为:

  • 创建临时元素 textarea
  • 将传入参数 text 赋值给临时元素 textarea,此处的参数 text 就是正文内容(document.body.innerText);
  • 设置 textarea 元素定位方法类型;
  • textarea 作为子节点添加到文章内容的末尾处,为接下来的选择文本做准备;
  • 使用 select() 方法选中 textarea 元素中的文本内容,这个步骤相当于使用鼠标选中文本,两者是一样的。

第八行调用 document.execCommand() 方法运行 copy 指令拷贝 select() 方法选中的内容,也就是文章的全部内容,如果错误就向控制台输出错误信息,否则复制成功之后删除 textarea 这个临时元素。

在 Drafts 打开并粘贴内容

在成功地实现了代码的前两个功能之后,接下来就是要打通 Safari 和 Drafts 之间的通道,这就需要 URL Scheme 和剪切板共同发挥作用了。

文章内容已经被拷贝到了剪切板,第三步只要制作一个动作让 Drafts 根据剪切板内容新建文稿即可,而 Bookmarklet 要做的事情就是打开 Drafts 并运行这个动作。通过查阅 Drafts URL Scheme 文档 可以知道 Drafts 运行动作 URL Scheme 为:

drafts5://x-callback-url/runAction?action=paste

在这里建议将动作名命名为 paste,最后一步只需要调用 window.open() 方法打开这个 URL Scheme 就完成了,这个步骤的代码如下:

url = 'drafts5://x-callback-url/runAction?action=paste';
window.open(url,'_self');

这里需要解释一下为什么不在 Bookmarklet 的代码中直接将 document.body.innerText 作为 URL Scheme 的 text 参数传递给 Drafts,而是要通过剪切板来传递文章内容。

如果直接将文章内容作为 URL Scheme 的 text 参数传递给 Drafts,所有的换行符都会被吃掉。具体原因没有深究,后来想到使用剪切板传递文章内容是个解决的好办法,于是就沿用下来了。

Bookmarklet 完整代码

javascript: (function() {
    function copyToClipboard(text) {
       if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
            var textarea = document.createElement("textarea");
            textarea.textContent = text;
            textarea.style.position = "fixed";
            document.body.appendChild(textarea);
            textarea.select();
            try {
                return document.execCommand("copy");
            } catch(ex) {
                console.warn("Copy to clipboar failed.", ex);
                return false;
            } finally {
                document.body.removeChild(textarea);
            }
        }
    }
    copyToClipboard(document.body.innerText);
    url = 'drafts5://x-callback-url/runAction?action=paste';
    window.open(url,'_self');
})();

在 Drafts 中创建 paste 动作

通过以上几步,我们已经将文章内容拷贝到了剪切板,接下来就是要在 Drafts 里创建一个名为 paste 的 Action(点击安装),让它能够从剪切板读取内容,并用这个内容新建草稿,以下是制作思路:

通过查询 Drafts URL Scheme 文档 可以知道 Drafts 新建草稿的 URL Scheme 为:

drafts5://create?text=

打开 Drafts 新建 paste 动作,让它能够从剪切板读取内容并新建草稿

在 IDENTIFICATION 处填写动作名称,例如图中的「paste」,接着点击「0 steps」滑到动作库底部选择 「URL」:

编辑 URL,看到下图红框框起来的参数了吗?通过 [[clipboard]] 参数可以非常方便地获取到剪切板的内容,将它和刚才上面查询到的新建草稿的 URL Scheme 拼接之后就可以得到这样一个 URL Scheme:

drafts5://x-callback-url/create?text=[[clipboard]]&x-success=weixin://

增强功能

做完了上面这些功能,基本的功能都已经实现了,已经可以通过 Bookmarklet 复制粘贴到 Drafts 然后返回微信了。但是在实际使用过程中发现了以下三个新的功能需求:

  • 标题带上作者和公众号
  • 文章尾部带上原始链接
  • 删除微信底部文章推荐

标题带上作者和公众号这一步是最为麻烦的,需要再拆分为三小步完成。所以接下来沉住气,一起来探究为什么需要这些功能以及它们是如何实现的。

获取文章作者名字

为什么要在标题带上作者和公众号?在《从文本格式化到分类收藏,我的文章阅读自动化流程》中提到我的阅读流程是:微信文章粘贴到 Drafts → Drafts 打上标签保存到 Bear → 在 Bear 中进行阅读 → 阅读完成后添加内部链接到「复盘清单」笔记,如下图所示:



但是不同公众号作者可能是不同的,这与公众号的文章来源有关。比如刚才在上面测试用的文章:《和 Apple 一起工作是什么体验?说说这些趣事》的作者是「四处趴趴走」,发布的公众号是「少数派」。这篇文章的标题是比较好记住的。但是如果碰上不太好记的标题,那么就可以在「复盘清单」中搜索作者或者公众号来查找这篇文章。而且在记得文章作者的情况下,根据作者来查找一篇文章速度也是比标题或者公众号更快一些。

打开网页检查器,来到元素页面按下 command+F 搜索网页源代码中的关键词,搜索测试文章中的「四处趴趴走」作者关键词可以看到有四个匹配结果。那么要选择哪个取它的值呢?基本原则:谁易得就取谁。

看到图中蓝色高亮的 HTML 代码,它的开头是 <meta 是不是有一种似曾相识的感觉?它就是刚才介绍 HTML 基本结构时提到的网页元数据标签。

既然 <meta> 是属于网页的基本标签,大概可以猜测它也和 doucument.body 一样有相应的方法可以直接获取到标签值,查阅 Web API 接口参考文档| MDN 可知可以通过以下方法获取标签值:

document.getElementsByTagName('META')

在控制台输入这个方法可以看到控制台输出了一个 HTMLCollection,其中包含了 22 个 <meta> 标签。

需要的作者名字在第 8 个,如果你有一些的编程经验,很容易就可以猜想到只要在方法后面添加一个索引号即可获得指定 <meta> 标签的 HTML 代码,所以在控制台接着输入:document.getElementsByTagName('META')[8],可以看到这次返回的结果就只有单独的一个作者元数据标签了。

现在还差最后⼀步,也是最简单的⼀步。因为这⾥需要的不是元数据标签,⽽是作者名字,所以只需要在后面加上 .content 即可获得到相对应的作者名字。举一反三也可以很容易地猜到如果在后面加上 .name 会获得 author 文本。

截屏2021-04-06 上午7.13.48

获取文章发布公众号名字

获取到了文章作者名字之后就轮到文章发布公众号名字了,按照上面的思路你可能也会想到在 <meta> 标签中找到公众号名字并使用 .content 获取文本内容,但是实际去找了一遍却发现 <meta> 标签中是没有文章发布公众号名字的。那么就重新开始搜索网页中「少数派」这个关键词,可以看到依旧有四个搜索结果。

把四个搜索结果浏览一遍过去,最后一个搜索结果引起了我的兴趣,看到 var nickname = "少数派"; 而且它又是在 <script> 标签内部,可以大胆猜测它是一个全局变量,只要调用了这个变量就能得到文章发布公众号名字。在控制台输入 nickname,非常顺利地获取到了文章发布的公众号名字:「少数派」三个字,至此两个关键信息的来源解决完毕。

添加作者和公众号到标题

现在我们已经知道可以 document.body.innerText 很方便地获取到文章内容了,那么如何将刚刚获得到的这两个关键信息插入文章标题呢?

document.body.innerText 获得到的是整篇文章的全部内容,如果要单独修改首行标题就需要将首行「拆」出来进行处理。在 JavaScript 中提供了两个用于拆分和合并的方法:split()join(),而文章每行之间是使用换行(\n)进行分隔的,所以就可以很容易地构造出如下代码:

content = document.body.innerText;
content = content.split('\n');
content[0] += ' ' + document.getElementsByTagName('META')[8].content + ' ' + nickname;
content = content.join('\n');

首先将 document.body.innerText 赋值给一个名字较短的 content 变量,方便后续操作,然后以换行符(\n)为标记进行拆分文本。

content[0] += ' ' + document.getElementsByTagName('META')[8].content + ' ' + nickname;
等价于
content[0] = content[0] + ' ' + document.getElementsByTagName('META')[8].content + ' ' + nickname;

标题毫无疑问是在首行的,所以也就是对应着 content[0],将 content[0] 重新赋值在后面依次加上作者名字和公众号名字以及三者之间用于分隔的空格。最后将拆分修改好了的文本使用 join() 按照换行符(\n)进行合并还原,这个功能就实现了。
 

文章尾部带上原始链接

文章尾部带上原始链接这个操作是比较好理解的,因为 Drafts 仅支持纯文本是无法将图片一并粘贴进来的,所以在不可缺少配图的少数文章中,可以通过底部这个原始链接打开原始网页并将图片手动复制粘贴到 Bear 中。但是好在这样需要配图进行说明的文章非常非常地少,不会占用多少时间,一般是读了十来篇才会有一篇文章必须要添加配图,而每天最多也就读二十多篇文章。

既然要添加原始链接,那么使用 Markdown 格式的链接就再合适不过了。思路就是在调用 copyToClipboard() 函数的时候在后面追加一个 Markdown 格式的链接一并复制即可。

Markdown 链接需要两个参数:网页标题和网页链接。还记得刚开始介绍的 <title> 标签吗?和 <body> 标签一样可以通过 document.title 获取到标题的文本值。

截屏2021-04-06 上午8.49.45

JavaScript 提供了一个名为 window 的类可以获取到网页窗口中的参数,接下来就是需要获取网页链接了,如下图所示通过 window.location 即可获取网页地址的所有参数。

截屏2021-04-06 上午8.51.52

但是需要的只有 href 参数所对应的 URL 地址,所以需要在后面加上 .href 即可。

现在两个参数来源同样也解决完成了,接下来就是构造 markdown 链接格式,代码如下

copyToClipboard(content + "\n" + '[' + document.title.trim() + '](' + window.location.href + ')');

content 就是刚刚重新拼接起来的文章内容,加一个换行符之后在新的一行构造出了一个 markdown 链接共同拷贝到剪切板。

删除微信底部文章推荐

在微信公众号底部会有一个推荐阅读,微信会根据你当前阅读的文章类型推荐相似的文章给你,这些文本内容同样会被复制粘贴到 Drafts 中,但是对于实际使用需求来说这是不需要的,所以需要将它删除掉。

由于底部的推荐文章同样属于文章文字内容的一部分,所以需要从 content 入手,可以看到下图红色框框出的「喜欢此内容的人还喜欢」是固定的文本也是推荐文章的开头文本,只需要将从「喜欢此内容的人还喜欢」到底部的文字全部删除即可,更新 content 变量赋值代码如下:

content = document.body.innerText.replace(/(推荐阅读|喜欢此内容的人还喜欢)(.*\n)+/g, '').replace(/.*阅读原文.*/g,'').replace(/[\r\n]{3,}/g, '\n\n');

可以看出这是在 document.body.innerText 获取到文章内容之后添加了三个 replace 方法,它们的功能依次是:删除从「推荐阅读」或「喜欢此内容的人还喜欢」到文章最后的全部内容,删除阅读原文的行,将三个以上的换行替换为两个换行。

域名条件判断

上面编写的代码是仅适用于微信公众号文章的,对于其他网站的文章可能就会失效,所以需要对代码的运行条件做一下判断。还记得刚刚 window.location 返回了的几个参数吗?其中包含了一个名为 host 的参数,可以获取到当前网页的主机名,如下图所示是调用 window.location.host 方法之后返回的结果。


将前面的拆分、添加作者和公众号的代码合并放到判断语句的代码块里,得到下面的代码:

if (window.location.host == 'mp.weixin.qq.com'){
  content = document.body.innerText.replace(/(推荐阅读|喜欢此内容的人还喜欢)(.*\n)+/g, '').replace(/.*阅读原文.*/g,'').replace(/[\r\n]{3,}/g, '\n\n');
  content = content.split('\n');
  content[0] += ' ' + document.getElementsByTagName('META')[8].content + ' ' + nickname;
  content = content.join('\n');
}

升级版 Bookmarklet 完整代码

javascript: (function() {
    function copyToClipboard(text) {
       if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
            var textarea = document.createElement("textarea");
            textarea.textContent = text;
            textarea.style.position = "fixed";
            document.body.appendChild(textarea);
            textarea.select();
            try {
                return document.execCommand("copy");
            } catch(ex) {
                console.warn("Copy to clipboar failed.", ex);
                return false;
            } finally {
                document.body.removeChild(textarea);
            }
        }
    }
    if (window.location.host == 'mp.weixin.qq.com'){
        content = document.body.innerText.replace(/(推荐阅读|喜欢此内容的人还喜欢)(.*\n)+/g, '').replace(/.*阅读原文.*/g,'').replace(/[\r\n]{3,}/g, '\n\n');
        content = content.split('\n');
        content[0] += ' ' + document.getElementsByTagName('META')[8].content + ' ' + nickname;
        content = content.join('\n');
    }
    copyToClipboard(content + "\n" + '[' + document.title.trim() + '](' + window.location.href + ')');
    url = 'drafts5://x-callback-url/runAction?action=paste';
    window.open(url,'_self');
})();

总结与扩展创新

到此小书签摘抄微信文章的 Bookmarklet 功能已经全部实现了,文中使用 Bookmarklet 在网页和软件之间,通过 URL Scheme 和 Clipboard 搭建起了桥梁,让两者得以复制粘贴文本。但是 Bookmarklet、URL Scheme 和 Clipboard 这三者的组合玩法,远远不止这篇文章实现的这个功能,故借本文抛砖引玉,希望少数派上的其他作者可以借鉴本文的思路构建出更多实用有趣的 Bookmarklet。

本文中的所有代码都可以在 Apple-Automation/JavaScript Bookmarklet 中找到,如果方便希望能帮我 star 一下,如果有任何需求或者 bug 也可以通过 issue 报给我。

参考文章

HTML 文档详解
HTML 元素参考
How To Copy to Clipboard
JS Copy Clipboard demo 
How do I copy to the clipboard in JavaScript
Bookmarklet to copy current page title and url in Markdown format to clipboard, like title