@web-readable/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +181 -0
- package/index.d.ts +0 -0
- package/index.js +11 -0
- package/package.json +50 -0
- package/web-readable.node +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# web-readable
|
|
2
|
+
|
|
3
|
+
`web-readable` は、Web ページから本文本体を抽出して Markdown に変換する Rust ライブラリです。
|
|
4
|
+
現時点では以下が実装済みです。
|
|
5
|
+
|
|
6
|
+
- `html5ever` による HTML 解析
|
|
7
|
+
- HTML5 のセマンティクスを重視したスコアリング抽出
|
|
8
|
+
- `main` / `article` / `section` などを優先する候補選定
|
|
9
|
+
- 低品質なナビゲーション・サイドバー・リンク集の抑制
|
|
10
|
+
- CommonMark / GFM 系の Markdown への変換サブセット
|
|
11
|
+
- MathML から TeX への変換
|
|
12
|
+
- `chromiumoxide` を使った動的取得(`dynamic` feature)
|
|
13
|
+
- 既存 CDP endpoint への接続によるレンダリング HTML 取得
|
|
14
|
+
- Lightpanda endpoint 検出時の `lightpanda fetch` フォールバックによる安定取得
|
|
15
|
+
|
|
16
|
+
## Node.js / npm
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @web-readable/core
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
const { extract, extractToMarkdown, htmlFragmentToMarkdown } = require('@web-readable/core')
|
|
24
|
+
|
|
25
|
+
const article = extract('<main><article><h1>タイトル</h1><p>本文です。</p></article></main>')
|
|
26
|
+
console.log(article.text_content)
|
|
27
|
+
console.log(extractToMarkdown('<article><p>Hello <strong>world</strong></p></article>'))
|
|
28
|
+
console.log(htmlFragmentToMarkdown('<p>Hello <strong>world</strong></p>'))
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 現在の公開API
|
|
32
|
+
|
|
33
|
+
- `extract(html)`
|
|
34
|
+
静的 HTML を抽出
|
|
35
|
+
- `extract_with_options(html, &ExtractOptions)`
|
|
36
|
+
オプション付きで静的 HTML を抽出
|
|
37
|
+
- `html_fragment_to_markdown(html)`
|
|
38
|
+
HTML フラグメントを Markdown に変換
|
|
39
|
+
- `html_fragment_to_markdown_with_options(html, &MarkdownOptions)`
|
|
40
|
+
埋め込みカードを URL に展開しつつ Markdown に変換
|
|
41
|
+
- `extract_to_markdown(html)` / `extract_to_markdown_with_options(html, &ExtractOptions)`
|
|
42
|
+
抽出結果を Markdown で取得
|
|
43
|
+
- `extract_to_markdown_with_markdown_options(html, &ExtractOptions, &MarkdownOptions)`
|
|
44
|
+
抽出と Markdown 変換の両方にオプションを指定
|
|
45
|
+
- `extract_from_url(url, &DynamicOptions, &ExtractOptions)`
|
|
46
|
+
CDP 経由で取得したページを抽出(`dynamic` feature 必須、`merge_paginated_content` で次ページ統合)
|
|
47
|
+
- `extract_to_markdown_from_url(url, &DynamicOptions, &ExtractOptions)`
|
|
48
|
+
CDP 経由で取得したページを Markdown で取得(`dynamic` feature 必須)
|
|
49
|
+
- `extract_to_markdown_from_url_with_markdown_options(url, &DynamicOptions, &ExtractOptions, &MarkdownOptions)`
|
|
50
|
+
CDP 取得 + Markdown 埋め込み展開
|
|
51
|
+
|
|
52
|
+
返却値は `ExtractedContent` で、主に以下を含みます。
|
|
53
|
+
|
|
54
|
+
- `title`
|
|
55
|
+
- `content_html`
|
|
56
|
+
- `text_content`
|
|
57
|
+
- `length`
|
|
58
|
+
- `score`
|
|
59
|
+
- `metadata`(`byline`, `excerpt`, `site_name`, `lang`, `published_time`)
|
|
60
|
+
|
|
61
|
+
## インストール
|
|
62
|
+
|
|
63
|
+
```toml
|
|
64
|
+
[dependencies]
|
|
65
|
+
web_readable = "0.1.0"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
動的取得を使う場合:
|
|
69
|
+
|
|
70
|
+
```toml
|
|
71
|
+
[dependencies]
|
|
72
|
+
web_readable = { version = "0.1.0", features = ["dynamic"] }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 静的HTMLの抽出
|
|
76
|
+
|
|
77
|
+
```rust
|
|
78
|
+
use web_readable::extract;
|
|
79
|
+
|
|
80
|
+
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
81
|
+
let html = r#"
|
|
82
|
+
<html>
|
|
83
|
+
<body>
|
|
84
|
+
<main>
|
|
85
|
+
<article>
|
|
86
|
+
<h1>記事タイトル</h1>
|
|
87
|
+
<p>本文です。</p>
|
|
88
|
+
</article>
|
|
89
|
+
</main>
|
|
90
|
+
</body>
|
|
91
|
+
</html>
|
|
92
|
+
"#;
|
|
93
|
+
|
|
94
|
+
let article = extract(html)?;
|
|
95
|
+
println!("{}", article.text_content);
|
|
96
|
+
Ok(())
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## オプション付きの抽出
|
|
101
|
+
|
|
102
|
+
```rust
|
|
103
|
+
use web_readable::{extract_with_options, ExtractOptions};
|
|
104
|
+
|
|
105
|
+
let options = ExtractOptions {
|
|
106
|
+
include_images: true,
|
|
107
|
+
merge_paginated_content: true,
|
|
108
|
+
..ExtractOptions::default()
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
let article = extract_with_options(html, &options)?;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```rust
|
|
115
|
+
use web_readable::{html_fragment_to_markdown_with_options, MarkdownOptions};
|
|
116
|
+
|
|
117
|
+
let markdown = html_fragment_to_markdown_with_options(
|
|
118
|
+
html,
|
|
119
|
+
&MarkdownOptions {
|
|
120
|
+
decode_embeds_as_urls: true,
|
|
121
|
+
},
|
|
122
|
+
);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 動的ページの抽出
|
|
126
|
+
|
|
127
|
+
このモードは、すでに起動済みの Chromium / Chrome の CDP endpoint に接続します。
|
|
128
|
+
Lightpanda endpoint を使う場合は自動で `lightpanda fetch` に切り替わります。
|
|
129
|
+
|
|
130
|
+
```rust
|
|
131
|
+
use web_readable::{extract_from_url, DynamicOptions, ExtractOptions};
|
|
132
|
+
|
|
133
|
+
#[tokio::main(flavor = "current_thread")]
|
|
134
|
+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
135
|
+
let dynamic = DynamicOptions::new("ws://127.0.0.1:9222/devtools/browser/<id>");
|
|
136
|
+
let article = extract_from_url(
|
|
137
|
+
"https://example.com/article",
|
|
138
|
+
&dynamic,
|
|
139
|
+
&ExtractOptions::default(),
|
|
140
|
+
)
|
|
141
|
+
.await?;
|
|
142
|
+
|
|
143
|
+
println!("{}", article.text_content);
|
|
144
|
+
Ok(())
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Lightpanda を使うときは、別プロセスで CDP サーバーを立てます。
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
lightpanda serve --host 127.0.0.1 --port 9222
|
|
152
|
+
cargo run --features dynamic --bin web_readable -- https://example.com 127.0.0.1:9222
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Markdown 変換
|
|
156
|
+
|
|
157
|
+
```rust
|
|
158
|
+
use web_readable::html_fragment_to_markdown;
|
|
159
|
+
|
|
160
|
+
let markdown = html_fragment_to_markdown(r#"<p>Hello <strong>world</strong></p>"#);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## CLI
|
|
164
|
+
|
|
165
|
+
簡易 CLI は `web_readable` バイナリとして用意しています。第一引数に URL、第二引数に CDP endpoint、第三引数に期待 Markdown ファイルを渡せます。
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
cargo run --features dynamic --bin web_readable -- https://example.com 127.0.0.1:9222
|
|
169
|
+
cargo run --features dynamic --bin web_readable -- https://example.com 127.0.0.1:9222 expected.md
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## ルール詳細
|
|
173
|
+
|
|
174
|
+
- [contentRule.md](contentRule.md)
|
|
175
|
+
- [markdownRule.md](markdownRule.md)
|
|
176
|
+
|
|
177
|
+
## 実装メモ
|
|
178
|
+
|
|
179
|
+
- 旧 Readability 実装は参考にしているが、古い class/id 依存のルールはそのまま使っていない
|
|
180
|
+
- スコアリングは HTML5 時代の構造を優先する
|
|
181
|
+
- `dynamic` feature は optional で、通常利用時の依存を軽く保つ
|
package/index.d.ts
ADDED
|
File without changes
|
package/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const names = {
|
|
2
|
+
'darwin-arm64': 'web-readable.darwin-arm64.node',
|
|
3
|
+
'darwin-x64': 'web-readable.darwin-x64.node',
|
|
4
|
+
'linux-arm64': 'web-readable.linux-arm64-gnu.node',
|
|
5
|
+
'linux-x64': 'web-readable.linux-x64-gnu.node',
|
|
6
|
+
'win32-arm64': 'web-readable.win32-arm64-msvc.node',
|
|
7
|
+
'win32-x64': 'web-readable.win32-x64-msvc.node'
|
|
8
|
+
}
|
|
9
|
+
const binary = names[`${process.platform}-${process.arch}`]
|
|
10
|
+
if (!binary) throw new Error(`Unsupported platform: ${process.platform}-${process.arch}`)
|
|
11
|
+
module.exports = require(`./${binary}`)
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@web-readable/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Fast article extraction and HTML-to-Markdown conversion powered by Rust.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": "https://github.com/taisan11/web-readable",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"main": "index.js",
|
|
11
|
+
"types": "index.d.ts",
|
|
12
|
+
"packageManager": "bun@1.3.14",
|
|
13
|
+
"files": [
|
|
14
|
+
"index.js",
|
|
15
|
+
"index.d.ts",
|
|
16
|
+
"*.node"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">= 16"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "napi build --release",
|
|
23
|
+
"test": "cargo test",
|
|
24
|
+
"prepublishOnly": "napi prepublish -t npm"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@napi-rs/cli": "^3.7.2"
|
|
28
|
+
},
|
|
29
|
+
"napi": {
|
|
30
|
+
"binaryName": "web-readable",
|
|
31
|
+
"targets": [
|
|
32
|
+
"x86_64-unknown-linux-gnu",
|
|
33
|
+
"x86_64-unknown-linux-musl",
|
|
34
|
+
"aarch64-unknown-linux-gnu",
|
|
35
|
+
"aarch64-apple-darwin",
|
|
36
|
+
"x86_64-apple-darwin",
|
|
37
|
+
"x86_64-pc-windows-msvc",
|
|
38
|
+
"aarch64-pc-windows-msvc"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"optionalDependencies": {
|
|
42
|
+
"@web-readable/core-linux-x64-gnu": "0.1.0",
|
|
43
|
+
"@web-readable/core-linux-x64-musl": "0.1.0",
|
|
44
|
+
"@web-readable/core-linux-arm64-gnu": "0.1.0",
|
|
45
|
+
"@web-readable/core-darwin-arm64": "0.1.0",
|
|
46
|
+
"@web-readable/core-darwin-x64": "0.1.0",
|
|
47
|
+
"@web-readable/core-win32-x64-msvc": "0.1.0",
|
|
48
|
+
"@web-readable/core-win32-arm64-msvc": "0.1.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
Binary file
|