2015.5.16
Python関係の記事も増えてきたところで、Twitterのボット的なものを作ってみましょう。今回は圧縮新聞や、しゅうまい、のような一見カオスな文章をつぶやくbotの基礎を構築してみましょう。そのまま使用しても割と面白い結果が得られますのでチャレンジしてみましょう。
以前も登録の仕方は書きましたがおさらいしておきましょう。
上記URLに飛んでTwitterのアカウントでログインします。
Manage Your Appsをクリックして今回製作するbotを登録してAPIキーを取得します。
Name:アプリケーションの名前を考えて入れましょう。
Description:アプリケーションの説明です。
Website:ブログやWebサイトのURLを入力します。
Consumer Key (API Key)、Consumer Secret (API Secret)、Access Token、Access Token Secretを取得すればOKです。この4つのキーは絶対に外部に漏らしてはいけません。アクセスレベルがRead, write, and direct messagesになっていることをちゃんと確認しておきましょう。
今回はTwitter APIを使用してツイートするわけなので、https://api.twitter.com/1.1/statuses/update.jsonを使用します。Twitter APIに関してはどんなものがあるのか公式サイト https://dev.twitter.com/rest/publicから確認しておきましょう。今後色々なアイデアが出てくるかもしれませんよ。
botの仕組みは以下のようにしていきます。
という流れとなります。
ターミナルを起動して必要なモジュールをインストールしていきましょう。まずは認証周りです。
$ pip install requests requests_oauthlib
pipがインストールされていない場合はまずはpip からインストールしておいてください。pipのインストールの仕方は以下。
$ easy_install pip
次に形態素解析を行うMeCabをインストールしましょう。http://mecab.googlecode.com/svn/trunk/mecab/doc/index.html#download
上記URLからダウンロードしてインストールします。細かいインストール方法をいかに記述しておきますので頑張りましょう。
brewが既にインストールされていればbrewをupdateしてbrewからインストールもできます。その場合は以下。
$ brew install mecab
そして辞書のインストール。
$ brew install mecab-ipadic
他の方法は以下を参考。
$ brew install wget $ wget https://mecab.googlecode.com/files/mecab-python-0.996.tar.gz $ pip install mecab-python-0.996.tar.gz
これでモジュール周りのインストールは終了となります。
ではいよいよコードを書いていきましょう。
#!/user/bin/env python # -*- coding: utf-8 -*- from requests_oauthlib import OAuth1Session import json import sys import MeCab import random import re
まずはお約束の2行を記述し、その後に使用するモジュールをインポートします。OAuth1SessionはTwitterの認証周りですね。jsonはTwitterから戻ってくるデータの形式がjsonなのでそのために使用します。sysは文字周りだと考えておけばいいでしょう。MeCabは形態素解析に必要となってきますね。randomモジュールはマルコフ連鎖でテキストを生成するために使用します。reは正規表現のために使用するモジュールとなります。
C_KEY = "*************************************" C_SECRET = "*************************************" A_KEY = "*************************************" A_SECRET = "*************************************"
次にTwitter APIでのキーを記述していきます。本来安全性のために別ファイルに分けるべきなのですが今回はスクリプトの中に組み込んでしまいましょう。Consumer Key (API Key)、Consumer Secret (API Secret)、Access Token、Access Token Secretを順に入れ込んでいきます。
ツイートするためのテキスト収集にhome_timelineを取得してもいいのですが、それではフォローしている人しか拾えません。せっかくなので特定のキーワードだけを拾うように設計してみましょう。
def Search_words(): url = "https://api.twitter.com/1.1/search/tweets.json?" params = { "q": unicode(search_words, "utf-8"), "lang": "ja", "result_type": "recent", "count": "100" } tw = OAuth1Session(C_KEY,C_SECRET,A_KEY,A_SECRET) req = tw.get(url, params = params) tweets = json.loads(req.text) for tweet in tweets["statuses"]: f = open("tweet.txt" , "aw") lists = (tweet["text"].encode("utf-8")) if "http" in lists: lists = lists.split("http", 1)[0] lists = lists.split("@")[0] lists = lists.split("RT")[0] f.write(lists) f.flush() f.close()
Search_wordsという関数を作ってみました。ここではTwitter APIの検索用APIを使用します。ぱっとみて大体わかるでしょうか。保存するテキストにはツイート本文しか必要ないので(tweet[“text”].encode(“utf-8”))としています。この本文にもhttpや@、RTが含まれるので.splitを使用し切り取っていきます。
このスクリプトの同一フォルダ内にtweet.txtという名前で保存をかけます。tweet.txtというファイルが無ければ自動生成、あれば上書きをしていくという仕組みになっています。当然ファイルを開いでいるのでf.flush()でキレイにしてからf.close()で閉じておきます。
最終的にWhileのループでぐるぐる回したいので以下のようになります。
#!/user/bin/env python # -*- coding: utf-8 -*- from requests_oauthlib import OAuth1Session import json import sys import MeCab import random import re while True: search_words = raw_input(u"words: ") C_KEY = "*************************************" C_SECRET = "*************************************" A_KEY = "*************************************" A_SECRET = "*************************************" def Search_words(): url = "https://api.twitter.com/1.1/search/tweets.json?" params = { "q": unicode(search_words, "utf-8"), "lang": "ja", "result_type": "recent", "count": "100" } tw = OAuth1Session(C_KEY,C_SECRET,A_KEY,A_SECRET) req = tw.get(url, params = params) tweets = json.loads(req.text) for tweet in tweets["statuses"]: f = open("tweet.txt" , "aw") lists = (tweet["text"].encode("utf-8")) if "http" in lists: lists = lists.split("http", 1)[0] lists = lists.split("@")[0] lists = lists.split("RT")[0] f.write(lists) f.flush() f.close() if search_words: Search_words() Mecab_file() else: break
さてここからが本題です。先ほど保存したテキストファイルをMeCabに投げて、マルコフ連鎖でテキスト生成をしなければなりません。では一気に行きます。
def Mecab_file(): f = open("tweet.txt","rb") data = f.read() f.close() mt = MeCab.Tagger("-Owakati") wordlist = mt.parse(data) wordlist = wordlist.rstrip(" \n").split(" ") markov = {} w = "" for x in wordlist: if w: if markov.has_key(w): new_list = markov[w] else: new_list =[] new_list.append(x) markov[w] = new_list w = x choice_words = wordlist[0] sentence = "" count = 0 while count < 90: sentence += choice_words choice_words = random.choice(markov[choice_words]) count += 1 sentence = sentence.split(" ", 1)[0] p = re.compile("[!-/:-@[-`{-~]") sus = p.sub("", sentence) words = re.sub(re.compile("[!-~]"),"",sus) twits = words + " 【tweet from twmarkov】"
MeCabで保存したテキストを展開し分かち書きを行います。マルコフ連鎖のためのテーブルを作成し、randomでキーワードをチョイスしリストへほり込んでいきます。英数字の文字列を正規表現で取り除いてツイートするためのテキストを生成し、投稿準備完了。という流れですね。ちょっと説明が簡素すぎますがまぁいいでしょう。
これをTwitterへ投稿しないといけないのでPOST用のスクリプトをくっつけます。
url = "https://api.twitter.com/1.1/statuses/update.json" params = {"status": twits,"lang": "ja"} tw = OAuth1Session(C_KEY,C_SECRET,A_KEY,A_SECRET) req = tw.post(url, params = params) if req.status_code == 200: print "Success! Your Tweet" else: print req.status_code
params = {“status”: twits,”lang”: “ja”}で、先ほど生成したtwits = words + ” 【tweet from twmarkov】”をつぶやくわけです。
では全部を合体させたコードが以下になります。これをターミナルで実行して任意のキーワードを検索しPOSTすることが可能になりました。
#!/user/bin/env python # -*- coding: utf-8 -*- from requests_oauthlib import OAuth1Session import json import sys import MeCab import random import re while True: search_words = raw_input(u"words: ") C_KEY = "*************************************" C_SECRET = "*************************************" A_KEY = "*************************************" A_SECRET = "*************************************" def Search_words(): url = "https://api.twitter.com/1.1/search/tweets.json?" params = { "q": unicode(search_words, "utf-8"), "lang": "ja", "result_type": "recent", "count": "100" } tw = OAuth1Session(C_KEY,C_SECRET,A_KEY,A_SECRET) req = tw.get(url, params = params) tweets = json.loads(req.text) for tweet in tweets["statuses"]: f = open("tweet.txt" , "aw") lists = (tweet["text"].encode("utf-8")) if "http" in lists: lists = lists.split("http", 1)[0] lists = lists.split("@")[0] lists = lists.split("RT")[0] f.write(lists) f.flush() f.close() def Mecab_file(): f = open("tweet.txt","rb") data = f.read() f.close() mt = MeCab.Tagger("-Owakati") wordlist = mt.parse(data) wordlist = wordlist.rstrip(" \n").split(" ") markov = {} w = "" for x in wordlist: if w: if markov.has_key(w): new_list = markov[w] else: new_list =[] new_list.append(x) markov[w] = new_list w = x choice_words = wordlist[0] sentence = "" count = 0 while count < 90: sentence += choice_words choice_words = random.choice(markov[choice_words]) count += 1 sentence = sentence.split(" ", 1)[0] p = re.compile("[!-/:-@[-`{-~]") sus = p.sub("", sentence) words = re.sub(re.compile("[!-~]"),"",sus) twits = words + " 【tweet from twmarkov】" url = "https://api.twitter.com/1.1/statuses/update.json" params = {"status": twits,"lang": "ja"} tw = OAuth1Session(C_KEY,C_SECRET,A_KEY,A_SECRET) req = tw.post(url, params = params) if req.status_code == 200: print "Success! Your Tweet" else: print req.status_code if search_words: Search_words() Mecab_file() else: break
検索文字列を入れ続ける限りはループで回り続ける構造です。while count < 90: のカウント数を変更すれば文字数の調整が可能です。最終的にどれくらいの長さのツイートをするかこの辺りを調整しても面白いと思います。検索したキーワードから保存したツイートの量がある一定を超えたあたりから面白いカオスなツイートが出てくるはずです。 実にシンプルなマルコフテーブルなのでこの辺りをしっかり手を入れてやればしゅうまい、圧縮新聞などのbotが作れるはずです。 後はこのスクリプト自体をcronで叩きに行くとか、そもそも検索せずにストリーミングAPIを使うとか様々な展開が考えられると思います。色々改造して遊んでみましょう。