为了更舒服的阅读外文,我写了个小玩意儿起源 最近发现一个外文的周刊质量还挺不错的,值得每周花些时间阅读。网址为:Web
起源
最近发现一个外文的周刊质量还挺不错的,值得每周花些时间阅读。网址为:Web Tools Weekly。
不过原网站的排版狭窄,而且也有一些广告模块,加上又是英文的,虽然可以借助工具翻译,但毕竟阅读体验不是很好。所以想着能不能将其内容提取出来,整理成通用的markdown格式,然后翻译成中文,方便自己阅读。顺便还能存个档,以后查阅也方便。
说干就干,所以就有了这个项目。这个项目的功能包含以下几个方面:
- 提取文章内容,转换成markdown格式
- 翻译文章内容,并尽可能保留原文的格式
- 存档,分别存储原文和翻译后的文章
效果预览
首先一键运行脚本。成功后的输入如下:
这是转换后的原文内容:
再来看看翻译后的内容:
可以看到,翻译后的内容保留了原文的格式,包括标题、链接等。这样就可以保证翻译后的内容和原文的对应关系。整体的翻译效果也还不错,虽然有些地方翻译的不够准确,需要人工校对一下,但总体来说还是可以接受的。
而这整个过程,只需要一键运行脚本,等待大概2分钟,就可以完成。这样就大大提高了效率,也方便了阅读。
接下来,我们来看看这个项目的具体实现。
开发重点
文章内容提取
提取文章内容,转换成markdown格式,是整个项目的核心功能。这里使用了turndown
库来解析网页内容,提取出文章内容。
turnDown.js是一个用于将HTML转换为Markdown的JavaScript库。它是一个轻量级的库,可以在浏览器和Node.js环境中使用。它支持HTML5,可以处理复杂的HTML和CSS。
它内置了一些默认的规则,可以将HTML转换为Markdown。但是,如果需要,还可以自定义规则,以满足特定的需求。
自定义规则
在这里,我们需要自定义一些规则,以满足我们的需求。比如,我们需要去除一些不必要的内容,比如广告模块,页脚等。我们还需要改写一些特定的内容,比如代码块。
这里给几个示例:
- 去除广告模块
turndownService.remove((node) => {
return /xpost/.test(node.className);
});
- 改写代码块
turndownService.addRule("codeArea", {
filter: (node) => {
return node.style.backgroundColor === "#272727";
},
replacement: function (content) {
if (content.includes("```")) return content;
return "```\n" + content + "\n```";
},
});
文章翻译
翻译文章内容,是整个项目的另一个核心功能。这里使用openai的API来实现翻译功能。
这里需要注意的一点是,文章整体的内容可能很多,如果一下子全部翻译,可能会导致超出API的token限制。所以这里需要将文章内容切分成多个部分,然后分别翻译,最后再合并。
内容切分与合并
首先,将文章按照换行符切分,然后指定需要合并的行数,将其合并成一个段落。这样就可以保证每个段落的内容不会超出API的token限制。
主要逻辑如下:
function mergeLines(fixedMarkdown) {
const mergedMarkdown = []
fixedMarkdown.split("\n").forEach((line, index) => {
if (index % mergeLine === 0) {
mergedMarkdown.push(line)
} else {
mergedMarkdown[mergedMarkdown.length - 1] += line+'\n'
}
})
return mergedMarkdown
}
存档
存档是整个项目的最后一个功能。这里需要将原文和翻译后的文章内容分别存储到不同的文件中。以便以后查阅,也可以作为自己的创作发布。
大致代码如下:
async function main() {
const fileName = url.split("/").pop();
const { fixedMarkdown: mdContent, title } = await extract(url);
console.log("提取成功!");
fs.writeFileSync(
path.join(__dirname, "archive", `${fileName}.md`),
mdContent
);
console.log("原文写入成功!");
const translatedContent = await translate(mdContent);
console.log("翻译成功!");
const extraContent = `\n\n文章翻译自:[${title}](${url}) \n\n`;
const finalContent = translatedContent + extraContent;
fs.writeFileSync(
path.join(__dirname, "archive", "cn", `${fileName}.cn.md`),
finalContent
);
console.log("译文写入成功!");
}
最后
项目里的自定义规则是针对Web Tools Weekly的,如果想要进行其他外文网站的内容提取和翻译,只需要修改自定义规则即可。其他逻辑几乎都是通用的。
上述代码只是整个项目的一个简单示例,实际项目中还有很多细节需要处理。如需查看完整代码,可以查看我的github仓库:web-tools-weekly-cn
转载自:https://juejin.cn/post/7362847673773244425