aardio 文档
aardio 范例: WebView2 - Readability 网页阅读模式提取正文、清洗、转为 Markdown
用法参考
import win.ui;
/*DSG{{*/
var winform = win.form(text="WebView2 - Readability 网页阅读模式提取正文、清洗、转为 Markdown";right=966;bottom=622)
winform.add(
btnExtract={cls="button";text="提取正文 / 复制 Markdown";left=758;top=6;right=950;bottom=36;dr=1;dt=1;z=3};
btnGo={cls="button";text="加载网址";left=648;top=6;right=748;bottom=36;dr=1;dt=1;z=2};
custom={cls="custom";left=0;top=45;right=966;bottom=622;db=1;dl=1;dr=1;dt=1;z=4};
editUrl={cls="edit";left=12;top=10;right=641;bottom=34;dl=1;dr=1;dt=1;edge=1;multiline=1;z=1}
)
/*}}*/
import web.view;
// 使用 custom 控件作为宿主窗口(方便我们在顶部保留输入框和按钮)
var wb = web.view(winform.custom);
/*
通过 wb.export 将 aardio 函数导出为 JavaScript 全局函数。
提取后的 JS 对象会自动转换为 aardio 中的表(table)。
*/
wb.export({
saveCleanData = function(article){
if( !article || !article.content ){
winform.msgbox("提取失败,此页面可能没有标准的文章正文格式。");
return true;
}
// 容错处理,防止对应字段为 null
var title = article.title : "未知标题";
var byline = article.byline : "";
import web.turndown;
var turndownService = web.turndown( codeBlockStyle = "fenced" );
turndownService.remove('script');
turndownService.remove('style');
//启用 gfm(GitHub Flavored Markdown)插件。
turndownService.useGfm()
// 添加自定义规则处理带类名的代码块
turndownService.addRule('codeBlock', "{
filter: function(node) {
return node.nodeName === 'PRE' && node.classList.contains('code');
},
replacement: function(content, node) {
var language = node.classList.item(1) || '';
language = language.replace(/^language-/, '');
return '```' + language + '\n' + content.trim() + '\n```';
}
}");
//用法参考: https://github.com/mixmark-io/turndown
var md = turndownService.turndown(
article.content
);
import string.markdown;
var content = string.markdown().render(md);
import win.clip;
win.clip.write(md)
// 构造干净的阅读模式 HTML(加入一些优美的排版 CSS)
var html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>` + title + `</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
line-height: 1.8;
color: #333;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #f4f5f7;
}
article {
background: #fff;
padding: 40px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}
h1 { text-align: center; color: #222; font-size: 2em; margin-bottom: 0.5em; }
.byline { text-align: center; color: #888; font-size: 0.9em; margin-bottom: 30px; }
img { max-width: 100%; height: auto; display: block; margin: 20px auto; border-radius: 4px; }
p { margin-bottom: 1.2em; font-size: 1.1em; }
a { color: #1a73e8; text-decoration: none; }
a:hover { text-decoration: underline; }
pre, code { background: #f1f3f5; padding: 4px 8px; border-radius: 4px; font-family: Consolas, monospace; }
pre { padding: 15px; overflow-x: auto; }
</style>
</head>
<body>
<article>
<h1>` + title + `</h1>
<div class="byline">` + byline + `</div>
` + content + `
</article>
</body>
</html>
`;
/*
被 JS 回调的 aardio 函数中应避免进行阻塞调用。
这里使用 setTimeout 异步更新 WebView 内容。
*/
winform.setTimeout(
function(){
wb.html = html;
}
);
return true; // 务必返回非 null 值
}
})
// 加载网址事件
winform.btnGo.oncommand = function(id,event){
var url = winform.editUrl.text;
if(#url) wb.go(url);
}
// 提取正文事件
winform.btnExtract.oncommand = function(id,event){
winform.btnExtract.disabled = true;
import inet.http;
// 1. 获取 Readability.js 的代码文本,注意 inet.http.get 是创建新线程下载
var readabilityJs = inet.http.get("https://lib.baomitu.com/readability/0.6.0/Readability.min.js");
if(!readabilityJs){
winform.msgbox("无法下载 Readability.js 库,请检查网络!");
winform.btnExtract.disabled = false;
return;
}
// 2. 拼接我们自己的提取执行代码
var script = readabilityJs + `
;(() => {
try {
// Readability 库在解析时会破坏原有的 DOM 结构,因此必须传入 document 的深度克隆
let documentClone = document.cloneNode(true);
let reader = new Readability(documentClone);
let article = reader.parse();
// 调用 aardio 导出的 saveCleanData 函数,把提取到的 JSON 抛给 aardio
window.saveCleanData(article);
} catch(e) {
window.saveCleanData(null);
}
})();
`;
//这比在页面内创建 <script src="..."> 标签更稳定,无视目标网站的 CSP 拦截。
wb.doScript(script);
winform.btnExtract.disabled = false;
}
// 监听导航事件,用户在网页内点击跳转时自动同步网址栏
wb.onDocumentInit = function(url) {
winform.editUrl.text = url;
}
// 启动时自动加载预设的默认网址
winform.btnGo.oncommand();
winform.show();
win.loopMessage();
Markdown 格式