## Webstemmer

back [English]

- 使いかた
- web クローラ
- レイアウト分析プログラム
- テキスト抽出プログラム
- URLDB操作プログラム
- HTML2TXT ユーティリティ
- バグ
- ライセンス

ダウンロード: `webstemmer-0.6.1.tar.gz` (要Python 2.4以上)

### これなに?

Webstemmer はニュースサイトから記事本文と記事のタイトルをプレインテキスト形式で 自動的に抽出するソフトウェアです。 サイトのトップページの URL さえ与えれば全自動で解析するため、 人手の介入はほとんど必要ありません。 動作原理はこちら。

注意: ニュースサイトのコンテンツは各国の著作権法により保護されています。 著作権のあるコンテンツを許可なく再配布することは禁じられています。 このソフトウェアはニュースサイトのテキストを研究用に分析する目的で 作られたもので、違法なコンテンツ配布を助長するためのものではありません。

ニュースサイトからテキストを取得すると、ふつう本文のほかに、 大量の広告やナビゲーション用のリンクなども混ざってしまいます。 またタイトルについても、すべてのサイトで `<title>` タグで囲まれたものが 記事のタイトルになっているとは限りません。このような HTML を人手で解析して、 正規表現などを使ってここから正しい部分を取ってくるのは面倒です。 また、ニュースサイトによっては何種類もの異なるレイアウトを使っているところがあります。 Webstemmer はこのようなニュースサイトのレイアウトを自動で分析し、 記事本文とタイトルだけをとってこれるようにします (出力例はこちら)。 現在のところ、この方法はメジャーなニュースサイトに対してうまくいっています。 また、これは特定の言語に特化した知識を使っていません。 唯一の知識は意味のある文字とそうでない文字 (句読点など、いわゆる“約物”) の区別です。 そのため、このソフトウェアは日本語、英語どちらのサイトでも動作します。

現在のところ、英語サイトでは、およそ 90% のページから 正しくテキストを抽出できています:

サイト名 | 抽出ページ数/取得ページ数 (一日の平均)
--- | ---
New York Times | 488.8/552.2 (88%)
Newsday | 373.7/454.7 (82%)
Washington Post | 342.6/367.3 (93%)
Boston Globe | 332.9/354.9 (93%)
ABC News | 299.7/344.4 (87%)
BBC | 283.3/337.4 (84%)
Los Angels Times | 263.2/345.5 (76%)
Reuters | 188.2/206.9 (91%)
CBS News | 171.8/190.1 (90%)
Seattle Times | 164.4/185.4 (89%)
NY Daily News | 144.3/147.4 (98%)
International Herald Tribune | 125.5/126.5 (99%)
Channel News Asia | 119.5/126.2 (94%)
CNN | 65.3/73.9 (89%)
Voice of America | 58.3/62.6 (94%)
Independent | 58.1/58.5 (99%)
Financial Times | 55.7/56.6 (98%)
USA Today | 44.5/46.7 (96%)
NY1 | 35.7/37.1 (95%)
1010 Wins | 14.3/16.1 (88%)
計 | 3829.1/4349.2 (88%)

日本語サイトでは、具体的な性能は測定していませんが、 以下のようなサイトで正しく動くことがわかっています:

- アサヒ・コム
- Nikkei NET
- Mainichi INTERACTIVE
- Yomiuri On-line
- IT media
- 東京新聞
- 日刊スポーツ
- 信濃毎日新聞
- livedoor ニュース

### 使いかた

Webstemmer をつかったテキスト抽出は以下のようなステップになります:

1. まず、特定のニュースサイトから種となる HTML ページを多数取得する。
2. 取得したページのレイアウトを学習する。
3. 別の日に、同一のニュースサイトから新しい HTML ページを取得する。
4. 2. で学習した結果をつかって、新しい HTML ページから本文を抽出する。

1. および 2. のステップが必要なのは最初の 1回だけです。 ひとたびサイトのレイアウトを学習してしまえば、 あとはレイアウトが大きく変更されるまで同じ学習結果 (「パターンファイル」と呼ばれます) が使えます。

Webstemmer には 4つのプログラムが含まれています:

- `textcrawler.py` (web クローラ)
- `analyze.py` (レイアウト分析プログラム)
- `extract.py` (テキスト抽出プログラム)
- `urldbutils.py` (URLDB操作プログラム)
- `html2txt.py` (簡単なテキスト抽出)

以前のバージョンの webstemmer は webクローラと レイアウト分析/テキスト抽出プログラムが一体化していましたが、 webstemmer-0.5 からはこれらが分離されました。

#### ステップ 1. 学習するための HTML ページを取得する

あるサイトのレイアウトを学習するときは、 まず最初に「種」となるページをいくつか収集する必要があります。 `textcrawler.py` はそのための簡易クローラです。 このクローラは再帰的にリンクをたどり、ある一定の深さ (デフォルトでは 1 -- つまり、開始したページにある各リンクを 1回だけたどった位置) に 到達するまでのページをすべてダウンロードします。

> (対象となるサイトのページを取得する)

>     $ ./textcrawler.py -o nikkei http://www.nikkei.co.jp/
>     Writing: 'nikkei.200509182149.zip'
>     Making connection: 'www.nikkei.co.jp'...
>     ...

ダウンロードされたページにはタイムスタンプがつけられ、 ひとつの zipファイルにまとめて保存されます。 このアーカイブ中の各ファイル名にはクロールが行われた日時がタイムスタンプとして 自動的に追加されます。この .zip ファイルは、ステップ 2. における レイアウトパターンの学習用としても、ステップ 4. における 実際のテキスト抽出元ページとしても使用することができます。

> (保存された zipファイルの中に含まれている取得ページ一覧を見る)

>     $ zipinfo nikkei.200509182149.zip
>     Archive:  nikkei.200509182149.zip   497470 bytes   105 files
>     -rw----     2.0 fat    55212 b- defN 18-Sep-05 21:57 200509182149/www.nikkei.co.jp/
>     -rw----     2.0 fat     2475 b- defN 18-Sep-05 21:57 200509182149/www.nikkei.co.jp/nikkeiinfo/
>     -rw----     2.0 fat    10194 b- defN 18-Sep-05 21:57 200509182149/www.nikkei.co.jp/privacy/
>     ...

#### ステップ 2. 取得したページのレイアウトパターンを学習する

つぎに、ステップ 1. で得られた .zip ファイルを `analyze.py` (レイアウト分析プログラム) に渡します。 このプログラムは、.zip ファイルに含まれている HTML ファイルをすべて解析し、 学習されたパターンを標準出力に表示します。この標準出力をファイルに リダイレクトすれば、学習したレイアウトのパターンを保存できます:

> (取得したページのレイアウトパターンを学習する)

>     $ ./analyze.py nikkei.200509182149.zip > nikkei.pat
>     Opening: 'nikkei.200509182149.zip'...
>     Added: 1: 200509182149/www.nikkei.co.jp/
>     Added: 2: 200509182149/www.nikkei.co.jp/nikkeiinfo/
>     Added: 3: 200509182149/www.nikkei.co.jp/privacy/
>     Added: 4: 200509182149/www.nikkei.co.jp/ad/mm/
>     ...

マシンの性能にもよりますが、通常 100ページほどのデータを学習する場合、およそ 2〜3分かかります。 これが 1000ページになると、所要時間は 2〜3時間になります。 (所要時間はページ数の2乗に比例しているため、学習するページ数が 2倍になれば学習時間は 約4倍になります。) 新山が使っている Xeon 2GHz のマシンでは 300以上のページを学習するのに 30分ぐらいかかりました。

なお、このパターンはテキスト形式で保存されており、 あとで人手で編集することも可能です (パターンファイルの構造)。

#### ステップ 3. テキスト抽出をおこなうページを取得する

この後、得られたパターンを使ってテキスト抽出を行うために、 もう一度クローラを走らせます。 (もとの学習に使った .zip ファイルそのものからもテキスト抽出はできますが、 ここでは数日後にまったく内容の異なる新たなページから取得すると仮定します。)

> (抽出したい HTML ファイルを取得する)

>     $ ./textcrawler.py -o nikkei http://www.nikkei.co.jp/
>     Writing: 'nikkei.200510291951.zip'
>     Making connection: 'www.nikkei.co.jp'...
>     ...

> (保存された zipファイルの中に含まれている取得ページ一覧を見る)

>     $ zipinfo nikkei.200510291951.zip
>     Archive:  nikkei.200510291951.zip   518951 bytes   103 files
>     -rw----     2.0 fat    56325 b- defN 29-Oct-05 19:51 200510291951/www.nikkei.co.jp/
>     -rw----     2.0 fat     2475 b- defN 29-Oct-05 19:51 200510291951/www.nikkei.co.jp/nikkeiinfo/
>     -rw----     2.0 fat    10194 b- defN 29-Oct-05 19:51 200510291951/www.nikkei.co.jp/privacy/
>     ...

#### ステップ 4. 学習したパターンを使って本文を抽出する

さて、ここまでくれば先に学習したパターンを使って、 新たに取得したページから本文を抽出できます:

> (パターンファイル nikkei.pat を使って本文とタイトルを抽出し、euc-jp で保存する)

>     $ ./extract.py -Ceuc-jp nikkei.pat nikkei.200510271344.zip > nikkei.txt
>     Opening: 'nikkei.200510291951.zip'...

本文とタイトルの情報はプレインテキスト形式で `nikkei.txt` に保存されています。

>     $ cat nikkei.txt
>     !UNMATCHED: 200510291951/www.nikkei.co.jp/            (どのパターンにもマッチしないページ)

>     !UNMATCHED: 200510291951/www.nikkei.co.jp/nikkeiinfo/ (どのパターンにもマッチしないページ)

>     !UNMATCHED: 200510291951/www.nikkei.co.jp/privacy/    (どのパターンにもマッチしないページ)
>     ...

>     !MATCHED: 200510291951/www.nikkei.co.jp/news/retto/20051028c6b2802a28.html  (マッチしたページ)
>     PATTERN: 200509182149/www.nikkei.co.jp/news/retto/20050916c3b1604m16.html   (マッチしたレイアウトパターン名)
>     TITLE: 四国４県の失業率3.8％に改善、有効求人倍率も改善傾向                  (記事の題名)
>     MAIN-7: 総務省が28日に発表した2005年7―9月の四国４県の完全失業率（原数値）は  (本文テキスト)
>             3.8％と前年同期比1.0ポイント低下した。４県労働局が同日発表した9月の
>             有効求人倍率も高知県を除いて前月の水準を上回った。景気の緩やかな
>             回復を背景に、四国でも雇用の改善が進んでいる。
>     ...
>     MAIN-7: ９月の求職者１人当たりの求人割合を示す有効求人倍率（季節調整値）は    (本文テキスト)
>             ４県が前月比0.02ポイント上昇の0.87倍だった。
>     SUB-9: (10/29)四国４県の失業率3.8％に改善、有効求人倍率も改善傾向           (それ以外のテキスト)
>     SUB-9: (10/29)高知大学、市民向け公開講座の音声をネット配信                  (それ以外のテキスト)
>     SUB-9: (10/29)スペースタグ、応用ソフト２社と提携し顧客拡大へ                (それ以外のテキスト)
>     ...
>     SUB-9: (10/21)手芸用品店の小野、京都に初出店・関西で攻勢へ                  (それ以外のテキスト)
>     SUB-9: (10/21)ナイトライド、光取り出し効率２倍の紫外線ＬＥＤ開発            (それ以外のテキスト)
>     SUB-9: (10/21)愛媛県知事、財政構造改革に意欲・月内にも方針                  (それ以外のテキスト)

>     !MATCHED: 200510291951/www.nikkei.co.jp/news/retto/20051028c6b2802p28.html  (マッチしたページ)
>     PATTERN: 200509182149/www.nikkei.co.jp/news/retto/20050916c3b1604m16.html   (マッチしたレイアウトパターン名)
>     ...

それぞれのページは空行で区切られ、各ページの先頭には必ず "`!MATCHED`" または "`!UNMATCHED`" で始まるヘッダと、そのページを示す識別子 (これは .zip アーカイブ中のファイル名です) がついています。 そのページが指定されたパターンのどれにもマッチしない場合はこれで終わりですが、マッチした場合は "`!MATCHED`" のあとに、パターン名を表す "`PATTERN:`" が続き、 そのあとに題名 ("`TITLE`") と 本文テキスト ("`MAIN`") が出力されます。

出力テキストの各行は HTML の改行 (`<p>` または `<br>`) にしたがって 区切られており、 たとえば上の例で "`MAIN`" が複数あるのは本文が いくつかの段落に分かれていることを示しています。 ページ内の各行はかならず "`TITLE:`"、"`MAIN-n:`" あるいは "`SUB-n:`" のように 大文字アルファベットのフィールドで始まっています (上の例では読みやすさのために意図的に改行が入れられています)。 そのため perl や grep などのコマンドで簡単に必要な部分をとりだすことができます。 "`SUB-n:`" と示されている行は、 記事の題名でも本文でもないが、補助的なテキストと判断された部分です (n の値はその部分につけられたスタイルの ID で、これはパターンごとに変わります)。

#### インストール

ダウンロードの項にあるリンクから tar.gz ファイルをダウンロードし、 展開してください。このプログラムを動かすには Python 2.4 以上 が必要です。 プログラム自体はただのスクリプトファイルなので特別なインストールは必要なく、 ただシェルから単に `./analyze.py` や `./extract.py` と タイプすれば ok です。あとはシェルスクリプトを書いて cron に仕掛けるなり何なりしてください。

### `textcrawler.py` (webクローラ)

`textcrawler.py` は特定のサイトを再帰的にクロールし、 テキストファイル (HTMLファイル) のみを集める簡単な webクローラです。 web 全体を対象としたクロールには向いていませんが、中規模程度のサイトから 100〜10000 程度のページを取得するのに向いています。 これは収集した複数のページをひとつの zip ファイルにまとめて保存します。 Mozilla 形式のクッキーファイルや、persistent HTTP接続、gzip圧縮をサポートしています。 対象サイトへの負荷をなるべく減らすために、再帰の深度やクロールする URL のパターンを ユーザが厳密にコントロールできるようになっており、また、URL を データベース (Berkeley DBM) に保存しておくことにより、一度取得した URL を 次回のクロールでは取得しないように設定することもできます。 可能なかぎり persistent 接続や gzip を使用し、`robots.txt` には必ず従います。 なお、HTTP接続は最初に指定したホストにしか行わず、他のサイトに向かうリンクは (そのサーバが同一のIPアドレスをもつ仮想サーバでないかぎり) すべて無視されます。

ほとんどのニュースサイトでは、個々の記事を示す URL は一意です。 したがって、通常、一度取得した URL は二度と取得する必要がありません。 `textcrawler.py` にはこのための機能として `-U`オプション (URLDB の指定) があります。URLDB ファイル名を指定すると、`textcrawler.py` は 一度取得した URL の md5ハッシュ値と、その URL へのリンクを最後に見た時刻を Berkeley DBM 形式のデータベースに記録します (指定されたファイルがない場合は 自動的に作成されます)。ある URL を取得しようとする際、それがすでに URLDB に記録されていれば そのページは保存しないため、これを使うと 2回目以降のクロールの際に必要な実行時間と ネットワーク帯域を大幅に削減することができます。 cron などを使って、クローラを一定時間おきに走らせる場合は、これはとくに有用です。 (ただし URLDB は取得した URL をすべて記録していくため、時間がたつにつれてこのファイルは 大きくなっていきます。大きくなりすぎた URLDB を整理するには `urldbutils.py`コマンドを使ってください。)

取得すべき URL をコントロールする方法として、 `-a` (Accept) と `-j` (reJect) の 2つのオプションが用意されています。 これらには受理すべき (あるいは拒否すべき) URL にマッチする正規表現を指定します。 これらのオプションはコマンドラインで指定された順に判定され、 URL は最初にマッチしたパターンにしたがって受理あるいは拒否されます (どのパターンにもマッチしない場合は、自動的に拒否とみなされます)。 なお、どちらのオプションも指定しない場合は、デフォルトで自動的にトップページの URL を プレフィックスとしてもつ URL をすべて受理し、jpg、gif などの明らかにテキストでない URL を拒否するような設定になっています。(`-a` あるいは `-j` を ひとつでも指定した場合、これらのデフォルトは使われませんので注意してください)

#### 構文

>     $ textcrawler.py -o 出力ファイル名 [オプション] 開始URL ...

必ず出力ファイル名の指定が必要です。このファイル名にはタイムスタンプ (`YYYYMMDDHHMM` の形式) と拡張子 `.zip` が自動的につけられます。 タイムスタンプはこのコマンドが実行された時点の値が入ります。 この値はコマンドラインから `-b` オプションで変更できます。

##### 使用例:

>     (http://www.asahi.com/ を開始ページとして再帰深度 2 でクロールし、結果を asahi.*.zip に保存する。
>         デフォルトの文字コードとして euc-jp を使用する)
>     $ textcrawler.py -o asahi -m2 -c euc-jp http://www.asahi.com/

>     (http://www.boston.com/news/globe/ を開始ページとしてクロールするが、
>         "http://www.boston.com/news/" 以下のページもクロールする。
>         URLDB ファイルとして boston.urldb を使用する)
>     $ textcrawler.py -o boston -U boston.urldb -a'^http://www\.boston\.com/news/' http://www.boston.com/news/globe/

#### オプション

`-o 出力ファイル名`
  このオプションは必須です。 ページの内容を出力する zip のファイル名 (のプレフィックス) を指定します。 実際にはこの名前は出力ファイル名としてそのまま使われるわけではなく、 タイムスタンプ (あるいは `-b` で指定した文字列) と 拡張子 `.zip` が自動的に追加されます。

`-m 再帰的クロールの最大深度`
  サイト内を再帰的にクロールするさいの最大深度 (デフォルトは 1) を指定します。 この値を 2 にするとリンクを 2段階でたどることになり、クロールするページ数が 大幅に増えます (たいていのニュースサイトでは、深度 1 だとページ数は 100程度、 2 にするとページ数は 1000〜2000 になります)。

`-k cookieファイル名`
  クローラが cookie を読み込むファイル (Mozilla の cookie.txt ファイル形式) を指定します。 サイトによっては、クローラがページを取得するのにクッキーを要求してくるところがあります。 このような場合、Mozilla であらかじめ取得した cookie.txt を指定しておけば クロールのさいにそれを使用できます。クローラが途中で取得したセッション用 cookie を このファイルに保存することはありません。

`-c デフォルトの文字コード`
  サイト内のページに HTML charset の指定がない場合、 デフォルトで使用する文字コードの名前 ("`euc-jp`", "`utf-8`" など) を指定します。文字コードの自動認識機能はありません。

`-a 許可する正規表現パターン`
  クロールを許可する URL のパターンを正規表現で指定します。 このオプションは `-j` オプションとともに複数個指定でき、 指定された順に判定されます。 したがって、オプションを指定する順番を変えると動作が変わります。

`-j 禁止する正規表現パターン`
  クロールを禁止する URL のパターンを正規表現で指定します。 このオプションは `-a` オプションとともに複数個指定でき、 指定された順に判定されます。 したがって、オプションを指定する順番を変えると動作が変わります。 デフォルトでは、`jpg, jpeg, gif, png, tiff, swf, mov, wmv, wma, ram, rm, rpm, gz, zip, class` の 拡張子をもつ URL はすべて禁止されています。

`-U URLDBファイル名`
  URLDB はクロールした URL (正確には、そのmd5ハッシュ値) と日時を記録しておく Berkeley DB のファイルです。指定されたファイル名が存在しない場合は新たに空の URLDB ファイルが作成されます。このオプションを指定するとクローラは 一度訪れた URLのmd5ハッシュ値を URLDB に記録しておき、2度目には そのページを出力ファイルに保存しなくなります (が、そのページが 再帰的クロールの途中にある場合は、さらなるリンク先 URL を得るために ページの読み込み自体はおこないます)。サイトを一定時間おきに巡回する場合、 これを使うとクロール時間を大幅に短縮できます。

`-b タイムスタンプ文字列`
  保存する zip ファイル名につけるタイムスタンプとなる文字列を指定します。 ここで指定された文字列は zip ファイル内の各ページ URL の先頭にも "`200510291951/www.example.com/...`" のような形でつけられます。 このオプションを指定しないと、タイムスタンプは現在の時刻にもとづいて `YYYYMMDDHHMM` のような形式で自動的に決められます。

`-i index.htmlの名前`
  ある URL が "`/`" で終わっている場合、ここで指定した文字列を URL の末尾に自動的に追加します。デフォルトでは空文字列 (追加しない) になっています。 サイトによっては、"`http://host/dir/`" と "`http://host/dir/index.html`" は 別々のページとみなされることがありますので、注意が必要です (Apache の mod_dir など)。

`-D 遅延時間`
  このオプションを指定すると、各ページをクロールするとき、 1ページごとに指定された秒数だけ待つようになります。 連続したアクセスが迷惑な場合に指定します。 デフォルトでは遅延を行いません。

`-T タイムアウト時間`
  クロールの際のタイムアウト時間を秒数で指定します。 デフォルトでは 300秒です。

`-L linkinfoファイル名`
  textcrawler は各ページのリンクを取得する際に、 そのリンク (`<a>` タグ) に含まれる アンカーテキストも同時に記録しておきます。クロールが終わったあと、 この情報は "`linkinfo`" という名前で .zip ファイル中に 保存されます。この情報はページの題名を分析するために `analyze.py` によって使用されます。このオプションはそのファイル名を "`linkinfo`" に変更するためのもので、 この値を空文字列にするとアンカーテキストは保存されません。

`-d`
  デバッグレベルを上げます。

### `analyze.py` (レイアウト分析プログラム)

`analyze.py` は `textcrawler.py` が取得した HTMLページの束をもとにレイアウトを分析し、学習したパターンファイルを標準出力に表示します。 使用するページの数によって、所要時間は数時間にも及ぶことがあります。 (なお、このプログラムに Psyco を使ってもメモリを大量消費するだけで、 今のところまったく効果がでません。)

`analyze.py` が出力するパターンファイル中の各パターンには、 ページ中の文字数などを考慮して、そのパターンの有用度を表す「スコア」がついています。 ふつう、このプログラムはすべてのページから本文を発見しようとしますが、 実際には「どのページが記事か」までは判定できません。 占いのコーナーや読者の声、新聞社の概要などはふつう別のレイアウトで書かれており、 これらを排除したい場合は一部のパターンを削除する必要があります。 幸いにも、こういった記事以外のページは数が少なく、したがってそれ用の パターンのスコアも低くなる場合が多いので、このようなページは `analyze.py` の `-S` オプションをつかって、 ある一定以下のスコアをもつパターンを出力しないようにすることで 排除することができます (もちろん新聞によって差はありますが)。 さらに細かいチューニングを行ないたい場合は、パターンファイルを テキストエディタでじかに編集することもできます (パターンファイルの構造を参照してください)。

#### 構文

>     $ analyze.py [オプション] 入力ファイル名 ... > パターンファイル名

通常、入力ファイルには `textcrawler.py` で取得した zipファイル名を指定します。入力ファイルは複数指定することができます。 複数回にわたるクロールの結果 (同一サイトから日を変えて取得した結果など) を 使って学習したいときに便利です。

##### 使用例:

>     (asahi.200510120801.zip と asahi.200510220801.zip の 2つのファイルに
>         格納されているページを使ってレイアウトを学習し、結果を asahi.pat に保存する)
>     $ analyze.py asahi.200510120801.zip asahi.200510220801.zip > asahi.pat

なお、`wget` などで再帰的に取得したページを使いたいときは、 以下のようにして取得したファイル名の一覧を標準入力から与えてやります:

>     $ find 200510120801/ -type f | ./analyze.py - linkinfo > asahi.pat

この場合はこのディレクトリ構造が、あたかも `textcrawler.py` が出力する .zip ファイルと同じように、 `タイムスタンプ/URL` の構造をしている必要があります。

#### オプション

いくつかのオプションは非常に技術的なもので、これらを変更するには 動作原理を理解している必要があります。

`-c デフォルトの文字コード`
  HTML ファイル内に charset の指定がない場合、 デフォルトで使用する文字コードの名前 ("`euc-jp`", "`utf-8`" など) を指定します。文字コードの自動認識機能はありません。

`-a 許可する正規表現パターン`
  分析に使うこと許可する URL のパターンを正規表現で指定します。 このオプションは `-j` オプションとともに複数個指定でき、 指定された順に判定されます。 したがって、オプションを指定する順番を変えると動作が変わります。

`-j 禁止する正規表現パターン`
  分析に使うことを禁止する URL のパターンを正規表現で指定します。 このオプションは `-a` オプションとともに複数個指定でき、 指定された順に判定されます。したがって、オプションを指定する順番を変えると動作が変わります。 デフォルトでは、与えられた zip ファイルに含まれているすべてのファイルをつかって レイアウトを分析します。

`-t クラスタリングのしきい値`
  ページのレイアウトをクラスタリングする際のしきい値を 0.0 〜 1.0 の範囲で指定します。 2つの異なるページの類似度がこの値を超えるとその 2つのページは同一のクラスタ (つまり、同一のレイアウト) に属するとみなされます。 この値を上げるほど厳密にレイアウトを区別するようになり、したがって 正確に本文が取れるようになりますが、この値を上げすぎるとクラスタが大きくならず、 少数のページしか取得できなくなってしまいます。この値のデフォルトは 0.97 ですが、 サイトによっては 0.99 や 0.95 に変更すると性能が上がる場合があります。

`-T 題名判定のしきい値`
  記事の題名を判定するときに、リンクのアンカーテキスト (あるいは記事本文) との類似度を使いますが、 そのための最低値を指定します。

`-S スコアのしきい値`
  生成されたパターンファイルには、各パターンにその有用度をあらわす「スコア」がついています。 このオプションは指定されたスコア以下のパターンをパターンファイルに出力しないようにします。 デフォルトは 100 です。一般的にいって、スコアが 100 以下のページは、まず記事のページではありません。 ほとんどのニュースサイトでは、この値を 1000以上にしてもほとんどの記事が取得できるようです。 この値を -1 にするとパターンの切り捨ては行われません。

`-L linkinfoファイル名`
  `textcrawler.py` はふつう zip アーカイブ内に 各ページへのリンクのアンカーテキストを記録した "`linkinfo`" というファイルを 保存しますが、もしこのファイル名がデフォルトと違っている場合に指定します。 なお、アーカイブ内に "`linkinfo`" ファイルが存在しない場合は このオプションに空文字列を指定すると、`analyze.py` は自前で アンカーテキストを解析しようとしますが、これによりレイアウトの分析速度はさらに遅くなるので、 なるべく "`linkinfo`" を使ったほうがいいでしょう。

`-d`
  デバッグレベルを上げます。

### `extract.py` (テキスト抽出プログラム)

パターンファイルを渡すと URL および本文とタイトル、マッチしたパターンをそれぞれ標準出力に表示します。

#### 構文

>     $ extract.py [オプション] パターンファイル名 入力ファイル名 ... > 出力テキスト

##### 使用例:

>     (パターンファイル asahi.pat を使って、asahi.200510220801.zip に格納されているページから
>         テキストを抽出し、shift_jis 形式で asahi.200510220801.txt に保存する)
>     $ extract.py -C shift_jis asahi.pat asahi.200510220801.zip > asahi.200510220801.txt

#### オプション

`-C 出力テキストの文字コード`
  記事の題名と本文を出力する文字コードの名前 ("`euc-jp`" など) を指定します。 デフォルトは `utf-8` です。

`-c デフォルトの文字コード`
  HTML ファイル内に charset の指定がない場合、 デフォルトで使用する文字コードの名前 ("`euc-jp`", "`utf-8`" など) を指定します。文字コードの自動認識機能はありません。

`-a 許可する正規表現パターン`
  抽出に使うこと許可する URL のパターンを正規表現で指定します。 このオプションは `-j` オプションとともに複数個指定でき、 指定された順に判定されます。 したがって、オプションを指定する順番を変えると動作が変わります。

`-j 禁止する正規表現パターン`
  抽出に使うことを禁止する URL のパターンを正規表現で指定します。 このオプションは `-a` オプションとともに複数個指定でき、 指定された順に判定されます。したがって、オプションを指定する順番を変えると動作が変わります。 デフォルトでは、与えられた zip ファイルに含まれているすべてのファイルから 抽出をこころみます。

`-t パターン類似度のしきい値`
  レイアウトをパターンと比較する際の、最低の類似度 (デフォルトは 0.8) を指定します。 各ページは与えられたパターンファイルに入っているすべてのパターンと比較され、 その類似度が最大のものが使われますが、それでも類似度がこの値よりも低いと そのページはどのパターンにもマッチしない判断され、"`!UNMATCHED`" が出力されます。 この値はあまり変更する必要はありません。

`-S`
  厳格なモード。具体的には、各ページとパターンとのマッチングを行うさい、 パターン中で指定されている LayoutBlock がひとつでも欠けているページはすぐに「一致しない」と判定します。 このオプションを使うことにより、より厳密にパターンとマッチするページのみが取り出せますが、 サイトによってはレイアウトがつねに微妙に変化しているため、このオプションを使うと ほとんどのページがどのパターンにも合致せず "`!UNMATCHED`" になってしまいます。

`-T DiffScoreのしきい値`
  ページから本文または補助的なセクションを抽出するときに、 そのセクションの DiffScore が一定以上のもののみを「変化している部分」と認識して使用します。 デフォルトの値は 0.5 です。

`-d`
  デバッグレベルを上げます。

### `urldbutils.py` (URLDB操作プログラム)

URLDB を使うにつれてそのファイルサイズは単調増加しますが、 そのサイト上のある URL がどこにも見えなくなって一定の時間が経過した場合、 その URL はもう二度と現れない (したがって記憶しておく必要もない) と仮定してもよいでしょう。 URLDB に保存されている各 URL には、「その URL を最後に見た時刻」が記録されています。 `urldbutils.py` はこの情報を利用して URLDB ファイルから アクセスされなくなった URL 整理し、DBM を再構築するためのツールです。

#### 構文

>     $ urldbutils.py {-D | -R} [オプション] ファイル名 [旧ファイル名]

2つのモードのうち、表示(Display、`-D`) か再構築(Reorganize、`-R`) かの どちらかを選ぶ必要があります (表示機能はほとんどデバッグ用です)。 DBM を再構築する場合は、新、旧2つのファイル名を指定します。 (なお、安全のため、新しいファイルがすでに存在している場合このコマンドは動作しません。)

##### 使用例:

>     (myurldb ファイルの中で 10日間以上、目撃されていない URL を削除し、
>         新しいURLDB ファイル myurldb.new をつくる。
>         その後、旧ファイルを上書きする)
>     $ urldbutils.py -R -t 10 myurldb.new myurldb
>     $ mv -i myurldb.new myurldb
>     mv: overwrite `urldb'? y

#### オプション

`-D`
  URLDB の内容 (ハッシュ値 + 最終アクセス時間の組) を一覧表示します。

`-R`
  URLDB のエントリーのうち、一定時間以上アクセスされていないものを削除した新しい DBM ファイルを作成します。 新、旧2つのファイル名および `-t` オプションの指定が必要です。

`-t 日数`
  日数のしきい値。これ以上長い時間アクセスされていない URL が消去されます。

`-v`
  冗長 (verbose) モード。`-R`モードで削除した項目をすべて表示します。

### `html2txt.py` (簡単なテキスト抽出)

`html2txt.py` はパターン定義を使わないシンプルな html からのテキスト抽出ツール (というよりはタグ削除ツール) です。 これはただすべての HTML タグを入力ファイル中からとり除きます。 また、 `<script>`...`</script>` または `<style>`...`</style>` タグで囲まれている javascript やスタイルシートも取り除きます。

#### 構文

>     $ html2txt.py [オプション] 入力ファイル名 ... > 出力ファイル名

##### 使用例:

>     $ html2txt.py index.html > index.txt

#### オプション

`-C 出力テキストの文字コード`
  記事の題名と本文を出力する文字コードの名前 ("`euc-jp`" など) を指定します。 デフォルトは `utf-8` です。

`-c デフォルトの文字コード`
  HTML ファイル内に charset の指定がない場合、 デフォルトで使用する文字コードの名前 ("`euc-jp`", "`utf-8`" など) を指定します。文字コードの自動認識機能はありません。

### バグ

- おそい。 (`analyze.py` も `extract.py` も)
- まだ題名部分をミスすることがある。
- 腐った HTML でパーザが落ちる可能性。(タグが 1000 階層も入れ子になったりすると、あやしい)

## ライセンス

(いわゆる MIT/X ライセンスです)

Copyright (c) 2005-2007 Yusuke Shinyama <yusuke at cs dot nyu dot edu>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Last Modified: Thu Sep 6 17:17:16 JST 2007