ソースコード
前回と同じくソースコードを公開します.
ツッコミなどをコメントに書いていただけたら感激ですd(・・
/*! * \file main.cpp */ #include <iostream> using namespace std; #include "./twitterStreaming.hpp" #define CR 13 #define LF 10 void *myrealloc(void *ptr, size_t size) { /* There might be a realloc() out there that doesn't like reallocing NULL pointers, so we take care of it here */ if(ptr) return realloc(ptr, size); else return malloc(size); } size_t curlCallback(void *ptr, size_t size, size_t nmemb, TwttrStrm::twitter &twitter) { size_t realsize = size * nmemb; twitter.mp_responseBuffer = (char *)myrealloc(twitter.mp_responseBuffer, twitter.m_responseSize+realsize+1); if (twitter.mp_responseBuffer) { memcpy(&(twitter.mp_responseBuffer[twitter.m_responseSize]), ptr, realsize); twitter.m_responseSize += realsize; twitter.mp_responseBuffer[twitter.m_responseSize] = '\0'; } if (CR == twitter.mp_responseBuffer[twitter.m_responseSize-2] && LF == twitter.mp_responseBuffer[twitter.m_responseSize-1]) // Tweet を一つ受け取りきったら入る { if (!twitter.loadJson()) { exit(0); } } return realsize; } int main(int argc, char **argv) { using namespace TwttrStrm; twitter twttr; // cURL CURL *curl_handle; CURLcode res; curl_handle = curl_easy_init(); // Twitter ログイン curl_easy_setopt(curl_handle, CURLOPT_PROXY, "192.168.0.1:8080"); curl_easy_setopt(curl_handle, CURLOPT_PROXYUSERPWD, "PROXY_USER_NAME:PROXY_PASSWORD"); curl_easy_setopt(curl_handle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); curl_easy_setopt(curl_handle, CURLOPT_USERPWD, "TWITTER_ID:TWITTER_PASSWORD"); // babel babel::init_babel(); if(curl_handle) { //curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/filter.json?follow=5835402"); // ID が「5835402」の人を追いかける //curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/filter.json?track=%23ppfun"); // 「#ppfun」というキーワードを追いかける curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/sample.json"); // サンプル /* send all data to this function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, curlCallback); /* we pass our 'chunk' struct to the callback function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &twttr); res = curl_easy_perform(curl_handle); /* always cleanup */ curl_easy_cleanup(curl_handle); } return 0; }
/*! * \file twitter.hpp */ #ifndef _TWITTER_STREAMING_HPP_ #define _TWITTER_STREAMING_HPP_ #include <map> #include <string> using namespace std; #include "./curl/curl.h" #include "./babel/babel.h" #include "./picojson.h" namespace TwttrStrm { class twitter { public: twitter(); //!< コンストラクタ ~twitter(); //!< デストラクタ bool loadJson(); //!< json から Tweet の情報を受け取る public: // cURL char *mp_responseBuffer; //!< Twiter の StreamingAPI から流れ込んでくる Tweet size_t m_responseSize; //!< mp_reponseBuffer のサイズ private: // Twitter string m_twitterUsrName; //!< Twitter のユーザ名 string m_twitterUsrPasswd; //!< Twitter のパスワード map<string, string> m_statuses; //!< Tweet の情報 <reply, mention> }; } // namespace TwttrStrm #endif // _TWITTER_STREAMING_HPP_
/*! * \file twitter.cpp */ #include "twitterStreaming.hpp" #include "json.hpp" #include "./babel/babel.h" namespace TwttrStrm { twitter::twitter(): mp_responseBuffer(NULL), m_responseSize(0), m_twitterUsrName(""), m_twitterUsrPasswd("") { } twitter::~twitter() { } bool twitter::loadJson() { using namespace picojson; string err; // エラーメッセージを受け取る value v; parse(v, mp_responseBuffer, mp_responseBuffer + m_responseSize, &err); if (err.empty()) // 正常に受け取れた { object2map(v.get<object>(), m_statuses); // 要素を全て抜き出す for (map<string, string>::iterator it = m_statuses.begin(); it != m_statuses.end(); it++) { cout << it->first << ": " << it->second << endl; } cout << endl; m_statuses.clear(); mp_responseBuffer = NULL; m_responseSize = 0; } return true; } } // namespace TwttrStrm
/*! * \file json.hpp */ #ifndef _JSON_HPP_ #define _JSON_HPP_ #include <map> #include <string> using namespace std; #include "./babel/babel.h" #include "./picojson.h" void object2map(picojson::object &obj, map<string, string> &mp); #endif // _JSON_HPP_
/*! * \file json.cpp */ #include "json.hpp" void object2map(picojson::object &obj, map<string, string> &mp) { for (picojson::object::iterator it = obj.begin(); it != obj.end(); it++) { string s = babel::utf8_to_sjis(it->second.to_str()); if (s == "object") { object2map(it->second.get<picojson::object>(), mp); } else { mp.insert(map<string, string>::value_type(it->first, s)); } } }
いい加減ソースコードも長くなったし見にくいですね.
行番号とスクロールバーが欲しいです.
WordPress あたりに移ろうかな(・・;
キーワードや ID を指定して Tweet を持ってくる
これは取りに行く json を変えるだけですね.
複数のキーワードや人を追いかけるときはカンマでつなげればいいらしいです.
詳しくは wiki で確認できます.
2行目の ID は僕の ID です.
RSS フィードの URL から確認したのですが,もっとスマートな方法があればいいですね.
普通の Twitter API を使えば持って来れそうな気もします.
// 「#ppfun」というキーワードを追いかける curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/filter.json?track=%23ppfun"); // ID が「5835402」の人を追いかける curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/filter.json?follow=5835402"); // ついでにサンプル curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/sample.json");
キーワードや ID で追ったり,Tweet の情報をごっそり集めたりしてみる
きっかけやお世話になった方々についてはこちら「Twitter の Streaming API を C/C++ でいじってみた(1)」へどうぞ.
とりあえず statuses/sample を持ってくる
「pingpong003ワークショップ@公立はこだて未来大学」に参加したのがきっかけで,「#ppfun」というハッシュタグを付けたつぶやきを流すアプリケーションをひそかに作っています.
そこで見つけたのがこれ,Twitter の Streaming APIをいじってみました.
キーワードやユーザIDなどでつぶやきにフィルタをかけて,リアルタイムに取得できるみたいです.
Twitter クライアントというよりは,つぶやきを流し続けたり,蓄積して分析したりするような使い方をするならとっても適しているような気がします.
まだ直さないといけないところが残っていますが,とりあえず statuses/sample からつぶやきとニックネームを取得して出力するものを公開します.
statuses/filter を使ったものももうすぐ公開します.
今回お世話になったみなさん,とてもとても感謝です.
- cURL and libcurl
- バベル - extra - C++ - TrickLibrary
- Kazuho@Cybozu Labs: 今更 C++ で JSON パーサ「picojson」を書いたわけ
[追記]
isLimit 関数ですが,delete が来るおは受け取ったステータスに欠落部分がある時でしたね.
#include <iostream> using namespace std; #include "./curl/curl.h" #include "./babel/babel.h" #include "./picojson.h" using namespace picojson; #define CR 13 #define LF 10 struct MemoryStruct { char *memory; size_t size; }; bool isLimit(value *pv) { value obj = pv->get("delete"); if (obj == NULL) return false; else return true; } static void *myrealloc(void *ptr, size_t size) { /* There might be a realloc() out there that doesn't like reallocing NULL pointers, so we take care of it here */ if(ptr) return realloc(ptr, size); else return malloc(size); } static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, MemoryStruct *data) { size_t realsize = size * nmemb; data->memory = (char *)myrealloc(data->memory, data->size + realsize + 1); if (data->memory) { memcpy(&(data->memory[data->size]), ptr, realsize); data->size += realsize; data->memory[data->size] = 0; } // picojson if (CR == data->memory[data->size-2] && LF == data->memory[data->size-1]) // Parsing Responses { value v; string err; parse(v, data->memory, data->memory + data->size, &err); if (isLimit(&v)) // Track Limiting { exit(0); // cleanup してない } if (err.empty()) { const string key("usr"); object obj = v.get<object>(); value usr = v.get("user"); object obj_usr = usr.get<object>(); string screen_name(obj_usr["screen_name"].to_str()); string text(obj["text"].to_str()); cout << screen_name << ": " << babel::utf8_to_sjis(text) << endl; data->memory = NULL; data->size = 0; } } return realsize; } int main(int argc, char **argv) { // babel babel::init_babel(); // cURL CURL *curl_handle; CURLcode res; struct MemoryStruct chunk; chunk.memory=NULL; /* we expect realloc(NULL, size) to work */ chunk.size = 0; /* no data at this point */ curl_handle = curl_easy_init(); curl_easy_setopt(curl_handle, CURLOPT_PROXY, "192.168.0.1:8080"); curl_easy_setopt(curl_handle, CURLOPT_PROXYUSERPWD, "PROXY_USER_NAME:PROXY_PASSWORD"); curl_easy_setopt(curl_handle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); curl_easy_setopt(curl_handle, CURLOPT_USERPWD, "TWITTER_ID:TWITTER_PASSWORD"); if(curl_handle) { curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/sample.json"); /* send all data to this function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); /* we pass our 'chunk' struct to the callback function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); res = curl_easy_perform(curl_handle); /* always cleanup */ curl_easy_cleanup(curl_handle); } return 0; }
さて,libcurl や picojson をもっと上手に使えるように勉強しなくちゃ_〆(・・o)
Problem33
/* * \file problem033.cpp * \brief Project Euler - Problem33 * * \author Takushi Homma (b1006018@fun.ac.jp) */ #include <iostream> #include <vector> #include <cmath> using namespace std; #define LMT 100 bool isNontrivial(int e, int d, int *pe, int *pd) { if (d%10 == 0 && d%10 == 0) { return false; } int tmpe, tmpd; if (e/10 == d/10) { tmpe = e%10; tmpd = d%10; } else if (e%10 == d/10) { tmpe = e/10; tmpd = d%10; } else if (e/10 == d%10) { tmpe = e%10; tmpd = d/10; } else if (e%10 == d%10) { tmpe = e%10; tmpd = d%10; } else { return false; } float a1 = (float)e / (float)d; float a2 = (float)tmpe / (float)tmpd; if (a1 == a2) { *pe = tmpe; *pd = tmpd; return true; } else { return false; } return false; } int main(int argc, char **argv) { vector<int> ve, vd; for (int d = 10; d < LMT; d++) { for (int e = 10; e < d; e++) { int tmpe, tmpd; if (isNontrivial(e, d, &tmpe, &tmpd)) { ve.push_back(tmpe); vd.push_back(tmpd); } } } int e = 1, d = 1; for (vector<int>::iterator it = ve.begin(), end = ve.end(); it != end; it++) { e *= *it; } for (vector<int>::iterator it = vd.begin(), end = vd.end(); it != end; it++) { d *= *it; } cout << d/e << endl; return 0; }
Problem32
/* * \file problem032.cpp * \brief Project Euler - Probmel32 * * \author Takushi Homma (b1006018@fun.ac.jp) */ #include <iostream> #include <string> #include <algorithm> #include <set> using namespace std; int main(int argc, char **argv) { int ans = 0; set<int> set_ans; string s = "123456789"; do { for (unsigned int i = 1; i < 8; i++) { for (unsigned int j = i+1; j < 9; j++) { int num[3]; int i_num = 0; memset(num, 0, 3*sizeof(int)); for (unsigned int k = 0; k < s.size(); k++) { if (k == i || k == j) { i_num++; } num[i_num] *= 10; num[i_num] += s.at(k)-'0'; } if (num[0]*num[1] == num[2]) { set_ans.insert(num[2]); } } } } while (next_permutation(s.begin(), s.end())); for (set<int>::iterator it = set_ans.begin(), e = set_ans.end(); it != e; it++) { ans += *it; } cout << ans << endl; return 0; }