extract

package
v1.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package extract は、HTMLコンテンツから本文テキストを高精度に抽出します。

取得(HTTP アクセス)はこのパッケージの責務ではありません。呼び出し側が用意した io.Reader を解析するだけなので、HTTP でもファイルでもテスト用の文字列でも同じ経路です。

本文抽出のルール

「記事本文だけを残す」ことを目的にしたヒューリスティックで、次の順に処理します。

0. 文字コードを判定する。BOM → Content-Type の charset → <meta charset> → 本文のバイト列、の順に判定して UTF-8 に変換します。パーサは入力を UTF-8 とみなすため、 これが無いと非 UTF-8 のページが丸ごと文字化けします。Content-Type ヘッダーが 手元にあるなら TextWithContentType に渡してください。

1. ノイズを落とす。script、style、form、nav、aside、noscript、template、 [hidden]、[aria-hidden="true"]、および広告・SNS・コメント欄まわりのクラス (.related-posts、.social-share、.comments、.ad-banner、.advertisement)を ページ全体から除去します。noscript / template はパーサからは中身がただの テキストに見えるため、落とさないと囲っている段落の本文に混ざります。

2. 本文の範囲を決める。article、main、div[role='main']、#main、#content、 .post-content、.article-body、.entry-content、.markdown-body、.readme に 最初に一致した要素を本文とします。見つからない場合はページ全体を本文とみなし、 そのときだけ header / footer / .sidebar も落とします(記事の内側の header は 見出しを、footer は署名を含むことがあるため、常に落とすと本文が欠けます)。

3. ブロック要素を順に拾う。p、h1〜h6、li、dt、dd、figcaption、blockquote、 table、pre を DOM の出現順に走査します。入れ子(<li><p>…</p></li> など)は 一度だけ出力され、表の中身は表の行としてだけ出ます。<br> は空白として扱います。 出力の形は次のとおりです。

  • title — 「【記事タイトル】 」を付けて先頭に
  • h1〜h6 — 「## 」を付ける(MinHeadingLength 文字以上のもの)
  • p, blockquote — MinParagraphLength 文字以上のものだけ
  • li, dt, dd, figcaption — 長さを問わず出力(短くても項目として意味を持つため)
  • table — 「【表題】 」付きキャプションと「セル | セル」の行。セルの中は 長さを問わず平坦化し、空の行は出力しない
  • pre — コードフェンスで囲む

しきい値はバイト数ではなく文字数で測ります。len() だと日本語は 1 文字 3 バイトで しきい値が実質 1/3 になり、ナビゲーションの断片が本文として残ります。

Index

Examples

Constants

View Source
const (
	// MinParagraphLength は、本文として採用する段落の最小文字数(バイト数ではない)です。
	MinParagraphLength = 20
	// MinHeadingLength は、見出しとして採用する最小文字数です。「概要」のような 2 文字の見出しを残します。
	MinHeadingLength = 2
)

Variables

This section is empty.

Functions

func Text

func Text(ctx context.Context, r io.Reader) (text string, hasBodyFound bool, err error)

Text は取得済みのHTMLコンテンツから整形されたテキストを抽出します。

第2戻り値は本文が見つかったかどうかです。タイトルしか取れなかった場合は テキストを返しつつ false になります(エラーではありません)。

Example
package main

import (
	"context"
	"fmt"
	"strings"

	"github.com/shouni/go-web-reader/extract"
)

func main() {
	html := `<html><head><title>Example</title></head><body>
<nav><a href="/">Home</a></nav>
<article>
  <h1>Heading</h1>
  <p>This paragraph is long enough to be treated as body text by the extractor.</p>
</article>
</body></html>`

	text, hasBody, err := extract.Text(context.Background(), strings.NewReader(html))
	if err != nil {
		panic(err)
	}
	fmt.Println(hasBody)
	fmt.Println(text)
}
Output:
true
【記事タイトル】 Example

## Heading

This paragraph is long enough to be treated as body text by the extractor.

func TextWithContentType added in v1.4.0

func TextWithContentType(ctx context.Context, r io.Reader, contentType string) (text string, hasBodyFound bool, err error)

TextWithContentType は、Content-Type ヘッダーの値を添えて Text します。

文字コードはヘッダーの charset が <meta charset> より優先されます。<meta> で 宣言しない Shift_JIS / EUC-JP のページはヘッダーだけが手がかりなので、手元に あるなら渡してください。contentType が空なら Text と同じです。

Types

type Engine

type Engine struct{}

Engine は状態を持たない抽出エンジンです。ゼロ値のまま使えます。 中身は Text と同じで、インターフェース値として渡したい呼び出し側のための型です。

func (Engine) Extract

func (Engine) Extract(ctx context.Context, r io.Reader) (string, bool, error)

Extract は取得済みのHTMLコンテンツから整形されたテキストを抽出します。

func (Engine) ExtractWithContentType added in v1.4.0

func (Engine) ExtractWithContentType(ctx context.Context, r io.Reader, contentType string) (string, bool, error)

ExtractWithContentType は Content-Type ヘッダーを添えて Extract します。 文字コードの判定にヘッダーの charset を使える分だけ Extract より正確です。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL