Safari 有个阅读模式,可以识别正文内容并重新排版,重新设置样式,让页面简洁,其中最核心的东西是正文内容识别部分。如下图
正文识别算法
正文提取算法主要分以下三种:
- 正文密度
- 遍历页面所有只包含文本节点的 dom 节点。遍历当前 dom 节点,当节点内的文本数量占比整个页面所有的文本数量大于 0.4 则认为是正文区域,否则继续遍及父级节点
- 针对英文页面有很好的效果,对于中文类含有噪音较多的网页会存在识别区域大于正文区域的情况,且针对图片内容等类型网页则无能为力
- Chrome 扩展 just-read 使用该算法,通过 css 解决了识别区域大于正文区域的情况,具体做法是通过 css 隐藏掉 footer 、header、comment、ad 等类名和标签名。虽然可以达到较高的准确率但是会存在误伤正文的情况
- 文本特征
- 识别页面所有的文本区域,根据正文的特征来识别正文。特征如:标签符号的数量,文本长度的峰值变化等特征来识别正文
- 对于图片类内容仍然是无能为力
- Chrome 自带的阅读模式
- 权值计算
- 对于正文特征进行权值计算,使用特征为: 标点符号数量、正文长度、正文链接密度。通过对以上特征的加权计算,对于得分加权到父级节点,并赋予祖父节点一半的权值。最后找出权值最高的 dom 节点就是正文节点
- 该算法需要解析DOM树,因此执行效率稍微慢一些。因为是加权对 dom 赋值计算,针对常规 div 包裹 p 标签类型的网页可以达到 100% 识别率,但是对于不按套路出牌的网页则会存在丢失正文的情况。如:正文使用多个 div 包裹,最后使用一个 div 把这些 div 包起来,这样权值计算之后会识别其中一个 div 导致其他正文丢失
- Safari 的阅读模式。该算法在 safari 进行了更多的优化,识别率更高。原始代码基于大名鼎鼎的 arc90 实验室的 Readability 。该算法已经商业化实现了 firefox ,chrome 插件及 flipboard 。目前火狐浏览器使用的源代码开源了 Readability
Readability 算法
一个简化的 Readability js 实现
可以看看其核心算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
let maybeNode = {
score:0,
};
const nodes = document.body.getElementsByTagName('p');
for(var i = 0, len = nodes.length; i < len; i++){
const node = nodes[i];
let score = 1;
const text = node.innerText;
score += text.split(/:|。|;|,|,|\.|\?|”/).length;
score += Math.min(Math.floor(text.length / 100), 3);
typeof node.score !== 'number' && (node.score = 0);
node.score += score;
node.setAttribute('score', node.score);
node.score > maybeNode.score && (maybeNode = node);
let index = 0;
let tempNode = node.parentElement;
while (tempNode && tempNode.tagName !== 'BODY'){
if(/div|article|section/i.test(tempNode.tagName)){
typeof tempNode.score !== 'number' && (tempNode.score = 0);
tempNode.score += score / (index < 2 ? index + 2 : index * 3);
tempNode.setAttribute('score', tempNode.score);
tempNode.score > maybeNode.score && (maybeNode = tempNode);
if (++index >= 3) {
break;
}
}
tempNode = tempNode.parentElement;
}
}
maybeNode && (maybeNode.style.border = '1px solid red');
Readability golang 实现
go-readability 是照着 Mozilla 开源的 Readability.js 写的,让工作方式、流程基本一致。
go-readability 使用示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package main
import (
"fmt"
"log"
"net/http"
"net/url"
"github.com/go-shiori/go-readability"
)
var (
urls = []string{
"https://golangnote.com/topic/260.html",
}
)
func main() {
for _, u := range urls {
resp, err := http.Get(u)
if err != nil {
log.Fatalf("failed to download %s: %v\n", u, err)
}
defer resp.Body.Close()
ur, _ := url.Parse(u)
article, err := readability.FromReader(resp.Body, ur)
if err != nil {
log.Fatalf("failed to parse %s: %v\n", u, err)
}
fmt.Printf("URL : %s\n", u)
fmt.Printf("Title : %s\n", article.Title)
fmt.Printf("Author : %s\n", article.Byline)
fmt.Printf("Length : %d\n", article.Length)
fmt.Printf("Excerpt : %s\n", article.Excerpt)
fmt.Printf("SiteName: %s\n", article.SiteName)
fmt.Printf("Image : %s\n", article.Image)
fmt.Printf("Favicon : %s\n", article.Favicon)
//fmt.Printf("Content : %s\n", article.Content)
fmt.Printf("TextContent : %s\n", article.TextContent)
fmt.Println()
}
}
输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
URL : https://golangnote.com/topic/260.html
Title : Golang 随机打乱数组/Slice - GolangNote
Author :
Length : 3628
Excerpt : 给定一个数组/列表/Slice,随机打乱顺序
SiteName:
Image :
Favicon : https://golangnote.com/static/favicon.png
TextContent : Jun 19TH, 2019
• Permalink
给定一个数组/列表/Slice,随机打乱顺序
Go: 随机打乱Slice顺
...... 省略正文内容 .....
大体能识别出来。
本文网址: https://golangnote.com/topic/305.html 转摘请注明来源