【Django】Wikipedia APIを使ってwiki内にある情報を取得する

## パッケージ
情報取得に必要なパッケージをインストール

```terminal:terminal
$ pip install wikipedia
```

https://pypi.org/project/Wikipedia-API/

requirements.txtに書き込んでおく。

```terminal:terminal
$ pip freeze > requirements.txt
```

## import & setting

```python:shell
import wikipedia

#要求する言語を日本語に設定
wikipedia.set_lang("jp")
```

## 関数
### wikiでクエリを検索
```python:shell
# デフォルト
wikipedia.search(query, results=10, suggestion=False)

>>> wikipedia.search("python")
['Python', 'モンティ・パイソン', 'IDLE (Python)', 'KML', 'Stackless Python', 'Eric Python IDE', 'Anaconda (Pythonディストリビューション)', 'IronPython', 'PyQt', 'Jython']

>>> wikipedia.search("python", results=3)
['Python', 'モンティ・パイソン', 'IDLE (Python)']

>>> wikipedia.search("python", results=3, suggestion=True)
(['Python', 'モンティ・パイソン', 'IDLE (Python)'], None)
```
|引数|説明
|---|---
|results|検索結果の件数（デフォルト10）
|suggestion|Trueの場合タプルで返します

### クエリの検索候補
候補がない場合はNoneを返します。

下記の例では、"pythone"と間違った入力を"python"に修正してくれています。

```python:shell
wikipedia.suggest(query)

>>> wikipedia.suggest("pythone")
'python'
```

### クエリの要約の取得
```python:shell
#デフォルト
wikipedia.summary(query, sentences=0, chars=0, auto_suggest=True, redirect=True)

>>> wikipedia.summary("python")
'Python（パイソン）はインタープリタ型の高水準汎用プログラミング言語である。グイド・ヴァン・ロッサムにより創り出され、1991年に最初にリリースされたPythonの設計哲学は、以下省略'

>>> wikipedia.summary("python", sentences=1)
'Python（パイソン）はインタープリタ型の高水準汎用プログラミング言語である。'

>>> wikipedia.summary("python", chars=1)
'Python…'
>>> wikipedia.summary("python", chars=10)
'Python（パイソン…'
```

|引数|説明
|---|---
|sentences|一文を返します（10文以下）0だと全文が返されます。
|chars|設定されている場合最初の文字を返します。
|auto_suggest|タイトルの候補がいくつかある場合有効なものを返します。
|redirect|RedirectErrorを発生させずにリダイレクトを許可します。

### ページのオブジェクトを取得
画像に関しては、ページの一番上の画像を取ってくるので使い物にならない気がしました。

|オブジェクト|説明
|---|---
|title|タイトルを取得
|categories|カテゴリーのリストを取得
|content|ページのテキストコンテンツを取得（画像・表・その他データを除く）
|images|ページ上の画像のURLのリストを取得
|links|ページ上のリンクのタイトルリストを取得
|references|ページ上の外部リンクのURLのリストを取得
|summary|ページのプレーンテキストの要約

```python:shell
#デフォルト引数
wikipedia.page(title=None, pageid=None, auto_suggest=True, redirect=True, preload=False)

>>> wikipedia.page("python")
<WikipediaPage 'Python'>

>>> wikipedia.page("Python").title
'Python'

>>> wikipedia.page("Python").categories[:2]
['BNF識別子が指定されている記事', 'FAST識別子が指定されている記事']

>>> wikipedia.page("Python").content[:50]
'Python（パイソン）はインタープリタ型の高水準汎用プログラミング言語である。グイド・ヴァン・ロッ'

>>> wikipedia.page("Python").url
'https://ja.wikipedia.org/wiki/Python'

>>> wikipedia.page("Python").images[:2]
['https://upload.wikimedia.org/wikipedia/commons/4/4a/Commons-logo.svg', 'https://upload.wikimedia.org/wikipedia/commons/5/5f/Disambig_gray.svg']

>>> wikipedia.page("Python").links[:5]
['.NET Framework', '1991年', '1994年', '1月1日', '2000年']

>>> wikipedia.page("Python").references[:2]
['http://forum.nokia.com/python', 'http://www.softantenna.com/wp/software/python-3-5-released/']

>>> wikipedia.page("Python").summary[:50]
'Python（パイソン）はインタープリタ型の高水準汎用プログラミング言語である。グイド・ヴァン・ロッ'
```

## 例外処理
最後の基本例外クラス`wikipedia.exceptions.WikipediaException`一つだけでまとめちゃっても大丈夫です。

```python:
#ページの曖昧性が解決される時に発生
exception wikipedia.exceptions.DisambiguationError(title, may_refer_to)

#リクエストがタイムアウトすると発生
exception wikipedia.exceptions.HTTPTimeoutError(query)

#クエリに一致するものがない場合発生
exception wikipedia.exceptions.PageError(pageid=None, *args)

#予期しないリダイレクトに解決された場合に発生
exception wikipedia.exceptions.RedirectError(title)

##基本例外クラス
exception wikipedia.exceptions.WikipediaException(error)
```

より詳しい情報は公式ページで

https://wikipedia.readthedocs.io/en/latest/code.html

## Djangoで実装
blogアプリにTgsモデルを作成したと想定。

blogの記事に付けたタグ名の情報をwikiから取得してみる。

```python:views.py
import wikipedia
from .models import Tags

wikipedia.set_lang("jp")

def TagsDetailView(request, name):
    tag_data = Tags.object.get(name=name)
    try:
        wiki_summary = wikipedia.summary(tag_data.name, sentences=2)
    except wikipedia.exceptions.DisambiguationError:
        wiki_summary = str(f"「{tag_data.name}」には候補が多数あります。タグ名に情報を追加し曖昧さを回避してください。")
    except wikipedia.exceptions.HTTPTimeoutError:
        wiki_summary = str("タイムアウトしました。")
    except wikipedia.exceptions.PageError:
        wiki_summary = str(f"「{tag_data.name}」に一致するものがありません。")

    context = {
        'tag_data': tag_data,
        'wiki_summary': wiki_summary,
        }
    return render(request, "blog/detail.html", context)

##その他
wiki_search = wikipedia.search(tag_data.name)
wiki_summary = wikipedia.summary(tag_data.name, sentences=2)
wiki_page = wikipedia.page(tag_data.name)
```

## 注意
queryの結果が存在しなかったり複数あったりすると正常に表示されないので例外処理を必ずしておく。

最善の策は、queryとwikiのページタイトル名を同じにすることですが、`auto_suggest`をTrue（デフォルト）にしておけば、queryに情報を追加するだけである程度予測し表示してくれるようにります。

## 感想
wikiの特性上どうしようもないのかもしれませんが、細部の情報が取得でできない？のでちょっと物足りない気がしました。

画像の取得に関しても「サムネイルを取得したいのにできない」というモヤモヤが・・・

サムネイルの取得についてどなたかご存知の方がいらっしゃったら教えて下さい汗

他に経度・緯度を取得する関数もありますが、この記事では割愛しました。

Wikipedia API公式

https://wikipedia.readthedocs.io/en/latest/code.html