C++でのTwitterデータの取得

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
理澄

C++でのTwitterデータの取得

#1

投稿記事 by 理澄 » 6年前

以前もお世話になりました。
今回は卒業論文への準備ということでC++を用いたタスクを出されたのですが、いきなり最初の所で詰まってしまったのでこちらに頼る事になりました。
過去のトピックに類似の質問が有りましたが、クライアントではなくデータの習得のみということでハードルの高さが違うと思うので、ここで質問させて頂きます。
http://dixq.net/forum/viewtopic.php?f=3&t=10085

タイトルにも書いたとおり、やりたいことは、C++でのTwitterデータの取得です。具体的には、自分のツイートやフォロワーなどの情報を何かしらの方法で取得することです。
そこで、具体的な質問は以下のようになります。

・Twitterのデータ取得にはXauthやOauthなどの認証は必要か
 -書き込みに認証は必要だが、取得のみでも必要でしょうか
・取得はどのように行えばいいか
-APIやライブラリなどC++で何かオススメの方法があればお願いします。

とりあえず、大きな疑問はこの二つです。どうかご教授願います。

以下は私の環境、状況です。

OS:Windows7 64bit enterprise
開発環境:eclipse+CDT
コンパイラ:MinGW gcc
C++経験:皆無 今回のタスクは初めての言語でのプログラミングも含んでいるため触れたことのないC++となりました
プログラミング経験:Javaでなら簡単なアプリケーションを自作できる程度です
知識:応用情報技術者 程度です

長文、駄文失礼いたしました。至らない所が有りましたらご質問ください。

YuO
記事: 942
登録日時: 9年前
住所: 東京都世田谷区

Re: C++でのTwitterデータの取得

#2

投稿記事 by YuO » 6年前

理澄 さんが書きました:・Twitterのデータ取得にはXauthやOauthなどの認証は必要か
 -書き込みに認証は必要だが、取得のみでも必要でしょうか
必要です。
Twitter / サービス利用規約の8. (iii)に,Twitter社の承諾無しにスクレイピングを行うことを禁じる条項があります。
よって,公開APIを使う必要がありますが,公開APIの使用で認証が不要なのは認証自体を行うためのURI群くらいです。
# help/toshelp/privacyですら認証が必要。
理澄 さんが書きました:・取得はどのように行えばいいか
-APIやライブラリなどC++で何かオススメの方法があればお願いします。
ライブラリのお薦めは知りませんが,とりあえず署名さえなんとかなれば,API直接叩くことは難しくないとは思います。
# OAuthの署名が面倒すぎる……。

理澄

Re: C++でのTwitterデータの取得

#3

投稿記事 by 理澄 » 6年前

YuOさん解答ありがとうございました。
認証が必要だということでOauthで認証することを決めTwitter developersに新規アプリケーションの登録をしてOauth認証に必要なConsumer keyとConsumer secretを発行してもらいました。

が、ここから先C++でOauth認証のプログラムを書く必要がありますよね。
参考になる資料がないか探したのですが、Windows上のC++での開発がほとんど見つかりませんでした。
twitcurlというライブラリは見つかったのですが・・・

C++でのOauth認証に必要な物や、サンプルなど初心者にもわかりやすいのはないでしょうか・・・

beatle
記事: 1280
登録日時: 9年前
住所: 埼玉
連絡を取る:

Re: C++でのTwitterデータの取得

#4

投稿記事 by beatle » 6年前

どうしてもC++で書かなければいけないのですか?
Pythonなど他の言語用ライブラリならいろいろ便利なのがあるのですが。

理澄

Re: C++でのTwitterデータの取得

#5

投稿記事 by 理澄 » 6年前

解答ありがとうございます。
Javaや他言語ではサンプルも豊富で、APIのサポートも手厚いのはわかっているんですが・・・
C++を指定されてしまったので、なんとかC++では出来ないでしょうか?
もしどうしてもダメなら、相談してみます。

beatle
記事: 1280
登録日時: 9年前
住所: 埼玉
連絡を取る:

Re: C++でのTwitterデータの取得

#6

投稿記事 by beatle » 6年前

先生がC++にこだわる理由はよくわかりません.もしかしたら,便利なTwitterライブラリが無い状況を知らず,なんとなく「C++」と言ったのでは?とも思ってしまいます.
メインはC++プログラムで,ツイッターを扱う部分だけ他の言語にする,というのも技術的には可能です.

ちょっと探したらこんなページがありますが参考になりますか?
C++でTwitter APIを利用する
「C/C++用の使いやすいライブラリが見つからなかったので自作しました。liboauthを元に改造して制作しました。」
だそうです.

理澄

Re: C++でのTwitterデータの取得

#7

投稿記事 by 理澄 » 6年前

解答ありがとうございます。
紹介頂いた物をとりあえずeclipseにインポートしてみました。
サイトにもある通り、VS2008以降での実行用にコーディングされているので、警告がでている部分をGCC用に書き直しました。
#pragma warning(disable:)→#pragma GCC diagnostic ignore など
しかし一種類だけエラーが出てしまいます。

コード:

#ifdef WIN32
	WSADATA wsaData;
	WORD wVersionRequested;
	wVersionRequested = MAKEWORD(1,1);
	WSAStartup(wVersionRequested, &wsaData);
	atexit((void (*)(void))(WSACleanup));
#endif
のWSAStartupの部分などです。エラーメッセージはundefined reference to `__imp_WSAStartup'とあるので
どこで定義されているのかWSASStartupを調べるとWin32のライブラリの関数だということで、リンクができていない?のかと思いました。
インクルードは

コード:

#include <windows.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netdb.h>
#endif

#include "socket.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

となっており、makefileは自動生成されたままの

コード:


TARGET = libtwicpp.a

OBJS = \
	hash.o \
	oauth.o \
	oauth_http.o \
	sha1.o \
	socket.o

all: $(TARGET)

$(TARGET): $(OBJS)
	$(AR) r $@ $^

clean:
	-rm $(TARGET)
	-rm *.o


となっています。
ライブラリを追加するので、makefileにLIBSを追加すればいいのかと思いましたが、そもそもwin32は明示的によぶ必要はあるんでしょうか
この推測が合っている場合はmakefikeになんと追加すればいいのでしょうか。

理澄

Re: C++でのTwitterデータの取得

#8

投稿記事 by 理澄 » 6年前

連投失礼します。
問題は解決していませんが、勘違いがあったので報告させていただきます。
WSAStartupなどのエラーがでている関数はWin32ではなく、WinSockで定義されているものでした。

WinSockを利用するためには、winsock.hをインクルードし、ws2_32.libをリンカに通す必要がある事が分かりました。
winsock.hのインクルードはすでに書いてあったので、eclipseのほうでws2_32.libを通そうと思い、プロジェクトを右クリック→プロパティ→C/C++一般→パス及びシンボル→ライブラリ にws2_32.libを追加するとエラー表示がなくなりました。

しかしビルドしてみると c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/4.5.4/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lC:\MinGW\lib\ws2\libws2_32
というエラーがでます。

LD.exeはリンカで、リンカがライブラリを見つけられないというエラーなのはわかるのですが、直し方がわかりません。
ライブラリに追加してエラー表示が消えたということはeclipseはライブラリを認識したということだと思います。
リンカは拡張子を自分で判断するので.aや.libを抜いて指定すれば治るという記事を見つけ試してみましたがws2_32でもws2_32.libでもws2_32.aでもws2_32ダメでした。

直し方をご存知の方がいたらご教授お願い致します。 補足としてエラーメッセージの\ws2\以降は自分が作ったディレクトリでlibws2_32.aとws2_32.libのみが入っています。

アバター
へにっくす
記事: 630
登録日時: 8年前
住所: 東京都

Re: C++でのTwitterデータの取得

#9

投稿記事 by へにっくす » 6年前

えーと
.libと.aって違うフォーマットじゃなかったっけ。
mingwのgccで扱うライブラリは拡張子が.aだったと思います。
Windows DLLから.aを作成するツールが確かあったと思います。dlltool?だったかな。

↓一応同じようなケースでの解決策
http://flspz.blogspot.jp/2012/07/gcc-er ... .html.html
written by へにっくす

理澄

Re: C++でのTwitterデータの取得

#10

投稿記事 by 理澄 » 6年前

解答ありがとうございます。
.aでも.libでもダメだったので、その後も色々変更しているとeclipseのライブラリの欄には絶対パスではなく、登録したライブラリパスからの相対パスを登録するみたいでした。

なので、ライブラリパスとして…lib/ws2を登録し、ライブラリとしてws2_32を登録することでライブラリをリンクすることが出来ました。
このときのライブラリはws2_32.libですが、拡張子は指定しません。

まだredefineやunusedなどは残っていますが、ようやくコンパイルしてexeの生成までこぎつける事が出来ました。
生成されるexeを実行するとlibgcc_s_sjlj-1.dllが足りないと言われるので、それをダウンロードして実行しました。
するとアプリケーションを正しく起動できませんでした。という0xc000007エラーがでてしまいました。調べるとこれは32bit向けのdllなどが入ってしまっている場合にでるらしいのですが、確かにexeはamd64とあるが、libgccはX86とあります。
検索しても64bit版のlibgccが出てこないのですが、どこで手に入るのでしょうか。

他に気になった点は、
http://dixq.net/forum/viewtopic.php?t=10052&p=81192
このトピックのNo34でws2_32.libはWinSock2.h用とあるのですが、WinSock.hしか使わないのでwsock32.libに変えたところ何故かバイナリーが生成されませんでした。ビルドは通るのでws2_32.libに戻してしまいましたが、これは影響があるのでしょうか。

何度も質問してすいません、どうかもう少しだけお力をお貸しください。

beatle
記事: 1280
登録日時: 9年前
住所: 埼玉
連絡を取る:

Re: C++でのTwitterデータの取得

#11

投稿記事 by beatle » 6年前

MinGWのgccでコンパイルしているということですから、実行時にMinGWのbinディレクトリなどをPATHに追加しておく必要があると思います。
つまりlibgcc_s_sjlj-1.dll(に限らず実行時に依存するdll)が存在するディレクトリがPATHに入っていなければなりません。

ちなみに私のMinGW環境には F:\MinGW\bin\libgcc_s_dw2-1.dll というファイルがありました。
MinGW GCCでコンパイルした実行可能ファイルを実行するには F:\MinGW\bin をPATHに追加する必要があります。

アバター
みけCAT
記事: 6311
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: C++でのTwitterデータの取得

#12

投稿記事 by みけCAT » 6年前

beatle さんが書きました:MinGW GCCでコンパイルした実行可能ファイルを実行するには F:\MinGW\bin をPATHに追加する必要があります。
コンパイル時に-staticオプションを指定すれば、その必要は無くなると思います。
ただし、-fopenmpを使った場合などの例外はあるようです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

理澄

Re: C++でのTwitterデータの取得

#13

投稿記事 by 理澄 » 6年前

解答ありがとうございした。
言われてはっとしてPATHを確認したらMinGWは設定してませんでした・・・すいません・・・
CygwinのPATHを設定して設定したつもりになってました・・・

PATHを設定し再起動した後に生成されたEXEを起動することで無事起動することができ、認証キー(ツイッターとの連携許可)とメッセージの入力画面は出たのですが、投稿が反映されません。
エラーは何も出ていませんが、redefineやunusedなどの警告が3つほどでています。
また、バイト数の関係かと思いtestと投稿もしましたが反映されません。

認証キーは適当なのを打つとfailedのメッセージが出力されるため、認証自体はうまくいっているようです。なのでメッセージのPOSTが引っかかっていると思うのですが、POST周りのコードは次のようになっています。

コード:

	if (!message.empty()) {
		{
			int n;
			wchar_t ucs2[1000];
			char utf8[1000];
			n = MultiByteToWideChar(CP_ACP, 0, message.c_str(), message.size(), ucs2, 1000);
			n = WideCharToMultiByte(CP_UTF8, 0, ucs2, n, utf8, 1000, 0, 0);
			message.assign(utf8, n);
		}

//		std::string uri = "http://api.twitter.com/statuses/update.xml";
//		std::string uri = "http://api.twitter.com/1/statuses/update.xml"; // 2012-11-15
		std::string uri = "http://api.twitter.com/1.1/statuses/update.json"; // 2013-02-26
		uri += "?status=";
		uri += oauth_url_escape(message.c_str());

		req_url = oauth_sign_url2(uri.c_str(), &postarg, OA_HMAC, 0, c_key.c_str(), c_secret.c_str(), t_key.c_str(), t_secret.c_str());
		reply = oauth_http_post(req_url.c_str(), postarg.c_str(), false);
	}

コード:

std::string oauth_sign_url2(
	const char *url,
	std::string *postargs, 
	OAuthMethod method, 
	const char *http_method, //< HTTP request method
	const char *c_key, //< consumer key - posted plain text
	const char *c_secret, //< consumer secret - used as 1st part of secret-key 
	const char *t_key, //< token key - posted plain text in URL
	const char *t_secret //< token secret - used as 2st part of secret-key
)

コード:

std::string oauth_http_post(const char *u, const char *p, bool keepalive)
{
	Socket sock;
	std::vector<std::string> header;
	std::vector<std::string> resheader;
	std::vector<unsigned char> resdata;
	sock.http_post(u, p, strlen(p), &header, &resheader, &resdata, keepalive);
	if (resheader.size() > 0) {
		int a, b, c;
		sscanf(resheader[0].c_str(), "HTTP/%u.%u %u", &a, &b, &c);
		if (c == 200 && !resdata.empty()) {
			char const *p = (char const *)&resdata[0];
			return std::string(p, p + resdata.size());
		}
	}
	return std::string();
}
POSTが成功したかどうかチェックするような構造がとりあえず必要だと思うのですが、POST成功のチェック方法とどこに入れればいいのかがわかりません。よろしくお願いします。

理澄

Re: C++でのTwitterデータの取得

#14

投稿記事 by 理澄 » 6年前

就活やレポート、アルバイトに追われ1ヶ月ほど間を開けてしまいましたが、進展があったので報告させていただきます。
twitter developersに登録したアプリを読み書き許可にし、コールバックURLなどの空欄を全部埋めてみるとeclipseから無事ツイートすることが出来ました。

現在、eclipseで実行→ブラウザが立ち上がり認証キーが表示→コンソールに入力→[テキストを入力→ツイート]
という流れになっています。[]の中がサンプルコードの内容なのですが、ここを書き換えツイートの取得にしたいと思っています。
サンプルコードを抜粋すると以下のようになっており、

コード:

	printf("input message: ");
	std::string message = inputtext();
	putchar('\n');
	if (!message.empty()) {
		{
			int n;
			wchar_t ucs2[1000];
			char utf8[1000];
			n = MultiByteToWideChar(CP_ACP, 0, message.c_str(), message.size(), ucs2, 1000);
			n = WideCharToMultiByte(CP_UTF8, 0, ucs2, n, utf8, 1000, 0, 0);
			message.assign(utf8, n);
		}

//		std::string uri = "http://api.twitter.com/statuses/update.xml";
//		std::string uri = "http://api.twitter.com/1/statuses/update.xml"; // 2012-11-15
		std::string uri = "http://api.twitter.com/1.1/statuses/update.json"; // 2013-02-26
		uri += "?status=";
		uri += oauth_url_escape(message.c_str());

		req_url = oauth_sign_url2(uri.c_str(), &postarg, OA_HMAC, 0, c_key.c_str(), c_secret.c_str(), t_key.c_str(), t_secret.c_str());
		reply = oauth_http_post(req_url.c_str(), postarg.c_str(), false);
http://www.geocities.co.jp/SiliconValle ... og_04.html
こちらを参考に、ツイートID=12345のツイートを取得に書き換える場合は、次のように変えればいいと思ったのですが、reply.emptyがtrueということでエラーなので取得ができていないことがわかりました。また、出力先のjsonも0バイトです。

コード:

	std::string uri = "https://api.twitter.com/1.1/statuses/show/12345.json"; // 2013-02-26
		req_url = oauth_sign_url2(uri.c_str(), 0, OA_HMAC, 0, c_key.c_str(), c_secret.c_str(), t_key.c_str(), t_secret.c_str());
		reply = oauth_http_get(req_url.c_str(), NULL);
		printf("test%s",reply.c_str());
		  /* ファイルに書き出す */
		FILE *fp;
		 fp = fopen("c:\\test.json","w");
		 fputs( reply.c_str() , fp );
		 fclose( fp );
この状況へのアドバイス、または別の方法などがありましたらどうかよろしくお願いいたします。

beatle
記事: 1280
登録日時: 9年前
住所: 埼玉
連絡を取る:

Re: C++でのTwitterデータの取得

#15

投稿記事 by beatle » 6年前

GET statuses/show/:idを読むと、特定のツイートを取得するAPIがちょっと違うのかなと思いますが、どうでしょうか。

理澄

Re: C++でのTwitterデータの取得

#16

投稿記事 by 理澄 » 6年前

おっしゃるとおり、idパラメータの指定方法が間違っていました。
さらに、このAPIのときはhttpでしたので修正したところ、ツイートの取得ができました。
これでやっと、データ集取できるとおもいきや適当に指定したidだとほとんどがnullとなってしまいました。
idは投稿順にインクリメントされて割り当てられると思っていたのですが、生成ルールがあるようです。
そりゃ42京もツイートがあるわけ無いですよね・・・

こちらによると、41bitまでが時刻などと決まっているようです。
今私がしたいのは、1日毎のツイート数(Twitter全体)などの取得です。
https://dev.twitter.com/docs/api/1.1/get/search/tweets
このAPIに計算した日時の範囲を引数に渡して、取得できたツイートの数をカウントすれば出来るんじゃないかと思っています。しかし、クエリが必須なのでワイルドカードが使えない場合は全ツイートの取得が出来ないうえに、APIのコール数制限もあるので厳しいのではないかと思っています。
何かいい方法はないでしょうか。お願い致します。

beatle
記事: 1280
登録日時: 9年前
住所: 埼玉
連絡を取る:

Re: C++でのTwitterデータの取得

#17

投稿記事 by beatle » 6年前

Twitter全体の投稿を漏らさず全部受け取るには、Twitter社と有料契約が必要だったと思います。
無料の範囲では、全体のうち何%か忘れましたが少ししか取得できません。

何か特定のクエリを決めて、自分のTLにおけるクエリ包含率(クエリを含むツイート数/TLの全ツイート数)とTwitter全体でのクエリ検索結果数を使えばある程度推測できると思います。

時刻AからBまでの世界中のツイート数推定値
= 時刻AからBまでのTwitter全体でのクエリ検索結果数
/ 時刻AからBまでの自分のTLにおけるクエリ包含率

で計算できます。

理澄

Re: C++でのTwitterデータの取得

#18

投稿記事 by 理澄 » 6年前

なるほど・・・
publicなデータ収集は無理そうですね。
もう時間もないので自分のツイートを全部取得して、それをグラフ化しようと思ったのですがTimeLineに関するAPIが戻り値を返してくれません。

コード:

std::string uri = "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=twitterapi&count=2";// 2013-02-26
		req_url = oauth_sign_url2(uri.c_str(), 0, OA_HMAC, 0, c_key.c_str(), c_secret.c_str(), t_key.c_str(), t_secret.c_str());
		reply = oauth_http_get(req_url.c_str(), NULL);
httpsのAPIは何か処理が違うのでしょうか?
https://dev.twitter.com/docs/api/1.1/ge ... r_timeline
特に変わった所は無いと思うのですが・・・

beatle
記事: 1280
登録日時: 9年前
住所: 埼玉
連絡を取る:

Re: C++でのTwitterデータの取得

#19

投稿記事 by beatle » 6年前

戻り値を返さないというのは、return文が実行されないのか、エラーっぽい値がreturnされるのか。
エラーっぽい値がreturnされるなら、その戻り値を貼り付けてもらえませんか?
または、そのエラーメッセージでGoogle検索したら何かヒントを得られませんか?

理澄

Re: C++でのTwitterデータの取得

#20

投稿記事 by 理澄 » 6年前

説明不足でした。
正確には、正常な戻り値(ポインター)が帰らず、戻り値がNULLとなっています。

コード:

@return  In case of an error NULL is returned; otherwise a pointer to the
 * replied content from HTTP server. latter needs to be freed by caller.
 */
std::string oauth_http_get(const char *u, const char *q)
{
	Socket sock;
	std::vector<std::string> header;
	std::vector<std::string> resheader;
	std::vector<unsigned char> resdata;
	sock.http_get(u, &header, &resheader, &resdata, false);
	if (resheader.size() > 0) {
		int a, b, c;
		sscanf(resheader[0].c_str(), "HTTP/%u.%u %u", &a, &b, &c);
		if (c == 200 && !resdata.empty()) {
			char const *p = (char const *)&resdata[0];
			return std::string(p, p + resdata.size());
		}
	}
	return std::string();
}
というのも、エラーがあるときにはNULLを返すようになっています。
エラーメッセージが返ってくるのであれば、すごいやりやすいのですが、何も帰ってこないので困っています。

beatle
記事: 1280
登録日時: 9年前
住所: 埼玉
連絡を取る:

Re: C++でのTwitterデータの取得

#21

投稿記事 by beatle » 6年前

oauth_http_get関数の14行目で、ステータスコードcが200かどうかをチェックしています。
HTTPのステータスコードを見ると、200は正常の意味です。

戻り値が空文字列(NULLではなく、string()は空文字列を生成します)になるのは、resheader.size()が0の場合か、cが200以外の場合か、resdata.empty()がtrueの場合です。
3つのうちどの原因でoauth_http_get関数が失敗しているのかは調べる必要がありそうですね。
特にステータスコードcの値はチェックしましょう。大きなヒントになると思います。

理澄

Re: C++でのTwitterデータの取得

#22

投稿記事 by 理澄 » 6年前

長い間お付き合いいただきありがとうございました。
httpsの認証が通らないのは、使っていたライブラリがhttpsに対応していないからでした。
さらに1/14からAPIへの通信は全てhttpsに統一されたため(https://dev.twitter.com/discussions/24239)、このライブラリではできなくなってしまったのですが、
先ほど見たところhttpsの対応版(http://www.soramimi.jp/twicpps/index.html)が出ていてそちらを利用したら無事ツイートの取得ができました!
取得したツイートの情報を時間や曜日などに分けてグラフとして統計を取ることができました。
本当にありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る