「Twitterから取得したデータを解析し、mongodbに格納し、Rで分析する」Node.jsアプリケーションを開発するための実験。プロトタイピング。Pragmatic Programmer流儀であれば、曳光弾プログラムでしょうか。
実験の環境
- OSX 10.8.1 Mountain Lion
- node.js 0.8.7
- R 2.13.2
- mongodb 2.0.7
内容
- Twitter開発者登録
- Streaming APIの利用
- P.O.S parts of speech 単語解析
- mongodbへのデータ登録
- Rからmongodbを利用
twitterの開発者登録
TwitterAPIの利用は、OAuthが推奨されている(Basic認証でも今のところは大丈夫だが、いずれダメになる)ので、OAuth認証を行うため、twitterの開発者登録を行い、アプリを登録しなければならない。
Twitter開発サイト Streaming API パラメータの扱い
Twitter開発者アカウント登録の手順
http://ratememo.blog17.fc2.com/blog-entry-967.html
を参考にしました。
- Twitterアカウントを用意する (mailアカウントが必要、既に登録済みのものはダメ)
- http://dev.twitter.com/ に取得したTwitterアカウントで、ログインする
- 「My Applicationの登録」リンクがある
https://dev.twitter.com/apps/new
ので、その画面に移動しアプリを登録 - access level を "read" から "read & write"に変更
- Access Token (Access Token key と Access Token Secret)を取得し、控えておく
ntwitterライブラリを使いstreaming APIへのアクセスをテスト
OAuthのサンプルのほとんどが、ユーザサイドから利用するWebアプリの認証に関するもので混乱。(OAuthの構造を良く理解していない自分が悪い)
今にして思へば、Twitterの開発者登録の時に、取得した"Access Token"は、「自分自身(自分のアプリ)がtwitterAPIにアクセスするための暗号キー」で、アプリを利用するユーザ(consumer)が使用するものではないのです。随分と混乱してます。
結局、ntwitterライブラリのサンプルソースを使う。
twitter API利用Node.jsライブラリ ntwitter
エラーイベントが起きる。調査
前回のサンプルを作った時にはエラー発生しなかったのに。なぜだろう。events.js:68 throw new Error("Uncaught, unspecified 'error' event."); https://github.com/AvianFlu/ntwitter/issues/57
とりあえず、エラーイベントを回避するため、サンプルコードに以下を追加。
- scream.on("error", function(error){
- console.log(arguments);
- });
再度、何度か実行してみると、成功する場合とエラーが返ってくる場合(argumentsを表示している)があるが、理由は不明。Twitter側の問題だろうか?
失敗した場合
$ node sample/ntwitter_sample.js { '0': 'http', '1': 401 }
P.O.S moduleを組み込んで実行してみた結果
英語専用の形態要素分析 "part-of-speach POS Tagging"のライブラリpos-jsを使い、単語の分解と品詞のタグ付けを試みる。POS Taggingとpos-jsライブラリについては、以前 記事を書いたので見ていただけますと幸いです。
http://tech-baker.blogspot.jp/2012/06/part-of-speech-tagging.html
ここまでのプログラムソースは、以下の通り。
- var twitter = require('ntwitter'); // twitter API用ライブラリ
- // Twitter開発者登録の結果
- var twit = new twitter({
- consumer_key : 'xxxxxxxxxxxxxxxxxxxx',
- consumer_secret : 'xxxxxxxxxxxxxxxxxxxx',
- access_token_key : 'xxxxxxxxxxxxxxxxxxxx',
- access_token_secret : 'xxxxxxxxxxxxxxxxxxxx'
- });
- var pos = require('pos'); // POS Tagging用ライブラリ
- // 検索キーは、とりあえず appleで :-p
- twit.stream('statuses/filter', {'track':'apple'}, function(stream) {
- stream.on('data', function(data) {
- // この行は日本語を省くため 結構いい加減
- if(data.text.toLowerCase().indexOf('apple') > 0){
- console.log(data.text); // オリジナルを表示
- var words = new pos.Lexer().lex(data.text); // 単語分解
- var taggedWords = new pos.Tagger().tag(words); // 品詞のタグ付け jsonで返す
- for(i in taggedWords){
- var taggedWord = taggedWords[i];
- var word = taggedWord[0];
- var tag = taggedWord[1];
- console.log(word + " : " + tag);
- }
- }
- });
- stream.on('end', function(response){
- //console.log('');
- });
- stream.on('destroy', function(response){
- //console.log('');
- });
- // エラーイベント対処
- stream.on('error', function(error){
- console.log(arguments);
- });
- // 5000ミリ秒で終了イベントを発生させた。これをしないと何時までのTwitterからのpushを受け続ける
- setTimeout(stream.destroy, 5000);
- });
実行してみると
$ node sample/s_api_with_pos.js (途中省略) @WhipeeDip One fifty and Apple will hand you a new phone. Though that thing is probably pushing “catastrophic damage ineligible for swap.” @WhipeeDip : NN One : NN fifty : NN and : CC Apple : NNP will : MD hand : NN you : PRP a : DT new : JJ phone : NN . : . Though : IN that : IN thing : VBG is : VBZ probably : RB pushing : VBG “catastrophic : NN damage : NN ineligible : JJ for : IN swap : NN . : . ” : NN
形態要素分析結果をmongodbに保存する
Node.js用のmongodb接続ライブラリ mongooseをインストールする。 # npm install mongoose
一発。
mongooseの使い方については、いずれまとめたいと思います。以下のサイトを参考にしました。
node.js + mongoose + mongodbで遊ぶ
上記のプログラムを改造して、mongodbに登録を行うように改造してみる。出来たプログラムを動かしてみると?
- 終了しない。プログラムが。
- でも、保存されたもよう。
mongodbのクライアントアプリ mongoで直接データを覗いてみます。
$ mongo MongoDB shell version: 2.0.7 connecting to: test > show dbs local (empty) posdb 0.203125GB test (empty) > use posdb switched to db posdb > show collections postags system.indexes > db.postags.find() { "word" : "@PissWizardCunt", "tag" : "NN", "_id" : ObjectId("50557db5da8a0357b8000001"), "__v" : 0 } { "word" : "not", "tag" : "RB", "_id" : ObjectId("50557db5da8a0357b8000006"), "__v" : 0 } (途中省略) { "word" : "5", "tag" : "CD", "_id" : ObjectId("50557db5da8a0357b800005b"), "__v" : 0 } { "word" : ".", "tag" : ".", "_id" : ObjectId("50557db5da8a0357b8000060"), "__v" : 0 } has more > exit bye
has more が表示されているけど、残りのデータは、どのように表示させたら良いのかな?
- // (途中まで同じ)
- var pos = require('pos'); // POS Taggingライブラリを呼び出す
- var mongoose = require('mongoose'); // mongodb接続用ライブラリを呼び出す
- // スキーマの定義 mongooseは、ORMのように振る舞う。modelを定義する訳ですね。
- var Schema = mongoose.Schema;
- var PosSchema = new Schema({
- tag: String,
- word: String
- });
- mongoose.model('PosTag', PosSchema);
- // 接続
- mongoose.connect('mongodb://localhost/posdb');
- var PosTag = mongoose.model('PosTag');
- twit.stream('statuses/filter', {'track':'apple'}, function(stream) {
- // TwitterからTweetを取得し
- stream.on('data', function(data) {
- if(data.text.toLowerCase().indexOf('apple') > 0){ // 日本語は省き
- var words = new pos.Lexer().lex(data.text); // 単語に分解し
- var taggedWords = new pos.Tagger().tag(words); // 品詞タグをつけ
- for(i in taggedWords){
- var postag = new PosTag(); // 新規レコードを用意?
- postag.tag = taggedWord[1]; // 値をセット
- postag.word = taggedWord[0]; // 値をセット
- postag.save(function(err){ // 登録エラー処理
- if(err){ console.log(err);}
- });
- }
- }
- });
- // (後半省略)
- });
統計解析環境Rからmongodbのデータを呼び出す
OSXはパッケージを本家からダウンロードして使っている。
mongodb接続ライブラリrmongodbをインストールするため、
- メニューのパッケージインストーラを起動
- ダウンロード先のミラーサイトを指定し
- rmongodb を検索し、インストール
httpdヘルプサーバーを起動... 完了 URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.13/rmongodb_1.0.2.tgz' を試しています Content type 'application/x-gzip' length 733855 bytes (716 Kb) 開かれた URL ================================================== downloaded 716 Kb ダウンロードされたパッケージは、以下にあります /var/folders/cw/qznw_j_1313d3stpq5zc34240000gn/T//RtmpAbXBrm/downloaded_packages console画面から、rmongodbを読み込んでみて、テストしてみる。 > library(rmongodb) rmongodb package (mongo-r-driver) loaded Use 'help("mongo")' to get started.
うまく、rmongodbライブラリはインストールされたので、恐る恐るtwitterデータを確認してみる。
保存されているデータの構成(私の現在のdb, collection構成)
--------- ------------ database collections --------- ------------ posdb ------> postags test (empty) local(empty)
$ r R version 2.13.2 (2011-09-30) Copyright (C) 2011 The R Foundation for Statistical Computing ISBN 3-900051-07-0 Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit) (途中省略) > library(rmongodb) rmongodb package (mongo-r-driver) loaded Use 'help("mongo")' to get started. > db <- mongo.create() > mongo.find.one(db,'posdb.postags') word : 2 @PissWizardCunt tag : 2 NN _id : 7 50557db5da8a0357b8000001 __v : 16 0 > mongo.find.one(db, 'posdb.postags', list(tag='NN')) word : 2 @PissWizardCunt tag : 2 NN _id : 7 50557db5da8a0357b8000001 __v : 16 0 > mongo.find.one(db, 'posdb.postags', list(tag='CD')) word : 2 13 tag : 2 CD _id : 7 50557db5da8a0357b800001a __v : 16 0 > mongo.find.one(db, 'posdb.postags', list(tag='RB')) word : 2 not tag : 2 RB _id : 7 50557db5da8a0357b8000006 __v : 16 0 > quit() Save workspace image? [y/n/c]: n
無事、データをRで処理することが出来るところまで、たどり着きました。今回の実験は終了。