【Python】wikipediaライブラリで指定したページと異なる結果が返ってくる

# 概要

pythonで[wikipediaのライブラリ](https://pypi.org/project/wikipedia/)を用いてスクレイピングしてた時に、__正しいページタイトルを指定しているのに異なる結果が返ってくる__ という事象に出くわしたので、その時に調べたことをまとめます。

# 事象

例として下記の[アイカツ!](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%82%A4%E3%82%AB%E3%83%84!)の取得例を見てみます。

```python
import wikipedia

target = "アイカツ!"

wikipedia.set_lang("ja")
wikipedia.search(target)
```

```
実行結果
['アイカツ!',
 'アイカツ! (アニメ)',
 'アイカツプラネット!',
 'アイカツフレンズ!',
 'アイカツスターズ!',
 'アイカツオンパレード!',
 'アイカツ!の登場人物一覧',
 'BEST FRIENDS!',
 'AIKATSU☆STARS!',
 'STAR☆ANIS']
```

```python
page_name = wikipedia.search(target)[0]
wikipedia.page(page_name)
```

```
実行結果
<WikipediaPage 'アイオワ州'>
```
？？？

アイオワ州、君は一体どこからやってきたんだい？？

---
wikipediaの検索窓で検索をかけてみる。

__-「アイカツ!」 （びっくりマークは半角）での検索結果 -__
![スクリーンショット 2023-09-20 22.09.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614119/795209cb-0882-16d3-341b-c88b1590e1d8.png)

検索上位２つしか映っていませんが、wikipedi.searchと同様の結果です。
全く問題は見当たりません。ところが、「!」を全角にすると...

__-「アイカツ！」 （びっくりマークは全角）での検索結果 -__
![スクリーンショット 2023-09-20 22.16.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614119/83af27f0-e5a9-764e-8ce8-14fe061330d6.png)

検索結果は同じですが、「もしかして：アイオワ」という結果が出現。
納得しづらいサジェストですが、これがとりあえずの原因そう。（なぜ全角びっくりマークでの検索結果が返ってきてるのかは不明ですが...）

# 調査・原因

ソースコードを見てみます。まずは```search```から。

```python
@cache
def search(query, results=10, suggestion=False):
  '''
  Do a Wikipedia search for `query`.

  Keyword arguments:

  * results - the maxmimum number of results returned
  * suggestion - if True, return results and suggestion (if any) in a tuple
  '''

  search_params = {
    'list': 'search',
    'srprop': '',
    'srlimit': results,
    'limit': results,
    'srsearch': query
  }
  if suggestion:
    search_params['srinfo'] = 'suggestion'

  raw_results = _wiki_request(search_params)

  if 'error' in raw_results:
    if raw_results['error']['info'] in ('HTTP request timed out.', 'Pool queue is full'):
      raise HTTPTimeoutError(query)
    else:
      raise WikipediaException(raw_results['error']['info'])

  search_results = (d['title'] for d in raw_results['query']['search'])

  if suggestion:
    if raw_results['query'].get('searchinfo'):
      return list(search_results), raw_results['query']['searchinfo']['suggestion']
    else:
      return list(search_results), None

  return list(search_results)
```

```suggestion```という引数がありますね。これを```True```にすると下記のように、検索結果に加えて、サジェスト結果も返ってきます。

```python
wikipedia.search("アイカツ!", suggestion=True)
```
```
実行結果
(['アイカツ!',
  'アイカツ! (アニメ)',
  'アイカツプラネット!',
  'アイカツフレンズ!',
  'アイカツスターズ!',
  'アイカツオンパレード!',
  'アイカツ!の登場人物一覧',
  'BEST FRIENDS!',
  'AIKATSU☆STARS!',
  'STAR☆ANIS'],
 'アイオワ')
```

次に```page```を見てみます。

```python
def page(title=None, pageid=None, auto_suggest=True, redirect=True, preload=False):
  '''
  Get a WikipediaPage object for the page with title `title` or the pageid
  `pageid` (mutually exclusive).

  Keyword arguments:

  * title - the title of the page to load
  * pageid - the numeric pageid of the page to load
  * auto_suggest - let Wikipedia find a valid page title for the query
  * redirect - allow redirection without raising RedirectError
  * preload - load content, summary, images, references, and links during initialization
  '''

  if title is not None:
    if auto_suggest:
      results, suggestion = search(title, results=1, suggestion=True)
      try:
        title = suggestion or results[0]
      except IndexError:
        # if there is no suggestion or search results, the page doesn't exist
        raise PageError(title)
    return WikipediaPage(title, redirect=redirect, preload=preload)
  elif pageid is not None:
    return WikipediaPage(pageid=pageid, preload=preload)
  else:
    raise ValueError("Either a title or a pageid must be specified")
```

```results, suggestion = search(title, results=1, suggestion=True)```とあるようにデフォルトでは```suggestion=True```で検索してして、```title = suggestion or results[0]```でページタイトルを更新しています。

```page(title="~")```で引数に厳密なページタイトルを指定しなくても結果が得られるように、デフォルトではサジェストを含めて毎回検索するようになっているみたいです。

サジェスト結果に左右されたくない場合には```auto_suggest=False```にして、厳密なページタイトルを指定すれば良さそうです。

```python
wikipedia.page("アイカツ!", auto_suggest=False)
```
```
実行結果
<WikipediaPage 'アイカツ!'>
```


# まとめ

- ```wikipedia.page()```はデフォルトでは、引数による検索結果をもとにページを取得している
- 検索結果のトップよりも「もしかして」のサジェスト結果が優先される

サジェスト結果を受け入れても良い場合には
```python
wikipedia.page("アイカツ!")
```
そうでない場合には
```python
page_name = wikipedia.search("アイカツ!")[0]
wikipedia.page(page_name, auto_suggest=False)
```

と書くのが良さそうです。

ただし

```python
wikipedia.search("生徒会にも穴はある!")
```
```
実行結果
['生徒会の一存',
 '生徒会役員共',
 '生徒会にも穴はある!',
 '賭ケグルイ',
 'ヤンキー君とメガネちゃん',
 'めだかボックス',
 '恋と選挙とチョコレート',
 'HAUNTEDじゃんくしょん',
 '豊田萌絵',
 '映像研には手を出すな!']
```
のようにそもそもWikipediaの検索自体に不安があります...笑
このことを念頭に入れて、使っていく必要がありそうです。