GAEでTwitterのツイートを圧縮新聞っぽくまとめてみる(2)
GAEでTwitterのツイートを圧縮新聞っぽくまとめてみる(1)という記事を書いたのですが、その続きです。
「圧縮新聞」を作ったを見ると、どうも品詞情報などは全く使っていないようなので、Yahoo! 形態素解析サービスで分割だけして、あとのロジックはそのまま使わせていただきました。
ソースコードはこんな感じ。
# -*- coding: utf-8 -*- import os import random from urllib import urlencode from google.appengine.ext.webapp import template from google.appengine.ext import webapp from google.appengine.api import urlfetch from django.utils import simplejson from BeautifulSoup import BeautifulStoneSoup # ユーザのツイートを圧縮する class Asshukutter(webapp.RequestHandler): def get(self): # リクエストを取得 user = self.request.params['user'] # twitterアカウントが入る # 形態素解析したユーザのツイートを取得 dic = self.segmentMorpheme(user) # 圧縮結果を取得 result = self.asshuku(dic) # ちゃんとした結果が得られなかったら得られるまで while result == "。".decode('utf_8'): result = self.asshuku(dic) data = {'result' : result.rstrip("。".decode('utf_8'))} path = os.path.join(os.path.dirname(__file__), '../html/index.html') self.response.out.write(template.render(path, data)) # ツイートを圧縮する def asshuku(self, dic): result = "" i = 0 punctuation = "。".decode('utf_8') # 木構造を繋げていく preSeg = dic[punctuation][random.randint(0,len(dic[punctuation])-1)] result = result + preSeg # 「。」が出てくるまで繋げる while preSeg != punctuation: i = i + 1 nextSeg = dic[preSeg][random.randint(0,len(dic[preSeg])-1)] result = result + nextSeg preSeg = nextSeg if i == 100: preSeg = punctuation return result # Yahoo! 形態素解析サービスを使って、ユーザのツイートを形態素で分割する def segmentMorpheme(self, user): dic = {} # ユーザのツイートを取得 tweets = self.searchUserTweet(user) # ツイートごとに形態素解析を行う for t in tweets: urlResult = urlfetch.fetch('http://jlp.yahooapis.jp/MAService/V1/parse', method=urlfetch.POST, headers={'Content-Type':'application/x-www-form-urlencoded'}, payload=urlencode({ 'appid': 'アプリケーションID', 'sentence' : t.encode('utf-8')})) # BeautifulStoneSoupを使って結果のxmlをパースする soup = BeautifulStoneSoup(urlResult.content.decode('utf_8')) preMorpheme = "。".decode('utf_8') flag = False for morpheme in soup('surface'): # 英数字のみからなる文字列を除外 if not morpheme.renderContents().isalnum() and not flag: nowMorpheme = morpheme.renderContents().decode('utf_8') # 木構造を作成 if dic.has_key(preMorpheme): dic[preMorpheme].append(nowMorpheme) else: dic[preMorpheme] = [nowMorpheme] preMorpheme = nowMorpheme # 英数字直後の形態素は除外 elif not morpheme.renderContents().isalnum() and flag: flag = False else: flag = True return dic # Twitter APIのuser_timelineを使ってユーザのツイートを取得する def searchUserTweet(self, user): text = [] preText = "" num = 0 # 入力したユーザ名をクエリとするURL url = "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=" + user urlresult = urlfetch.fetch(url) if urlresult.status_code == 200: # 結果をsimplejsonを使ってパース jsonload = simplejson.loads(urlresult.content) for result in jsonload: num = num + 1 if num % 7 == 0: preText = preText + result['text'] + "。".decode('utf_8') text.append(preText) preText = "" else: preText = preText + result['text'] + "。".decode('utf_8') text.append(preText) else: text.append("存在しないか非公開なアカウントです。".decode('utf_8')) return text
Twitter APIのuser_timelineを使ってユーザのツイートを取得し、それをYahoo! APIの形態素解析にかけ、それを圧縮新聞と同様にマルコフ連鎖で繋げていきます。
Yahoo!の形態素解析は、1リクエストの最大サイズが100KBなので、ツイートを3分割くらいにしてます。
マルコフ連鎖を実現するために、ある形態素をキー、その後ろにくる形態素のリストをバリューをするディクショナリを作成します。
なので、形態素解析にかけ、連続した形態素の、前の形態素をディクショナリのキー、後ろの形態素をディクショナリのバリューのリストに挿入します。
あとはランダムに繋げていきます。
圧縮新聞は4単語を繋げてますが、これは2単語を繋げていきます。
リンクの文字列が結構やっかいで英数字を無視してしまっているんですが、そのためかエラーが出ます。
まぁ出来れば整形して載せます。
一応、作ったものは → 圧縮ったー
while文動きっぱが怖いので上のソースちょっといじって運用してます。
マルコフ連鎖に品詞情報付与したら精度良くなる気がするけど、そうでもないのかな…。