Yahoo! 日本語形態素解析 Web サービスの Wrapper を書いてみた。ついでに うはぁ検索に組み込んで うひゃ検索にした。


Python から Yahoo! 日本語形態素解析 Web サービスを使うための Wrapperを書いてみました。


ついでに前回紹介させてもらった「うはぁ検索」に組み込んで WikiはてなYahoo!日本語形態素解析WebサービスAmazon を同時に検索する 「うひゃ検索」 に進化させてみました。
http://small-world.sakura.ne.jp/whya.cgi


Yahoo! では形態素解析用の辞書のメンテナンスをしているとのことで
頻繁に検索される言葉は辞書に登録されているようです。
この辞書に登録されていればかなりメジャーな言葉といえそうですね。

ちなみに一般的な辞書に載ってなくって登録されているのは


残念ながら? まだ登録されていないのは。

等でした。


Yahoo! 日本語形態素解析 Web サービスは辞書がメンテナンスされているのはスバラシいのですが、困るのは未知語を全て名詞と判断してしまうことです。
英数文字やカタカナだけで書かれた言葉は、めちゃくちゃな言葉でも全て名詞と判断されてしまいます。実際のところ未知語のほとんどは名詞なので、困らない場合も多いのでしょうが、使っている方は未知語なのか名詞なのかの区別がつかないので、ここは利用者側に品詞を選択できるようにしてほしかったです。


Yahoo! 日本語形態素解析 Web サービスの Wrapper のソースを貼り付けておきます。

#!/home/small-world/local/bin/python
# coding=utf-8

import sys, urllib, logging
from xml.etree import ElementTree

class YahooApisParseWrapper:
 def __init__(self, appid, logger=False ):
  self.opener = urllib.FancyURLopener()
  self.appid = appid
  self.logger = logger
  self.YahooApisParseWrapperUrl = \
   "http://jlp.yahooapis.jp/MAService/V1/parse?"

  if self.logger:
   self.logger.debug( 'YahooApisParseWrapperLocalSearchUrl: ' +
                      self.YahooApisParseWrapperUrl )

 # xmlnsが定義されているとtagの名前の前に
 # xmlnsで定義されているURIが付加されて
 # {http://webservices.amazon.com/AWSECommerceService/2005-10-05}Title
 # のようになる
 def getXmlns( self, xml ):
  
  xmlns = ''
  start = xml.find( 'xmlns="' ) + len( 'xmlns="' )
  end = xml.find( '"', start + len( 'xmlns="' ) )

  if start >= 0 and end >= 0:
   xmlns = '{' + xml[ start : end ] + '}'

  if self.logger:
   self.logger.debug( 'xmlns: ' + xmlns )

  return xmlns

 # Yahoo!日本語形態素解析Webサービスの実行
 def Parse( self, Keywords ):
  try:
   # Getの変数に値をセット
   Keywords = urllib.quote( Keywords )
   get_val = 'appid=' + self.appid +\
             '&sentence=' + Keywords

   # ログ出力
   if self.logger:
    self.logger.debug( 'Parse: ' +
     self.YahooApisParseWrapperUrl + '&' + get_val )
  
   # API実行
   xml = self.opener.open(self.YahooApisParseWrapperUrl , get_val).read()
   if self.logger:
    self.logger.debug( xml )

   # xmlnsの取得
   xmlns = self.getXmlns( xml )

   # ElementTreeの構築
   eTree = ElementTree.fromstring( xml )

   return eTree, xmlns

  except:
   msg = 'Parse失敗 %s: %s \n' \
            %(sys.exc_info()[0], sys.exc_info()[1])
   if self.logger:
    logger.error( msg )

 # Parseの結果から要素を取り出す
 # 取り出す要素を指定できる。
 def getWord( self, eTree, xmlns, extractAttributes ):
  try:

   # 検索にヒットしたwordのリスト作成
   wordList = 
   for elem in eTree.getiterator():
     if elem.tag == xmlns + 'word':
      wordList.append( elem )

   # 各wordからextractAttributesで指定された要素を取り出して
   # itemsに入れて返す
   # itemsはディクショナリのリスト
   items = 
   for item in wordList:
    Attr = {}
    Attr['Tree'] = item
    for key, val in extractAttributes.items():
     Attr[ key ] = item.find( val ).text.encode( 'utf-8' )
    items.append( Attr )
    
   return items

  except:
   msg = 'getWord失敗 %s: %s \n' \
            %(sys.exc_info()[0], sys.exc_info()[1])
   if self.logger:
    logger.error( msg )

if  __name__    ==  '__main__':
 # ---------- Logger set up ---------- #
 DEBUG_LEBEL=logging.DEBUG
 #DEBUG_LEBEL=logging.INFO
 LOG_FILE="./YahooApisParseWrapper.log"
 LOGGER_NAME="YahooApisParseWrapper"
 logger = logging.getLogger(LOGGER_NAME)
 logger.setLevel(DEBUG_LEBEL)
 formatter =\
  logging.Formatter("%(asctime)s, %(levelname)s, %(module)s, %(lineno)d, %(message)s")
 hdlr = logging.FileHandler(LOG_FILE)
 hdlr.setFormatter(formatter)
 logger.addHandler(hdlr)
 # ---------- End Logger set up ---------- #
 try:
  # 必須
  # Yahoo! JAPAN Webサービス の アプリケーションID
  appid = 'Your Access Key ID'
  
  # インスタンス作成
  awsapw = YahooApisParseWrapper( appid, logger )

  # Parseの実行
  # searchWord = '涼宮ハルヒ'
  #searchWord = 'モーニング娘。'
  searchWord = 'しょこたん'
  #searchWord = 'ごっつい'
  #searchWord = 'ほしのあき'

  # Parse をする
  eTree, xmlns = awsapw.Parse( searchWord )

  # Parseの検索結果から値を取り出す
  extractAttributest = { 
   'surface':xmlns + 'surface' ,
   'pos':xmlns + 'pos' }
  wordList = awsapw.getWord( eTree, xmlns, extractAttributest )

  # 一語か複数語かの判定
  if len( wordList ) == 1:
   print searchWord, wordList[0]['pos'], "Yahoo!形態素解析辞書に登録済み"
  else :
   print searchWord, "は分解されちゃうよ", 
   for item in wordList:
    print item['surface'], 

 except:
  msg = 'main失敗 %s: %s \n' \
           %(sys.exc_info()[0], sys.exc_info()[1])
  logger.error( msg )


ではでは