3 个不稳定版本
0.2.0 | 2020年9月23日 |
---|---|
0.1.1 | 2020年2月16日 |
0.1.0 | 2020年2月11日 |
#1819 in 网页编程
171 每月下载量
用于 5 个 crates (4 直接)
32KB
612 行
easy-scraper
专注于易用的 HTML 提取库。
在这个库中,匹配模式被描述为 HTML DOM 树。您可以编写直观的模式并轻松提取所需内容。
示例
use easy_scraper::Pattern;
let doc = r#"
<!DOCTYPE html>
<html lang="en">
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
</html>
"#;
let pat = Pattern::new(r#"
<ul>
<li>{{foo}}</li>
</ul>
"#).unwrap();
let ms = pat.matches(doc);
assert_eq!(ms.len(), 3);
assert_eq!(ms[0]["foo"], "1");
assert_eq!(ms[1]["foo"], "2");
assert_eq!(ms[2]["foo"], "3");
语法
DOM 树
DOM 树是有效的模式。您可以在 DOM 树中编写占位符。
<ul>
<li>{{foo}}</li>
</ul>
如果模式是文档的子集,则匹配模式。
如果文档是
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
这些树是它的子集。
<ul>
<li>1</li>
</ul>
<ul>
<li>2</li>
</ul>
<ul>
<li>3</li>
</ul>
因此,匹配结果是
[
{ "foo": "1" },
{ "foo": "2" },
{ "foo": "3" },
]
子节点
由于子集规则,子节点与任何后代匹配。
例如,这个模式
<div>
<li>{{id}}</li>
</div>
与这个文档匹配。
<div>
<ul>
<li>1</li>
</ul>
</div>
兄弟节点
为了避免无用的匹配,兄弟节点仅限于匹配同一父节点的连续子节点。
例如,这个模式
<ul>
<li>{{foo}}</li>
<li>{{bar}}</li>
</ul>
不匹配此文档。
<ul>
<li>123</li>
<div>
<li>456</li>
</div>
</ul>
对于此文档,
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
匹配结果是
[
{ "foo": "1", "bar": "2" },
{ "foo": "2", "bar": "3" },
]
{ "foo": 1, "bar": 3 }
不包含,因为没有连续的子节点。
您可以在模式中写入 ...
来指定兄弟节点之间的允许节点。
<ul>
<li>{{foo}}</li>
...
<li>{{bar}}</li>
</ul>
此模式的匹配结果是
[
{ "foo": "1", "bar": "2" },
{ "foo": "1", "bar": "3" },
{ "foo": "2", "bar": "3" },
]
如果您想将兄弟节点作为子序列而不是连续子串进行匹配,您可以使用 subseq
模式。
<table>
<tr><th>AAA</th><td>aaa</td></tr>
<tr><th>BBB</th><td>bbb</td></tr>
<tr><th>CCC</th><td>ccc</td></tr>
<tr><th>DDD</th><td>ddd</td></tr>
<tr><th>EEE</th><td>eee</td></tr>
</table>
对于此文档,
<table subseq>
<tr><th>AAA</th><td>{{a}}</td></tr>
<tr><th>BBB</th><td>{{b}}</td></tr>
<tr><th>DDD</th><td>{{d}}</td></tr>
</table>
此模式匹配。
[
{
"a": "aaa",
"b": "bbb",
"d": "ddd"
}
]
属性
您可以在模式中指定属性。当模式的属性是文档属性的子集时,属性模式匹配。
此模式
<div class="attr1">
{{foo}}
</div>
与此文档匹配。
<div class="attr1 attr2">
Hello
</div>
您还可以在属性中编写占位符。
<a href="{{url}}">{{title}}</a>
此文档的匹配结果是
<a href="https://www.google.com">Google</a>
<a href="https://www.yahoo.com">Yahoo</a>
[
{ "url": "https://www.google.com", "title": "Google" },
{ "url": "https://www.yahoo.com", "title": "Yahoo" },
]
部分文本节点模式
您可以在文本节点中编写任意位置的占位符。
<ul>
<li>A: {{a}}, B: {{b}}</li>
</ul>
此文档的匹配结果是
<ul>
<li>A: 1, B: 2</li>
<li>A: 3, B: 4</li>
<li>A: 5, B: 6</li>
</ul>
[
{ "a": "1", "b": "2" },
{ "a": "3", "b": "4" },
{ "a": "5", "b": "6" },
]
您还可以在属性位置编写占位符。
<ul>
<a href="/users/{{userid}}">{{username}}</a>
</ul>
此文档的匹配结果是
<ul>
<a href="/users/foo">Foo</a>
<a href="/users/bar">Bar</a>
<a href="/users/baz">Baz</a>
</ul>
[
{ "userid": "foo", "username": "Foo" },
{ "userid": "bar", "username": "Bar" },
{ "userid": "baz", "username": "Baz" },
]
整个子树模式
模式 {{var:*}}
与整个子树作为字符串匹配。
<div>{{body:*}}</div>
此文档的匹配结果是
<body>
Hello
<span>hoge</span>
World
</body>
[
{ "body": "Hello<span>hoge</span>World" }
]
空白字符
几乎在所有位置都会忽略空白字符。
限制
- 整个子树模式必须是父节点唯一的元素。
这是有效的
<div>
{{foo:*}}
</div>
有无效的
<div>
hoge {{foo:*}}
</div>
<ul>
<li></li>
{{foo:*}}
<li></li>
<ul>
许可证:MIT
依赖项
~6–12MB
~146K SLoC