概要
pythonでwikipediaのライブラリを用いてスクレイピングしてた時に、正しいページタイトルを指定しているのに異なる結果が返ってくる という事象に出くわしたので、その時に調べたことをまとめます。
事象
例として下記のアイカツ!の取得例を見てみます。
import wikipedia
target = "アイカツ!"
wikipedia.set_lang("ja")
wikipedia.search(target)
実行結果
['アイカツ!',
'アイカツ! (アニメ)',
'アイカツプラネット!',
'アイカツフレンズ!',
'アイカツスターズ!',
'アイカツオンパレード!',
'アイカツ!の登場人物一覧',
'BEST FRIENDS!',
'AIKATSU☆STARS!',
'STAR☆ANIS']
page_name = wikipedia.search(target)[0]
wikipedia.page(page_name)
実行結果
<WikipediaPage 'アイオワ州'>
???
アイオワ州、君は一体どこからやってきたんだい??
wikipediaの検索窓で検索をかけてみる。
検索上位2つしか映っていませんが、wikipedi.searchと同様の結果です。
全く問題は見当たりません。ところが、「!」を全角にすると...
検索結果は同じですが、「もしかして:アイオワ」という結果が出現。
納得しづらいサジェストですが、これがとりあえずの原因そう。(なぜ全角びっくりマークでの検索結果が返ってきてるのかは不明ですが...)
調査・原因
ソースコードを見てみます。まずはsearch
から。
@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
にすると下記のように、検索結果に加えて、サジェスト結果も返ってきます。
wikipedia.search("アイカツ!", suggestion=True)
実行結果
(['アイカツ!',
'アイカツ! (アニメ)',
'アイカツプラネット!',
'アイカツフレンズ!',
'アイカツスターズ!',
'アイカツオンパレード!',
'アイカツ!の登場人物一覧',
'BEST FRIENDS!',
'AIKATSU☆STARS!',
'STAR☆ANIS'],
'アイオワ')
次にpage
を見てみます。
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
にして、厳密なページタイトルを指定すれば良さそうです。
wikipedia.page("アイカツ!", auto_suggest=False)
実行結果
<WikipediaPage 'アイカツ!'>
まとめ
-
wikipedia.page()
はデフォルトでは、引数による検索結果をもとにページを取得している - 検索結果のトップよりも「もしかして」のサジェスト結果が優先される
サジェスト結果を受け入れても良い場合には
wikipedia.page("アイカツ!")
そうでない場合には
page_name = wikipedia.search("アイカツ!")[0]
wikipedia.page(page_name, auto_suggest=False)
と書くのが良さそうです。
ただし
wikipedia.search("生徒会にも穴はある!")
実行結果
['生徒会の一存',
'生徒会役員共',
'生徒会にも穴はある!',
'賭ケグルイ',
'ヤンキー君とメガネちゃん',
'めだかボックス',
'恋と選挙とチョコレート',
'HAUNTEDじゃんくしょん',
'豊田萌絵',
'映像研には手を出すな!']
のようにそもそもWikipediaの検索自体に不安があります...笑
このことを念頭に入れて、使っていく必要がありそうです。