はてなキーワードしりとりを改造

先日掲載していたはてなキーワードしりとりをコメントで教えていただいた内容を参考に改造しました。

一度問い合わせた単語を従来は2つのリストで管理していましたが辞書で行うように変更しました。さらにはてなキーワードAPIへのアクセスやXMLの解析を行う関数を廃止し、この辞書のメソッドにして問い合わせ済みかどうかのチェックと一括して行うようにしました。

# coding: utf-8

import urllib
import urllib2
from xml.dom.minidom import parse

def input_reader(text):
    """入力を受け取ってunicodeオブジェクトにして返す"""
    
    word = raw_input(text)
    
    return unicode(word, "utf-8")

class AskedWords(dict):
    """APIへの問い合わせと結果の管理を一括して担う"""
    
    def __init__(self):
        dict.__init__(self)
    
    def _ask_hatena(self, word):
        """word_checkから呼ばれてはてなキーワードAPIにwordを問い合わせる"""
        #URLエンコード
        encoded_word = urllib.quote(word.encode("utf-8"))
        
        #URLを作成
        requestURL = ("http://search.hatena.ne.jp/keyword?word="
                       + encoded_word
                       + "&mode=rss&ie=utf8&page=1")
        
        return urllib2.urlopen(requestURL, None)
    
    def word_check(self, word, turn):
        """wordがはてなキーワードに登録されているか確認する
           はてなキーワードに存在すればそのfuriganaタグの内容を返す
           存在しなければNoneを返す
           問い合わせでエラーが発生した場合にはFalseを返す
        """
        if word in self.keys(): # すでに問い合わせたことがある単語はここで弾く
            return self[word]

        try:
            dom = parse(self._ask_hatena(word))
        except:
            self[word] = False
            return False
        
        items = dom.getElementsByTagName("item")
        hatenaNS = "http://www.hatena.ne.jp/info/xmlns#" #XMLのNS
    
        if items and (items[0].getElementsByTagName("title"))[0].firstChild.data == word:
            self[word] = turn
            return (items[0].getElementsByTagNameNS(hatenaNS, "furigana"))[0].firstChild.data
        else:
            self[word] = None
            return None
    
    

def main():
    asked_words = AskedWords()
    turn = 1
    initial = u"は" #しりとりの最初の文字
    
    print (u"最初のもじは「" + initial + u"」です")
    
    while True:
        wordU = input_reader(u"次の単語を入力してください。次は" + str(turn) + u"語目です。")
        
        furigana = asked_words.word_check(wordU, turn)
        
        if furigana is None:
            print u"この単語ははてなキーワードに登録されていませんでした。"
            continue
        
        if furigana is False:
            print u"xmlデータを正しく受信できませんでした。他の単語を試してください。"
            continue
        
        if isinstance(furigana, int):
            print u"その単語は" + str(furigana) + u"番目に使いました。"
            continue
        
        if not furigana.startswith(initial):
            print u"次の文字は「" + initial + u"」です!"
            continue
        
        if furigana.endswith(u"ん"):
            print u"「ん」がついたよ。"
            break
        
        print wordU
        
        if furigana.endswith(u"ー"):
            initial = furigana[-2:-1]
        else:
            initial = furigana[-1:]
        
        toRep = {u"ゃ":u"や",u"ゅ":u"ゆ",u"ょ":u"よ",u"を":u"お",u"っ":u"つ"}
        
        if initial in toRep.keys():
            initial = toRep[initial]
        
        turn += 1
    
    print u"終了です"

if __name__ == "__main__":

仮に

最初のもじは「は」です
次の単語を入力してください。次は1語目です。はてなブックマーク
はてなブックマーク
次の単語を入力してください。次は2語目です。熊
xmlデータを正しく受信できませんでした。他の単語を試してください。
次の単語を入力してください。次は2語目です。車
この単語ははてなキーワードに登録されていませんでした。
次の単語を入力してください。次は2語目です。孔雀
孔雀
次の単語を入力してください。次は3語目です。鯨
この単語ははてなキーワードに登録されていませんでした。
次の単語を入力してください。次は3語目です。クローン
「ん」がついたよ。
終了です

と実行したとするとasked_words辞書の内容は

{u"はてなブックマーク":1, u"熊":False, u"車":None, u"孔雀":2, u"鯨":None}

となっています。