モテる! Node.js でつくる twitter ボット制作
-
Upload
hecomi -
Category
Technology
-
view
6.688 -
download
2
description
Transcript of モテる! Node.js でつくる twitter ボット制作
モテる! Node.js でつくる Twitter ボット制作
Presented by @hecomi
X
はじめに
introduction
/ ̄ ̄ ̄ ̄ ̄ ̄\ / \ _______ / / \| .′ j/ ,. -―――‐- ., 〉 / j|:..//-∠、. . . . . /--. \{ 〈_/上|. / o \/∨ o V/庁=、 \ |/ ┌──── ┐ ∨ソ/ )、_;,. ! | ;_/ ⌒ 介:. 、 ____,,ノイ{ ⌒7⌒\/\/\'⌒ ,′ V/, ○∨ ∧ j__,V/○ j ′〉 {___,ノ 人__ク _,ノ\冖┘ へ. └冖 \_ {丈____\/-―-\/___丈}
___________ / \< のぉどじぇーえすって |
| なにするです? | \___________/
__ ,... -―――‐/ \ー- 、 __ ./: : : : : : : : : :/ \__/ .‘,
/: : ,---- ̄ ̄ ____ .‘,
/: : : : | ., - ´ ,. -,l .\ ‘,__
/: : : : : : :.| / ⌒ l____丿.⌒ヽ /
/: : : : : : :/ ./ | ./
/: : : : : :/ ./l o .__ o ∨
./: : : : : :‘, ./.ヽ ____|___|___ .|
.,: : : : : : : :‘, _ -ー´ | | .|
l: : : : : : : : / .| | |
|: : : : : : : :\ ヽ / ./
|: : : ._------|ー‐―-、 _ .\______//
|: :/  ̄ ̄ヽ _>ー――――‐ ´ |/  ̄/: :|__\ <> |ヽ
/: : : : : : └-\/.人
.|: : : :/: : : : : : : : : : : :‘,
\:/: : : : : : : : : :○: : :‘,
/: : : : : : : : : : : : : : : :‘,
〈: : : : : : : : : : : : : : : : : : |
`ー-...._: : : : : : : /l: :_/
.‘,: : :`ー---/ : ̄/
‘,: : : : : :./: : : /
.‘,: : : : / : /
l ̄ ̄〉 ̄〉
 ̄ ̄ ̄ ̄
___________ / \< さーばさいどでじゃば |
| すくりぷとじっこうしたり? | \___________/
/ .:::::::::::::::::::::::::::::::::::::::::::::.\ /.:::::::::::::: ´ ̄ ̄ ̄ ̄` 、:::::.\ / .::::::::::::/ ____ \:::::::| ___/ .:::::::::::::∨ / \. . . . /^\ \,′ \:::::::::::::::::::::::| // '⌒ |/∨ ⌒ |\__〉 ` ――r┴‐| / o o│./┴┐ \⌒′ r――――┐ レ' / >ヘ | │ ,< ^⌒T>乂__ ...ノ イ⌒^ ∠ニ=干‐ 厂}‐r‐厂} { . . . │ |=イ.│|=イ _,,..ノ\ . .│ | 八 |│/ /. . . . . . \_|_j,′.〉 ̄ \ . . . . . . . . . . . (__)ヘ {\. . . . . . . . . . ∧. . 〉 、::\___/::::}/ \::::::::::::::::::::,′:/ \::::::::::::/.::::,′ {三三}ニニ} {___┐┐
___________ / \< よくわからないので |
| おことわりするです | \___________/
本発表について
• となってる人が多いと思うので…
• 実際に Node.js 環境を構築して、その上で Twitter ボットを動かしてみます。
– おうむ返しボット、特定のキーワードに反応するボット、人工無能ボットから、一歩進んで形態素解析ボットを紹介します。
のぉどじぇーえす?
introduction
Node.js?
• http://nodejs.jp/• サーバサイドで JavaScript を実行
– エンジンは v8
何が出来るの?
• ブラウザの JavaScript で出来なそうなことがサーバ上で出来ます
何が出来るの?
• ブラウザの JavaScript で出来なそうなことがサーバ上で出来ます
– ファイル操作とか
var fs = require('fs');fs.writeFile('log.txt', ‘Hello, world!', function(err) { if (err) throw err; console.log('Success!');});
何が出来るの?
• ブラウザの JavaScript で出来なそうなことがサーバ上で出来ます
– http サーバ立てたりとか
var http = require('http'); http.createServer(function(req, res) { res.writeHead( 200, {'Content-Type': 'text/plain'} ); res.write('Hello, world!\n'); res.end();}).listen(3000);
何が出来るの?
• ブラウザの JavaScript で出来なそうなことがサーバ上で出来ます
– http サーバ立てたりとか
var http = require('http'); http.createServer(function(req, res) { res.writeHead( 200, {'Content-Type': 'text/plain'} ); res.write('Hello, world!'); res.end();}).listen(3000);
いんすとーる
install
インストールしよう
• Windows 環境下(http://nodejs.org/)
クリックしてインストールするだけ
インストールしよう
• Mac / Linux 環境下
– バージョン管理も含めて nave がオススメ
• https://github.com/isaacs/nave
インストールしよう
• node.js と npm のインストール
• ちなみに結構コンパイル時間かかります
• 参考– naveを使ったnode.jsインストールと、最近のnpmの使い方 - ラシウラ
– http://d.hatena.ne.jp/bellbind/20110530/1306764093
$ mkdir ~/.nave$ cd ~/.nave$ git clone git://github.com/isaacs/nave.git$ ~/.nave/nave/nave.sh use latest $$ curl https://npmjs.org/install.sh | sh
インストールしよう
• インストールされたか確認
– Windows の人はコマンドプロンプト上で
• これで OK!
$ node –vv0.8.9$ npm –vV1.1.61
はろーわーるど
Hello, world!
対話コンソール
$ node> console.log('Hello, world!'); // これを打つHello, world!undefined> (Ctrl+D 押下)$
ファイル
$ cat helloworld.jsconsole.log('Hello, world!');$ node helloworld.jsHello, world!
おまけ:ブラウザ
$ node helloworld
// helloworld.jsvar http = require('http'); http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.write('Hello, world!\n'); res.end();}).listen(3000);
ついったーぼっとせいさく
Make twitter bot!
Consumer Key / Access Token
1. 適当な Twitter アカウントを作成
2. Twitter の開発者サイトより1. Consumer Key / Consumer Secret2. Access Token / Access Token Secret
を取得する※
• ※参考:– twitterアクセストークンなどの取得方法(WordPress更新通知用)
– http://musilog.net/webdesign/my-works/twitter-oauth-wp-to-twitter.php
開発者サイト:https://dev.twitter.com/
Twitter モジュール導入
• npm でインストール$ mkdir twitter_bot$ cd twitter_bot$ npm install twitternpm http GET https://registry.npmjs.org/twitternpm http 200 https://registry.npmjs.org/twitternpm http GET https://registry.npmjs.org/twitter/-/twitter-0.1.18.tgznpm http 200 https://registry.npmjs.org/twitter/-/twitter-0.1.18.tgz…(ry
• 依存関係も含めて必要なモジュールをインストールしてくれます
npm
• npm は node package manager の略
• package 数は 15006 個!(2012/09/22 現在)
• 使い方
– npm install hoge• 実行したディレクトリ下に node_modules ディレクトリを作成してそこにモジュールを展開
• 実行したディレクトリ下のみで使用できる
– npm install -g hoge• どのディレクトリからでも使える
Twitter で はろーわーるど
• 早速使ってみましょう!
var twitter = require('twitter');
var bot = new twitter({ consumer_key : 'xxxxxxxxxx', consumer_secret : 'xxxxxxxxxx', access_token_key : 'xxxxxxxxxx', access_token_secret : 'xxxxxxxxxx'});
bot.updateStatus('Hello, world!', function (data) { console.log(data);});
モジュールのロード
さきほど取得した
各キーを入力
つぶやいたら呼ばれる
コールバック関数。
data には Twitter から
返ってきた JSON が
入っている。
Twitter に Hello, world!
とつぶやく。
結果$ node twitter{ entities: { hashtags: [], user_mentions: [], urls: [] }, retweet_count: 0, id_str: '249420311064358913', place: null, in_reply_to_user_id: null, favorited: false, in_reply_to_status_id_str: null, coordinates: null, created_at: 'Sat Sep 22 08:10:10 +0000 2012', in_reply_to_user_id_str: null, contributors: null, user:…(ry
Streaming API を利用
bot.stream('user', function(stream) { stream.on('data', function(data) { console.log(data); // ズラーッと TL の情報が表示される });�});
• twitter モジュールの説明:
– https://github.com/jdub/node-twitter
• stream 接続
※ ローカル環境の Linux 機で試してみると $ node bot とコマンドを実行してもすぐ終了してしまう場合があります。原因は分かる方いらっしゃいましたら @hecomi まで教えて下さい m(_ _)m
色んなボットを作ってみよう!
• 例として3つ紹介します
– おうむ返しボット
– 特定のキーワードに反応するヤツ
– 人工無脳
おうむ返しボット
var BOT_ID = 'hecomiroid';bot.stream('user', function(stream) { stream.on('data', function(data) { if ( !('text' in data) ) { console.error('[ERROR] invalid data'); return; } var twUserId = data.user.screen_name , replyStr = data.text.replace(new RegExp('^@' + BOT_ID + ' '), '') , isMention = (data.in_reply_to_user_id !== null) ; if (!isMention || twUserId === BOT_ID) return; bot.updateStatus('@' + id + ' ' + text, function (data) { console.log(data); }); });});
Streamin API 接続直後はfollowing ID 一覧が降ってきたりするので、そういったゴミを除外。
@の部分を除去
他人から自分へのつぶやき以外は除外
この ID をミスるとループしまくるので注意!
特定のキーワードに反応するヤツ
var BOT_ID = 'hecomiroid';bot.stream('user', { track: 'Vim' }, function(stream) { stream.on('data', function(data) { if ( !('text' in data) ) { console.error('[ERROR] invalid data'); return; } if (data.user.screen_name === BOT_ID) return; var twStr = data.user.name + 'さんが、"' + data.text + '"って呟いた'; bot.updateStatus(twStr, function (data) { console.log(data); }); });});
自分の TL に加えて、検索ワードを追加できる
人工無脳var printf = require('printf'); // npm install printfvar BOT_ID = 'hecomiroid';var replyMap = {
'こんにち(は|わ)' : 'ちょりーっす!','おやすみ(なさい)?' : 'いい夢見ろよ','うー' : '(」・ω・)」うー!(/・ω・)/にゃー!','(.*?)なう' : '%sするのが許されるのは小学生までだよねー!'
};
bot.stream('user', function(stream) { stream.on('data', function(data) { if ( !('text' in data) ) { console.error('[ERROR] invalid data'); return; } if (data.user.screen_name === BOT_ID) return; for (var regex in replyMap) { if ( new RegExp(regex).test(data.text) ) { var replyStr = printf(replyMap[regex], RegExp.$1); var tweetStr = printf('@%s %s', data.user.screen_name, replyStr); bot.updateStatus(tweetStr, function (data) { console.log(data); }); return; } }});
キーワードと返信する文章を
正規表現で書いて
引っ掛かったら返事をつぶやく
できた!
• というわけで Twitter ボットが出来ました。
• 最後に、もう一歩進んだボット制作を紹介して終わりにします。
もういっぽふみこんでみる
Make more interesting bot!
もっと色々やりたい
• 色んな(JavaScriptには無い)プログラムやライブラリと連携してもっと面白いことをつぶやかせたい、と思いませんか?
もっと色々やりたい
• 色んな(JavaScriptには無い)プログラムやライブラリと連携してもっと面白いことをつぶやかせたい、と思いませんか?
• それ、簡単にできます!
もっと色々やりたい
• 色んな(JavaScriptには無い)プログラムやライブラリと連携してもっと面白いことをつぶやかせたい、と思いませんか?
• それ、簡単にできます!
• 例として MeCab を使った形態素解析ボットを作ってみようと思います。
• 簡単な方法と大変な方法の2つを紹介します。
MeCab のインストール
• MeCab: Yet Another Part-of-Speech and Morphological Analyzer– http://mecab.googlecode.com/svn/trunk/mecab/doc/index.html#download
• Windows ならインストーラ– インストール後は環境変数へ登録
• mac なら– brew install mecab mecab-ipadic
• Linux なら– sudo aptitude install mecab mecab-ipadic-utf8
① 簡単な方法
• コンソール上で実行して結果をパース
var exec = require('child_process').exec;
exec('ls', function(err, stdout, stderr) { console.log(stdout); });
• こんな風にコマンドの実行結果を文字列で受け取ることができますので、後はパースすれば OK です。
MeCab の結果をパースvar exec = require('child_process').exec , fs = require('fs') , TMP_TXT_FILE_NAME = '__tmp__.txt';
function parse(str, callback) { fs.writeFile(TMP_TXT_FILE_NAME, str, function(err) { if (err) callback(err, null); exec('mecab ' + TMP_TXT_FILE_NAME, function(err, stdout, stderr) { if (err) callback(err, null); var mecabResultArr = [] , mecabResultStr = stdout.split('\n') ; for (var i in mecabResultStr) { var wordInfoArr = []; if (mecabResultStr[i].indexOf('EOS') === 0) break; /([^\s]+)\s+([^\s]+)/.test(mecabResultStr[i]); wordInfoArr.push(RegExp.$1); wordInfoArr = wordInfoArr.concat(RegExp.$2.split(',')); mecabResultArr.push(wordInfoArr); } exec('rm ' + TMP_TXT_FILE_NAME, function(err, stdout, stderr) { if (err) callback(err, null); callback(null, mecabResultArr); }); }); });}
parse('すもももももももものうち', function(err, result) { console.log(result); });
一時ファイルを削除
MeCab を実行して
結果をパースする
解析する文章を
一時ファイルに書き出す
(ちなみに echo ‘hogehoge’ | mecab を利用しても OK です。ファイルに 一時書きだしたのは windows 環境 での文字化けを避けているからです)
結果
$ node mecab[ [ 'すもも', '名詞', '一般', '*', '*', '*', '*', 'すもも', 'スモモ', 'スモモ' ], [ 'も', '助詞', '係助詞', '*', '*', '*', '*', 'も', 'モ', 'モ' ], [ 'もも', '名詞', '一般', '*', '*', '*', '*', 'もも', 'モモ', 'モモ' ], [ 'も', '助詞', '係助詞', '*', '*', '*', '*', 'も', 'モ', 'モ' ], [ 'もも', '名詞', '一般', '*', '*', '*', '*', 'もも', 'モモ', 'モモ' ], [ 'の', '助詞', '連体化', '*', '*', '*', '*', 'の', 'ノ', 'ノ' ], [ 'うち', '名詞', '非自立', '副詞可能', '*', '*', '*', 'うち', 'ウチ', 'ウチ'] ]
別の JS から使えるようにするvar exec = require('child_process').exec , fs = require('fs') , TMP_TXT_FILE_NAME = '__tmp__.txt';
module.exports = function(str, callback) { fs.writeFile(TMP_TXT_FILE_NAME, str, function(err) { if (err) callback(err, null); exec('mecab ' + TMP_TXT_FILE_NAME, function(err, stdout, stderr) { if (err) callback(err, null); var mecabResultArr = [] , mecabResultStr = stdout.split('\n') ; for (var i in mecabResultStr) { var wordInfoArr = []; if (mecabResultStr[i].indexOf('EOS') === 0) break; /([^\s]+)\s+([^\s]+)/.test(mecabResultStr[i]); wordInfoArr.push(RegExp.$1); wordInfoArr = wordInfoArr.concat(RegExp.$2.split(',')); mecabResultArr.push(wordInfoArr); } exec('rm ' + TMP_TXT_FILE_NAME, function(err, stdout, stderr) { if (err) callback(err, null); callback(null, mecabResultArr); }); }); });}
module.exports すると別のファイルからこの関数を使えるようになる
別の JS から使う
var parse = require('./parse.js');
parse('すもももももももものうち', function(err, result) { console.log(result);});
形態素分析ボット(おうむ返しボットを改造)
parse(mentionStr, function(err, mecabResult) { var replyStr = ''; mecabResult.forEach(function(wordInfoArr) { replyStr += printf('%s[%s] ', wordInfoArr[0], wordInfoArr[1]); }); var tweetStr = printf('@%s %s', data.user.screen_name, replyStr); bot.updateStatus(tweetStr, function (data) { console.log(data); });});
• つぶやく部分を以下のように変更すると形態素解析ボットが出来ます
② 大変な方法
• C/C++ でモジュールを書く
– 面倒ですが作れば速いです
• v8 のお作法に従って書けばOK
• 詳しく解説しようとすると時間足りないので、詳細は以下をご参照下さい m(_ _)m
• node.js の mecab addon 作った - 凹みTips※
– http://d.hatena.ne.jp/hecomi/20120611/1339347112※ ここでは node-waf をコンパイルツールとして使っていますが、最近は node-gyp に置き換わったみたいです。
おわりに
Summary
まとめ
• Node.js の環境を整えました
• Twitter に呟くボットを作ってみました
• 一歩踏み込んだ処理をするボットを作ってみました
おまけ
Appendix
おまけ - ネストを浅く
• 非同期処理を繰り返すとネストがどんどん深くなっていきます
var exec = require('child_process').exec;
exec('echo hoge', function(err, stdout, stderr) { console.log(stdout); exec('echo fuga', function(err, stdout, stderr) { console.log(stdout); exec('echo piyo', function(err, stdout, stderr) { console.log(stdout); }); });});
• これを解決する方法は色々ありますが、async.js あたりがおすすめです。
おまけ - ネストを浅くvar exec = require('child_process').exec , async = require('async');
async.series([ function(next) { exec('echo hoge', function(err, stdout, stderr) { console.log(stdout); next(null); }); }, function(next) { exec('echo fuga', function(err, stdout, stderr) { console.log(stdout); next(null); }); }, function(next) { exec('echo piyo', function(err, stdout, stderr) { console.log(stdout); next(null); }); }]);
おまけ - ネストを浅く
• async.js には他にもパラで処理したり、引数を次々と渡して行ったりと色んなパターンで書けます。
• 参考:
– async.jsでフロー制御 - すぎゃーんメモ
– http://d.hatena.ne.jp/sugyan/20110605/1307240191
おまけ - ネストを浅く
• 非同期処理を繰り返すとネストがどんどん深くなっていきます
var exec = require('child_process').exec;
exec('echo hoge', function(err, stdout, stderr) { console.log(stdout); exec('echo fuga', function(err, stdout, stderr) { console.log(stdout); exec('echo piyo', function(err, stdout, stderr) { console.log(stdout); }); });});
• これを解決する方法は色々ありますが、async.js あたりがおすすめです。
おまけ - 例外処理
• 例外が処理されないと Node.js は…
おまけ - 例外処理
• 例外が処理されないと Node.js は…
_人人人人人人_> 突然の死 < ̄^Y^Y^Y^Y^Y^ ̄します。
おまけ - 例外処理
• なので以下のようなコードで例外を補足して処理してあげます。
process.on('uncaughtException', function (err) { console.log('uncaughtException => ' + err);});
• 参考– node.jsの最低限の例外処理 - motsatのブログ
– http://d.hatena.ne.jp/bellbind/20110530/1306764093
おわり
end