Python ライブラリ wscraper を使って Wikipedia のテキストデータを処理する

# wscraper について

[wscraper (GitHub)](https://github.com/tfull/wikipedia_scraper)
[wscraper (PyPI)](https://pypi.org/project/wscraper/)

PyPI で公開されている、 `wscraper` というパッケージは、当記事の筆者 T.Furukawa が作成し、2021年11月現在では `v0.2.0` が最新となっています。
wscraper は Wikipedia のダンプファイルを読み込み、 Python コード中で記事の内容を一つずつ返す機能などを備えています。これを用いて、辞書を作ったり、機械学習モデルに与えるデータを作ったりすることができます。
Wikipedia のデータは10GB単位の膨大なデータであるため、使用する際にはメモリの管理に気を使う必要があります。また、本文はテキスト整形用の記号が含まれており、文書としての解釈に一手間かける必要があります。そういった課題を解決し、 Wikipedia の大きなデータを、文の大規模データとして簡潔に活用する目的として wscraper は作られました。

# 使用例

## コマンド

Python 3 を想定しています。 wscraper を pip でインストールします。

```
pip install wscraper==0.2.0
```

解析したい Wikipedia を用意しましょう。アーカイブされた XML 形式のダンプがあります。

https://dumps.wikimedia.org/jawiki/

`jawiki-*-pages-articles-multistream.xml.bz2` の形式である数GBのデータです。

ダウンロードしたら、 bunzip2 で展開します。

```
bunzip2 ファイル名.xml.bz2
```

数十GBの大きなデータなので、ある程度のストレージが必要です。

さて、 wscraper を使いますが、最初に初期化でディレクトリを作っておきます。

```
wscraper initialize
```

ディレクトリと、必要なファイルが生成されます。デフォルトでは `~/.wscraper` 以下が生成されますが、 `WSCRAPER_ROOT` でパスは変更できます。

次に、展開した XML ファイルを、 wscraper にインポートします。 `--name` で、 wscraper 内での名前を与えられます。デフォルトでは、拡張子を外したファイル名になります。ここでは、 `my_wp` と名付けました。
import によって、大きな XML ファイルを複数の XML に切り分けて保存してくれます。

```
wscraper import ファイル名.xml --name my_wp
```

では、 `my_wp` と名前のついたコーパスを、デフォルトで使用する状態 (current) にします。

```
wscraper switch my_wp
```

言語の設定もしておきます。ダウンロードした Wikipedia の言語です。現状日本語と英語しかありませんが。
`wscraper set` で、 current のコーパスに対して言語を設定します。
これをやると、 Python コード中で言語情報を与えなくてよくなります。

```
wscraper set --language japanese
```

コマンドでの準備は完了です。

## Python コード

`wscraper.analysis` 以下に、各種のイテレーターがあります。

```python
from wscraper.analysis import *
```

Wikipedia のダンプファイルには、 記事とリダイレクションの情報が含まれています。 EntryIterator, RedirectionIterator を用意しています。どちらも構わず取得したいのであれば、 BothIterator が使えます。

```python
# Entry, Redirection を返す。
for i, b in enumerate(BothIterator()):
    print(f"both: {i}: {type(b)}")

# title は記事のタイトル、 mediawiki はマークアップされた文書
for i, e in enumerate(EntryIterator()):
    print(f"entry {i}: {e.title} {len(e.mediawiki)}")

# source はリダイレクション元タイトル、 target はリダイレクション先タイトル
for i, r in enumerate(RedirectionIterator()):
    print(f"redirection: {i}: {r.source} -> {r.target}")
```

`wscraper switch` と `wscraper set` を実行していれば、引数無しでイテレーターを生成できます。もし実行していない場合は、 `EntryIterator(name = "my_wp", language = "japanese")` のように、ここで引数として与えます。

文書、文章を解析したい場合は、上記のイテレーターを使用することは少ないと思います。  `ArticleIterator` と `ParagraphIterator` の出番です。どちらも、マークアップ用の記号などは排除され、人目でも読みやすい文になっています。
（このアルゴリズムは改良の余地があると思われるため、随時更新していく可能性があります。）

`ArticleIterator` は、記事1つに対して1レコード、 `ParagraphIterator` は、記事をさらに段落 (元データで `== 段落タイトル ==` となっている部分) で区切り、複数レコードにしています。例えば、現時点での Wikipedia の 「[Python](https://ja.wikipedia.org/wiki/Python)」 の記事では、「概要」や「言語の機能」というタイトルを持つ段落があります。

このイテレーターは、引数を与えなければ文を `str` で返してくれますが、言語モデルに与えるための形態素解析をしたい場合は多いと思われます。 `tagger` 引数で、出力される文に噛ませたい関数を設定しましょう。引数に `type = dict` を設定すると、タイトルなども含めて dict 形式で返してくれます。詳しくは GitHub リポジトリの README を御覧ください。

```python
# MeCab で形態素解析
import MeCab

tagger = MeCab.Tagger("-Owakati")

def tokenize(x):
    return tagger.parse(x).strip().split()

for it in ArticleIterator(tagger = tokenize):
    # tokenize された結果が it に入る
    pass
```

例えば、 `gensim.models.word2vec.Word2Vec` はコーパスとしてイテレーターを受け取れるので、このまま Word2Vec を学習させることができます。

```
w2v = Word2Vec(ArticleIterator(tagger = tokenize))
```

また、 Wikipedia 以外の手持ちのコーパスをくっつけて、機械学習させたい場合も出てくるかもしれません。その時は、 `CombinedIterator` でイテレーターをくっつけることが可能です。

```python
# サンプル用追加データのイテレーター
# ランダムな6単語でなる文（仮）を生成
class MyIterator:
    def __init__(self):
        self.i = 0
        self.n = 20

    def __iter__(self):
        self.i = 0
        return self

    def __next__(self):
        if self.i >= self.n:
            raise StopIteration()
        self.i += 1
        return random.choices(["dog", "cat", "mouse", "horse", "ABC", "look", "watch", "peace", "world", "hello"], k = 6)


combined_iterator = CombinedIterator(ArticleIterator(tagger = tokenize), MyIterator())

Word2Vec(combined_iterator)
```

（余談、 `itertools.chain` で済ますことも検討しましたが、 `iter` 関数の初期化の挙動がうまくいかず、独自のクラスを作ることにしました。）

# 削除

デフォルトで `~/.wscraper` 以下にあるデータは、 pip uninstall しても消えません。 `rm -r ~/.wscraper` で消してください。

# まとめ

wscraper は、 Wikipedia の大規模データを、メモリ効率を考えながら、マークアップを消したノイズの少ない文で取得できるパッケージです。自然言語処理タスクやその他の作業において、沢山の文や単語のデータが必要になったときは使ってみてください。