Funny Snowman

FunnySnowman > Geek<ギーク>なコトをやってみよっと

Pythonスクリプトでウィキ(wikipedeia)のデータを検索してみたら、とっても簡単だった。

ゴール設定(ラピロが何でも教えてくれる百科事典ロボットになる!)

自分で書いた会話シミュレーションだけでは面白くない。そこで、自分も知らない言葉や単語を聞かれたときは、ウィキペディア(wikipedia)の膨大なフリー百科事典で検索してみることにした。例えば、ラピロに質問してみる「外傷って何ですか?」(いや、知っているよ。知っているけれど、サンプルとして聞いただけ)。そしたら、ラピロは、こう答える「外傷とは、身体を構成している組織の生理的な連続性が断たれた状態のこと。機械的外力(力学的外力)による損傷。目視可能な損傷、比較的軽度な損傷などの俗称。の事ですよ」。ね、ラピロのIQが一気に100を超えそうな気がしませんか?

Rapiro ラピロが百科事典ロボットになる

事前準備(pythonライブラリのインストール)

インターネットのウィキペディアを検索するには、wikipediaのpythonライブラリをインストールします。

$ sudo pip install wikipedia                       # Wikipediaライブラリをインストール
Downloading wikipedia-1.4.0.tar.gz
  

2017年7月時点では、version1.4.9のwikiライブラリがダウンロード、インストールされました。

実験(インタプリタ・コマンドラインで検索してみる)

pythonインタプリタを実行して、コマンドラインでwikiを検索して動作を確認する。ひえええー。本当にこの3行だけでWikiサイトからデータを取得出来ちゃったよ。

pi@raspberrypi:~$ python
>>> import wikipedia
>>> wikipedia.set_lang("ja")
>>> print wikipedia.summary("外傷")
外傷とは
身体を構成している組織の生理的な連続性が断たれた状態のこと。本項で詳述する。
機械的外力(力学的外力)による損傷。目視可能な損傷、比較的軽度な損傷などの俗称。
外傷(がいしょう、英: injury, trauma)とは、外的要因による組織または臓器の損傷の総称。
通常、怪我(けが)と呼ばれ、外傷を負うことを負傷(ふしょう)といい、外傷を負った者を
負傷者(ふしょうしゃ)という。なお、死亡と外傷をあわせて死傷(ししょう)といい、死亡
した者と外傷を負った者とを合せて死傷者(ししょうしゃ)という。精神医学において、心理
的外傷を単に外傷と呼ぶことがある→心的外傷(トラウマ)を参照。身体的外傷の場合、広義
には、物理的あるいは化学的な外的要因による損傷すべてを指すが、通常は機械的外力(力学
的外力)による損傷を指す。
  

でも説明長い。ラピロに喋らせるには少々面倒です。ここで戻値の文章の数を指定できます。

pi@raspberrypi:~$ python
>>> import wikipedia
>>> wikipedia.set_lang("ja")
>>> print wikipedia.summary("外傷", sentences=1)
外傷とは
身体を構成している組織の生理的な連続性が断たれた状態のこと。
  

知りたい単語の意味を説明するには不十分なので、2~3文は必要かも。

最終検査(Pythonスクリプトで実行してみる)

ラピロのメインスクリプトに組み込む前の最終テストとして、小さいスクリプト(wikitest.py)を書いてみた。例えば「外傷」を聞くなら、[python wikitest.py 外傷]を実行する。すると、ラピロがインターネットのwikipediaで調べた結果を、前回までに作ったjtalkスクリプトで音声合成して喋ってくれる。
▽ スクリプト

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# wikitest.py

import wikipedia
import sys
import os

# Wikiの検索
def main_wiki( strText ):

	# 単語のサマリーを取得。
	print( strText + "ですね。ちょっとお待ちください。" )
	wikipedia.set_lang("ja")

	#print wikipedia.summary( strText )
	try:
		strReturn = wikipedia.summary( strText, sentences=1 ).encode("utf-8")
	except:
		print( "いっぱい考えたけど、思い出せなかっです。" )
	finally:
		print( strReturn )
		strReturn = strReturn + "の事です。"
		strCMD = "./jtalk.sh '" + strReturn + "' 'normal'"
		os.system( strCMD )

	# タイトルの取得。
	#print( "▼タイトル" )
	#ny = wikipedia.page( strText )
	#print( ny.title )

	# 単語の詳細情報を取得。
	#print( "▼詳細情報" )
	#print( ny.content ) とても口語で喋るには情報量が多すぎるのでコメントアウト。

# 初期設定
if __name__ == '__main__':

	if (len(sys.argv) <= 1):
		print("Syntax: python wikitest.py '[text]'")
		sys.exit()
	else:
		main_wiki( sys.argv[1] )
        
  

▽ 実行結果

# python wikitest.py 外傷
外傷ですね。ちょっとお待ちください。
外傷とは
身体を構成している組織の生理的な連続性が断たれた状態のこと。の事です。
  

何を聞いても回答してくれる。ラピロが凄く頭良くなった。

考察(オフライン版wikipediaを使うか?)

Wikipediaの別の使い方として、wikiにはダウンロード用のデータファイルが用意されている。これはwikiのwebサイトをクローリングしてデータを取り出しちゃおうという人が増えてWebサイトの負荷が高まってしまうことを避ける目的と思われる。wikiのデータ(jawiki-latest-pages-articles.xml)は解凍後で10GBを超える巨大なファイルだった。SQLなどで検索するには、XMLファイルをRDBなどに変換した方がいい。下記pythonスクリプトで直接XMLファイルを検索することも出来たが、検索に58秒かかった。

考察の結果としては、簡単にwikiを実装するならインターネットwikiを検索する方が、(1)速い (2)簡単:インストール不要 (3)最新の辞書データを参照できる。ダウンロードした時の利点は、(1)オフラインでも使える (2){あり得ないだろうけれど}将来wikiがサービス終了になったりしても使い続けられる だろうか。

▽ スクリプト

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Wikipediaから記事をパースする

import xml.sax
import xml.sax.handler
import sys
import string

glbTitle = False
glbSearch = False
glbComment = False
glbKeyword = ""
glbCount = 0

class Handler( xml.sax.handler.ContentHandler ):

        def startElement(self, name, attrs):
                global glbTitle, glbComment
                if( name == "title" ):
                        glbTitle = True
                if( name == "text" ):
                        glbComment = True

        def endElement(self, name):
                global glbTitle, glbComment
                if( name == "title" ):
                        glbTitle = False
                if( name == "text" ):
                        glbComment = False
                if( glbSearch == True and name == "text" ):
                        sys.exit()

        def characters(self, content):
                global glbSearch, glbCount

                if( glbTitle == True ):
                        #print "Title:" + content
                        #if( string.find(content, glbKeyword ) != -1 ):
                        if( content == glbKeyword ):
                                glbSearch = True

                if( glbSearch == True and glbComment == True ):
                        if( glbCount < 10 ):
                                print content
                                glbCount = glbCount + 1

                return

def main( strKeyword ):
        global glbKeyword
        glbKeyword = strKeyword
        print( "<" + strKeyword + ">" )

    # SAX XMLReaderオブジェクトを生成する
        parser = xml.sax.make_parser()
    # XMLReaderにイベントのハンドラーを設定する。
        parser.setContentHandler( Handler() )
    # XMLReaderが、入力ソースを使ってSAXイベントを発生させる。
        parser.parse(open("jawiki-latest-pages-articles.xml","r"))
        return

if __name__=="__main__":

        if ( len(sys.argv) < 1 ):
                print( "Syntax: python try_readxml.py " )
        else:
                main( sys.argv[1].decode("utf-8") )
  

▽ 実行結果

# python try_readxml.py 外傷
<外傷>
{{otheruses|身体的外傷|心理的外傷|心的外傷}}
'''外傷'''とは
#身体を構成している組織の生理的な連続性が断たれた状態のこと。本項で詳述する。
#[[機械]]的外力([[力学]]的外力)による損傷。目視可能な損傷、比較的軽度な損傷などの俗称。
----
  

まとめ(ラピロが何でも教えてくれる百科事典ロボットになる!)

Pythonのwikipediaライブラリを使うと、最小、僅か3行のスクリプトを追加するだけで、インターネットのフリー百科事典を検索してデータを取得することができた。ラピロに組み込むことで、自分でWikiを検索できる、とっても頭のいいロボットになった。意外なことにインターネットの日本語ブログなどで「Pythonのwikipediaライブラリ」を使った事例が掲載されていないので、ついつい、wiki全項目のデータダウンロードを最初に試してしまい2日間くらい余計な作業をしてしまったけど、オンライン版wiki検索ライブラリはお薦め。

ラピロがWikipedia百科事典ロボットになった

▲上に戻る