ホームタイムラインを取得する[statuses/home_timeline](Twitter API)
Twitter APIの使い方シリーズ、第6回目に突入です。今回は「ホームタイムラインを取得する方法」を紹介します。自分がいつも見ている、自分とフォローした人たちのつぶやき一覧です。
目次
1リクエスト方法
「ホームタイムラインの取得」に関する公式の解説(英語)は、下記ページにあります。
GET statuses/home_timeline Twitter Developer Center
1-1リクエストURL(メソッド)
GETメソッドで、下記URLにリクエストを送ります。
[GET] https://api.twitter.com/1.1/statuses/home_timeline.json
1-2パラメータ
データ取得用のパラメータ(OAuth1.0認証を除く)は下記の通りです。全てオプショナル(任意)なので、指定しても、しなくてもどちらでもかまいません。
項目 | 解説 | 初期値 |
---|---|---|
count | 取得する件数。最大値は200。 | 20 |
since_id | つぶやきIDを指定すると、このIDより未来のデータのみを取得する。(このIDを含めて取得する) | - |
max_id | つぶやきIDを指定すると、このIDより過去のデータのみを取得する。(このIDを含めて取得する) | - |
trim_user | [true]を指定すると、ユーザーオブジェクトの内容がユーザーIDのみになる。詳しくは当ブログの過去記事、「[trim_user]とは?」で解説している。 | false |
exclude_replies | [true]を指定すると、リプライのつぶやきを除外する。 | false |
contributor_details | [true]を指定すると、ライター(複数人による投稿)機能を利用したつぶやきの場合、そのライターのユーザーオブジェクトを含める。 | false |
include_entities | [false]にすると、[entities]を含めない。「[include_entities]とは?」で解説している。 | true |
※は「指定必須」、※は「どちらか指定必須」のパラメータです。
2ホームタイムラインを取得する手順
それでは、ホームタイムラインのデータを取得していきましょう。「1から取得する方法」と「(前回作成した)ライブラリを利用して取得する方法」を、それぞれ掲載しています。
2-11からコードを書いて取得
1から、OAuth1.0認証方式のリクエストをして取得する方法を紹介します。ライブラリを利用する人は、「ライブラリを利用する」へ移動して下さい。
2〜17行目を、自身の環境に合わせて設定して下さい。詳しくは「アプリケーションの登録」「アクセストークンの取得」をご参考下さい。
<?php //[API Key]と[API Secret] ([API Secret]はついでにURLエンコード) $api_key = 'jqirc25fnwoybX7e1s6X9Pw4j'; $api_secret = rawurlencode('wGhZrxrkaMyTvvjHkUf1tjQJVBBzC0CRUfwOuE0Zqzcbf7FcE3'); //[アクセストークン]と[アクセストークンシークレット] ([アクセストークンシークレット]はついでにURLエンコード) $access_token = '1528352858-8QUZgOv01iG4bXZKEcFxrfoXDl5639UJYWY5T8n'; $access_token_secret = 'g3YXllfia8AT3orOHMcTp0Zw3f1lNIFME6JCWoCHiMy7M'; //リクエストURLとリクエストメソッド $request_method = 'GET'; $request_url = 'https://api.twitter.com/1.1/statuses/home_timeline.json'; //データ取得用のパラメータ(連想配列形式) $params_a = array( 'count' => 10, ); //キーを作成する $signature_key = "{$api_secret}&{$access_token_secret}"; //OAuth1.0認証用のパラメータ(連想配列形式) $params_b = array( 'oauth_consumer_key' => $api_key, 'oauth_token' => $access_token, 'oauth_nonce' => microtime(), 'oauth_signature_method' => 'HMAC-SHA1', 'oauth_timestamp' => time(), 'oauth_version' => '1.0' ); //データを作成する $params_c = array_merge($params_a,$params_b); ksort($params_c); $signature_params = http_build_query($params_c,'','&',PHP_QUERY_RFC3986); $signature_params = rawurlencode($signature_params); $encoded_request_method = rawurlencode($request_method); $encoded_request_url = rawurlencode($request_url); $signature_data = "{$encoded_request_method}&{$encoded_request_url}&{$signature_params}"; //署名を作成する $hash = hash_hmac('sha1',$signature_data,$signature_key,TRUE); $signature = base64_encode($hash); //GETリクエストの準備 $params_c['oauth_signature'] = $signature; $header_params = http_build_query($params_c,'',',',PHP_QUERY_RFC3986); $tail = '?'.http_build_query($params_a,'','&',PHP_QUERY_RFC3986); //リクエストを実行する $response = @file_get_contents( $request_url.$tail, //[第1引数:リクエストURL($request_url)とクエリー($tail)を合体] false, //[第2引数:リクエストURLは相対パスか?(違うのでfalse)] stream_context_create( //[第3引数:stream_context_create()でメソッドとヘッダーを指定] array( 'http' => array( 'method' => $request_method, //リクエストメソッド 'header' => array( //カスタムヘッダー 'Authorization: OAuth '.$header_params, ), ) ) ) ); //配列[$data]を作成する $data = array(); $data[0] = $response; //JSONデータ $data[1] = $http_response_header; //レスポンスヘッダー //JSONデータを出力する(確認のため) echo $data[0];
2-2ライブラリを利用して取得
「OAUth認証用のライブラリを作ろう」で作成した自作ライブラリ(twoh10_scr
)を利用する場合は、こちらを参考にして下さい。
それでは、関数ライブラリを使ってリクエストを送ってみましょう。次のようにリクエストを作成します。ちなみに、データ取得用のパラメータを何も指定しない場合は、配列を空にすれば大丈夫です(8行目)。
<?php //ライブラリを読み込む(ファイルの相対パスを指定) require_once './twoh10_scr.php'; //引数の指定 $url = 'https://api.twitter.com/1.1/statuses/home_timeline.json'; $method = 'GET'; $params = array( ); //リクエスト実行 $data = twoh10_scr($url,$method,$params); //取得したJSONデータの出力(確認のため) echo $data[0];
3取得できるJSONデータ
このAPIリクエストで取得できるJSONデータを解説します。
3-1つぶやきのサンプル
下記が取得するつぶやきの内容です。@arayutwのつぶやきに、@syncerjpが返信をしています。この@syncerのつぶやきを取得しました。
@arayutw つぶやき(リプライ)のサンプルです。
メンション(@arayutw )、ハッシュタグ(#hashtag)、シンボルタグ( $AMZN )、リンク(http://t.co/QKWZPBRH0v) pic.twitter.com/QQNk0UhrYa
— Syncer (@SyncerJP) 2014, 8月 13
3-2JSONデータの解説
下記が取得できるJSONデータ(つぶやき1つ分)です。実際には、[count]で指定した数だけ、配列形式で取得することができます。ユーザーオブジェクト("user": {〜}
)の中身は、過去記事で解説した「ユーザープロフィールのJSONデータ」と同内容です。公式リツイートじゃない場合、リツイートオブジェクト("retweeted_status": {〜}
)は存在しません。
青文字コメントは、説明のために足したものです。緑文字は、JSONデータをオブジェクト形式に変換し、変数、$object
に格納した際の取得方法です。
[ {1つ目のつぶやき "created_at": "Wed Aug 13 03:11:46 +0000 2014",投稿日時$object[0]->created_at "id": 499392843618594816,投稿ID(数値型)$object[0]->id "id_str": "499392843618594816",投稿ID(文字型)$object[0]->id_str "text": "@arayutw つぶやき(リプライ)のサンプルです。\nメンション(@arayutw )、ハッシュタグ(#hashtag)、シンボルタグ( $AMZN )、リンク(http://t.co/QKWZPBRH0v) http://t.co/QQNk0UhrYa",つぶやきの内容(プレーンテキスト)$object[0]->text "source": "<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>",投稿した端末$object[0]->source "truncated": false,$object[0]->truncated "in_reply_to_status_id": 499392247574450176,返信先の投稿ID(数値型)$object[0]->in_reply_to_status_id "in_reply_to_status_id_str": "499392247574450176",返信先の投稿ID(文字型)$object[0]->in_reply_to_status_id_str "in_reply_to_user_id": 1528352858,返信先のユーザーID(数値型)$object[0]->in_reply_to_user_id "in_reply_to_user_id_str": "1528352858",返信先のユーザーID(文字型)$object[0]->in_reply_to_user_id_str "in_reply_to_screen_name": "arayutw",返信先のスクリーンネーム$object[0]->in_reply_to_screen_name "user": {ユーザーオブジェクト(内容は「ユーザープロフィールのJSONデータ」を参照) ... }, "geo": {位置情報[1] "type": "Point",位置情報の種類(ピンポイント)$object[0]->geo->type "coordinates": [緯度、経度の順 35.7987175,$object[0]->geo->coordinates[0] 139.79455649$object[0]->geo->coordinates[1] ] }, "coordinates": {位置情報[2] "type": "Point",位置情報の種類(ピンポイント)$object[0]->coordinates->type "coordinates": [経度、緯度の順([1]と順序が逆) 139.79455649,$object[0]->coordinates->coordinates[0] 35.7987175$object[0]->coordinates->coordinates[1] ] }, "retweeted_status": {公式リツイートの場合のみ存在、この中に「元のつぶやき」のJSONデータが含まれる "created_at": "Wed Aug 13 05:14:48 +0000 2014",元のつぶやきの投稿日時$object[0]->retweeted_status->created_at "id": 4994238035799654402,元のつぶやきの投稿ID(数値型)$object[0]->retweeted_status->id "id_str": "4994238035799654402",元のつぶやきの投稿ID(文字型)$object[0]->retweeted_status->id_str "text": "この記事が面白かったらリツイートしてね!",元のつぶやきの内容(プレーンテキスト)$object[0]->retweeted_status->text ... }, "place": {場所情報 "id": "76c498282a5a7997",場所ID$object[0]->place->id "url": "https://api.twitter.com/1.1/geo/id/76c498282a5a7997.json",場所IDを取得するAPIのリクエストURL$object[0]->place->url "place_type": "city",場所の種類$object[0]->place->place_type "name": "足立区",場所の名前(短縮)$object[0]->place->name "full_name": "足立区, 東京",場所の名前(フル)$object[0]->place->full_name "country_code": "JP",国コード$object[0]->place->country_code "country": "日本",国名$object[0]->place->country "contained_within": [ ], "bounding_box": {範囲情報 "type": "Polygon",位置情報の種類(ポリゴン=範囲)$object[0]->bounding_box->type "coordinates": [範囲情報(最北西、最北東、最南東、最南西の座標データ) [ [最北西の座標 139.73540200298,$object[0]->bounding_box->coordinates[0][0] 35.735108003253$object[0]->bounding_box->coordinates[0][1] ], [最北東の座標 139.85608699408,$object[0]->bounding_box->coordinates[1][0] 35.735108003253$object[0]->bounding_box->coordinates[1][1] ], [最南東の座標 139.85608699408,$object[0]->bounding_box->coordinates[2][0] 35.813931997672$object[0]->bounding_box->coordinates[2][1] ], [最南西の座標 139.73540200298,$object[0]->bounding_box->coordinates[3][0] 35.813931997672$object[0]->bounding_box->coordinates[3][1] ] ] ] }, "attributes": { } }, "contributors": null,ライター機能を利用した投稿か?国名$object[0]->contributors "retweet_count": 0,リツイートされた回数$object[0]->retweet_count "favorite_count": 0,お気に入りされた回数$object[0]->favorite_count "entities": {エンティティ(リンク情報) ※[include_entities=false]にすると、除外できる "hashtags": [ハッシュタグ情報(配列形式) { "text": "hashtag",タグ名$object[0]->entities->hashtags[0]->text "indices": [テキスト中のタグの位置(文字数) 52,オフセット(開始位置より前の文字数)$object[0]->entities->hashtags[0]->indices[0] 60終了位置$object[0]->entities->hashtags[0]->indices[1] ] } ], "symbols": [シンボルタグ情報(配列形式) { "text": "AMZN",タグ名$object[0]->entities->symbols[0]->text "indices": [テキスト中のタグの位置(文字数) 70,オフセット(開始位置より前の文字数)$object[0]->entities->symbols[0]->indices[0] 75終了位置$object[0]->entities->symbols[0]->indices[1] ] } ], "urls": [URLアドレス情報(配列形式) { "url": "http://t.co/QKWZPBRH0v",プレーンテキスト中にあるURL文字列(短縮URL)$object[0]->entities->urls[0]->url "expanded_url": "http://syncer.jp",本来のURLアドレス$object[0]->entities->urls[0]->expanded_url "display_url": "syncer.jp",表示されるURLアドレス$object[0]->entities->urls[0]->display_url "indices": [テキスト中のURLの位置(文字数) 82,オフセット(開始位置より前の文字数)$object[0]->entities->urls[0]->indices[0] 104終了位置$object[0]->entities->urls[0]->indices[1] ] } ], "user_mentions": [メンション情報(配列形式) { "screen_name": "arayutw",プレーンテキスト中にあるメンション先のスクリーンネーム$object[0]->entities->user_mentions[0]->screen_name "name": "あらゆ",メンション先のユーザー名$object[0]->entities->user_mentions[0]->name "id": 1528352858,メンション先のユーザーID(数値型)$object[0]->entities->user_mentions[0]->id "id_str": "1528352858",メンション先のユーザーID(文字型)$object[0]->entities->user_mentions[0]->id_str "indices": [テキスト中のメンションの位置(文字数) 0,オフセット(開始位置より前の文字数)$object[0]->entities->user_mentions[0]->indices[0] 8終了位置$object[0]->entities->user_mentions[0]->indices[1] ] }, { "screen_name": "arayutw",プレーンテキスト中にあるメンション先のスクリーンネーム$object[0]->entities->user_mentions[1]->screen_name "name": "あらゆ",メンション先のユーザー名$object[0]->entities->user_mentions[1]->name "id": 1528352858,メンション先のユーザーID(数値型)$object[0]->entities->user_mentions[1]->id "id_str": "1528352858",メンション先のユーザーID(文字型)$object[0]->entities->user_mentions[1]->id_str "indices": [テキスト中のメンションの位置(文字数) 34,オフセット(開始位置より前の文字数)$object[0]->entities->user_mentions[1]->indices[0] 42終了位置$object[0]->entities->user_mentions[1]->indices[1] ] } ], "media": [メディア(添付画像)の情報(配列形式) { "id": 499392842129629184,添付画像のID(数値型)$object[0]->entities->media[0]->id "id_str": "499392842129629184",添付画像のID(文字型)$object[0]->entities->media[0]->id_str "indices": [テキスト中の添付画像URLの位置(文字数) 106,オフセット(開始位置より前の文字数)$object[0]->entities->media[0]->indices[0] 128終了位置$object[0]->entities->media[0]->indices[1] ], "media_url": "http://pbs.twimg.com/media/Bu4zJN6CYAAzKbI.jpg",画像ファイルのURL$object[0]->entities->media[0]->media_url "media_url_https": "https://pbs.twimg.com/media/Bu4zJN6CYAAzKbI.jpg",画像ファイルのURL(https)$object[0]->entities->media[0]->media_url_https "url": "http://t.co/QQNk0UhrYa",画像ファイルのURL(短縮)$object[0]->entities->media[0]->url "display_url": "pic.twitter.com/QQNk0UhrYa",表示される画像URL$object[0]->entities->media[0]->display_url "expanded_url": "http://twitter.com/SyncerJP/status/499392843618594816/photo/1",画像ページのパーマリンク$object[0]->entities->media[0]->expanded_url "type": "photo",メディアの種類(写真)$object[0]->entities->media[0]->type "sizes": {用意されてる画像サイズの情報 "medium": {ミディアム(中くらい) "w": 600,幅$object[0]->entities->media[0]->sizes->medium->w "h": 450,高さ$object[0]->entities->media[0]->sizes->medium->h "resize": "fit"リサイズ形式(縦横比維持)$object[0]->entities->media[0]->sizes->medium->resize }, "large": {ミディアム(巨大) "w": 1024,幅$object[0]->entities->media[0]->sizes->large->w "h": 768,高さ$object[0]->entities->media[0]->sizes->large->h "resize": "fit"リサイズ形式(縦横比維持)$object[0]->entities->media[0]->sizes->large->resize }, "thumb": {サムネイル(極小) "w": 150,幅$object[0]->entities->media[0]->sizes->thumb->w "h": 150,高さ$object[0]->entities->media[0]->sizes->thumb->h "resize": "crop"リサイズ形式(切り抜き)$object[0]->entities->media[0]->sizes->thumb->resize }, "small": {スモール(小) "w": 340,幅$object[0]->entities->media[0]->sizes->small->w "h": 255,高さ$object[0]->entities->media[0]->sizes->small->h "resize": "fit"リサイズ形式(縦横比維持)$object[0]->entities->media[0]->sizes->small->resize } } } ] }, "extended_entities": {拡張エンティティ(メディアのみ) "media": [メディア(添付画像)の情報(配列形式) { "id": 499392842129629184,添付画像のID(数値型)$object[0]->extended_entities->media[0]->id "id_str": "499392842129629184",添付画像のID(文字型)$object[0]->extended_entities->media[0]->id_str "indices": [テキスト中の添付画像URLの位置(文字数) 106,オフセット(開始位置より前の文字数)$object[0]->extended_entities->media[0]->indices[0] 128終了位置$object[0]->extended_entities->media[0]->indices[1] ], "media_url": "http://pbs.twimg.com/media/Bu4zJN6CYAAzKbI.jpg",画像ファイルのURL$object[0]->extended_entities->media[0]->media_url "media_url_https": "https://pbs.twimg.com/media/Bu4zJN6CYAAzKbI.jpg",画像ファイルのURL(https)$object[0]->extended_entities->media[0]->media_url_https "url": "http://t.co/QQNk0UhrYa",画像ファイルのURL(短縮)$object[0]->extended_entities->media[0]->url "display_url": "pic.twitter.com/QQNk0UhrYa",表示される画像URL$object[0]->extended_entities->media[0]->display_url "expanded_url": "http://twitter.com/SyncerJP/status/499392843618594816/photo/1",画像ページのパーマリンク$object[0]->extended_entities->media[0]->expanded_url "type": "photo",メディアの種類(写真)$object[0]->extended_entities->media[0]->type "sizes": {用意されてる画像サイズの情報 "medium": {ミディアム(中くらい) "w": 600,幅$object[0]->extended_entities->media[0]->sizes->medium->w "h": 450,高さ$object[0]->extended_entities->media[0]->sizes->medium->h "resize": "fit"リサイズ形式(縦横比維持)$object[0]->extended_entities->media[0]->sizes->medium->resize }, "large": {ミディアム(巨大) "w": 1024,幅$object[0]->extended_entities->media[0]->sizes->large->w "h": 768,高さ$object[0]->extended_entities->media[0]->sizes->large->h "resize": "fit"リサイズ形式(縦横比維持)$object[0]->extended_entities->media[0]->sizes->large->resize }, "thumb": {サムネイル(極小) "w": 150,幅$object[0]->extended_entities->media[0]->sizes->thumb->w "h": 150,高さ$object[0]->extended_entities->media[0]->sizes->thumb->h "resize": "crop"リサイズ形式(切り抜き)$object[0]->extended_entities->media[0]->sizes->thumb->resize }, "small": {スモール(小) "w": 340,幅$object[0]->extended_entities->media[0]->sizes->small->w "h": 255,高さ$object[0]->extended_entities->media[0]->sizes->small->h "resize": "fit"リサイズ形式(縦横比維持)$object[0]->extended_entities->media[0]->sizes->small->resize } } } ] }, "favorited": false,アクセストークンの主がお気に入りを付けているか?$object[0]->favorited "retweeted": false,アクセストークンの主がリツイートしているか?$object[0]->retweeted "possibly_sensitive": false,不適切な内容が含まれている可能性がある投稿か?$object[0]->possibly_sensitive "lang": "ja"言語$object[0]->lang } , ...(2つ目、3つ目のつぶやきと続く) ]
4[include_entities]とは?
データ取得時、パラメータの[include_entities]にfalse
を指定することができます。すると、"entities": {〜}
を丸ごと除外して、JSONデータを取得することができます。つぶやきにリンクを付ける必要がなく、プレーンテキストのままでいい場合は、取得するデータを減らしてサーバーの負担を軽減する目的で指定しましょう。
4-1[extended_entities]の存在意義
JSONデータ内の[entities]と[extended_entities]の内容を見比べてみて下さい。"entities": {〜}
の中の添付画像(media
)の情報と、"extended_entities": {〜}
は全く同じデータであることが分かると思います。何故、同じデータが重複して含まれているのでしょうか?
[entities]は、つぶやきのテキストにリンクを付けるためのデータ、いわば、つぶやきの内容を変換するためのデータです。対して[extended_entities]は、つぶやきのテキストに「加えて」、画像などを用意(拡張)するために用いるデータという違いがあります。
だから例えば、つぶやきを表示して添付画像があったらそれをつぶやきの下にimg
タグで表示して…という処理をする時には、存在意味通りに[extended_entities]のデータを利用した方が美しいですが、現状は[entities]の内容があれば、[extended_entities]は実質不要です。
5つぶやき一覧を出力する
この章では、取得したJSONデータを加工して、ブラウザに「つぶやき一覧」を取得してみます。
5-1サンプルプログラム(PHP)
サンプルプログラムを用意しました。「値の取り出し方」に注目して、JSONデータと見比べてみて下さい。先ほどのプログラムの続き($data
にJSONデータとレスポンスヘッダーを取得したところ)から記述して下さい。
//取得したJSONデータ[$data[0]]をオブジェクト形式に変換 $object = json_decode($data[0]); //HTMLのヘッダーを出力 echo 'ホームタイムライン
'; //つぶやきデータの配列をループ処理 foreach($object as $obj){ //名前・スクリーンネーム・アイコン画像 $name = $obj->user->name; $screen_name = $obj->user->screen_name; $icon = $obj->user->profile_image_url; //つぶやき・投稿日時(整形) $text = $obj->text; $date = date('Y/m/d H:i:s',strtotime($obj->created_at)); //位置情報を付けている場合、リンクを追加 if(isset($obj->place->full_name) && !empty($obj->place->full_name)){ //場所名 $place_name = $obj->place->full_name; //座標情報があればGoogle Mapsへのリンクを付ける if(isset($obj->geo->coordinates[1]) && !empty($obj->geo->coordinates[1])){ $place_name = ''.$place_name.''; } //つぶやきに追加 $text .= $place_name; } //出力 echo '@'.$screen_name.'('.$name.') '.$text.'('.$date.')
'; }
5-2ダウンロード
ここまでの完成版プログラムを下記からダウンロードすることができます。確認用にご利用下さい。
5-3出力結果を確認する(デモ)
出力結果を早く見たい人は、下記のデモページへアクセスして下さい。
それでは、ドキドキしながら出力してみましょう。このように、ホームタイムライン上の、自分や自分がフォローしている人たちのつぶやき一覧が表示されれば成功です!これだけでも、それらしいプログラムになりましたね!
さて、ですがここで、「つぶやきの内容」がおかしいことに、注目して下さい。次の章からは、処理が足りない分を補足していきましょう。
6リツイートを反映する
おかしい点1つ目は、公式リツイートのつぶやきのユーザー情報が、元のつぶやき本人ではなく、リツイートした人のものになっている点です。上記プログラムでは、ユーザー情報を一律でユーザーオブジェクト("user": {〜}
)から取得していましたが、リツイートの場合は、リツイートオブジェクト("retweeted_status": {〜}
)から取得しなければいけません。
6-1サンプルプログラム(PHP)
前章のプログラムの10〜17行目の処理を、10〜34行目のように修正しましょう。リツイートの場合の条件分けを加えました。
//取得したJSONデータ[$data[0]]をオブジェクト形式に変換 $object = json_decode($data[0]); //HTMLのヘッダーを出力 echo 'ホームタイムライン
'; //つぶやきデータの配列をループ処理 foreach($obj as $obj){ //リツイートの場合 if(isset($obj->retweeted_status) && !empty($obj->retweeted_status)){ //名前・スクリーンネーム・アイコン画像 $name = $obj->retweeted_status->user->name; $screen_name = $obj->retweeted_status->user->screen_name; $icon = $obj->retweeted_status->user->profile_image_url; //つぶやき・投稿日時(整形) $text = $obj->retweeted_status->text; $date = date('Y/m/d H:i:s',strtotime($obj->retweeted_status->created_at)); //位置情報を付けている場合、リンクを追加 if(isset($obj->retweeted_status->place->full_name) && !empty($obj->retweeted_status->place->full_name)){ //場所名 $place_name = $obj->retweeted_status->place->full_name; //座標情報があればGoogle Mapsへのリンクを付ける if(isset($obj->retweeted_status->geo->coordinates[1]) && !empty($obj->retweeted_status->geo->coordinates[1])){ $place_name = ''.$place_name.''; } //つぶやきに追加 $text .= $place_name; } //つぶやきの最後に[〜さんがRT]を付ける $text .= ' [@'.$obj->user->screen_name.'さんがRT]'; //それ以外の場合 }else{ //名前・スクリーンネーム・アイコン画像 $name = $obj->user->name; $screen_name = $obj->user->screen_name; $icon = $obj->user->profile_image_url; //つぶやき・投稿日時(整形) $text = $obj->text; $date = date('Y/m/d H:i:s',strtotime($obj->created_at)); //位置情報を付けている場合、リンクを追加 if(isset($obj->place->full_name) && !empty($obj->place->full_name)){ //場所名 $place_name = $obj->place->full_name; //座標情報があればGoogle Mapsへのリンクを付ける if(isset($obj->geo->coordinates[1]) && !empty($obj->geo->coordinates[1])){ $place_name = ''.$place_name.''; } //つぶやきに追加 $text .= $place_name; } } //出力 echo '@'.$screen_name.'('.$name.') '.$text.'('.$date.')
'; }
6-2デモを確認する
デモを確認したい人は、下記のデモページにアクセスして下さい。
このように、リツイートの場合はアイコンや名前が「元のつぶやき」をしたユーザーの情報になり、つぶやきの最後に「〜さんがRT(リツイート)」というテキストが付くようになりましたね。
7[entities]を処理しよう!
おかしい点2つ目は、つぶやきのテキストにリンクが貼られていないことです。いわゆるプレーンテキストの状態になっています。これにリンクを付けるには、JSONデータ内に存在するエンティティオブジェクト("entities": {〜}
)を利用します。はい、難関です…。
7-1[entities]とは?
[entities(entityの複数形)]とは「実体」という意味です。特殊文字で例えれば、<
に対して<
が実体ということになります。細かいことは考えず、ことTwitter APIにおいては、「リンク内容が詰まったデータ」と認識しておけば、間違いはないと思います。
つぶやきにリンクを付けていくには、このエンティティオブジェクト("entities": {〜}
)を参照しながら処理していくことになります。
7-2処理の流れ
では、具体的にどのように処理をしていくのか見てみましょう。
JSONデータ
下記は、JSONデータの中から、つぶやきの内容("text": "〜"
)とエンティティオブジェクトの内、ハッシュタグ("hashtags": [〜])の部分だけを取り出したものです。
[ { "text": "@arayutw つぶやき(リプライ)のサンプルです。\nメンション(@arayutw )、ハッシュタグ(#hashtag)、シンボルタグ( $AMZN )、リンク(http://t.co/QKWZPBRH0v) http://t.co/QQNk0UhrYa", "entities": { "hashtags": [ハッシュタグ情報(配列形式) { "text": "hashtag",タグ名 "indices": [テキスト中のタグの位置(文字数) 52,オフセット(開始位置より前の文字数) 60終了位置 ] } ], ... }, ... } , ... ]
リンクの付け方
下記がつぶやきのプレーンテキストです。
@arayutw つぶやき(リプライ)のサンプルです。\nメンション(@arayutw )、ハッシュタグ(#hashtag)、シンボルタグ( $AMZN )、リンク(http://t.co/QKWZPBRH0v) http://t.co/QQNk0UhrYa
エンティティオブジェクト内にある、ハッシュタグの「オフセットの位置」と「終わりの位置」を見て下さい。それぞれ、オフセットが52
、終わりが60
です。これは、プレーンテキスト内の53文字目から60文字目に、ハッシュタグの文字(#hashtag)があるという情報です。
@arayutw つぶやき(リプライ)のサンプルです。\nメンション(@arayutw )、ハッシュタグ(
[0〜52文字目]
#hashtag
[53〜60文字目]
)、シンボルタグ( $AMZN )、リンク(http://t.co/QKWZPBRH0v) http://t.co/QQNk0UhrYa
[61〜最後]
だからこの部分(53〜60文字目)を一旦、次のように削除して、
@arayutw つぶやき(リプライ)のサンプルです。\nメンション(@arayutw )、ハッシュタグ()、シンボルタグ( $AMZN )、リンク(http://t.co/QKWZPBRH0v) http://t.co/QQNk0UhrYa
同じ場所に、リンクタグを追加したハッシュタグのテキスト(リッチテキスト)を入れてやればいいというわけなんです。タグ名については、ハッシュタグオブジェクト内の"text": "〜"
で調べることができますね。次のようになります。
@arayutw つぶやき(リプライ)のサンプルです。\nメンション(@arayutw )、ハッシュタグ(#hashtag)、シンボルタグ( $AMZN )、リンク(http://t.co/QKWZPBRH0v) http://t.co/QQNk0UhrYa
PHPでの処理の例
PHPでは、次のようになります。余談ですが、mb_substr_replace()
という関数が存在しないので、ちょっと面倒な処理になっています。
<?php //つぶやき、開始位置、終了位置 $text = "@arayutw つぶやき(リプライ)のサンプルです。\nメンション(@arayutw )、ハッシュタグ(#hashtag)、シンボルタグ( $AMZN )、リンク(http://t.co/QKWZPBRH0v) http://t.co/QQNk0UhrYa"; $s = 52; $e = 60; //0〜51文字目(最初から該当箇所の直前まで)を保存 $before = mb_substr( $text , 0 , $s ); //61文字目以降(該当箇所の後から最後まで)を保存 $after = mb_substr( $text , $e , null ); //リンク付きのタグを用意 $tag_link = 'hashtag'; //合体させる echo $before.$tag_link.$after;
mb_substr()
については、下記の公式マニュアルをご参考下さい。
mb_substr PHP公式マニュアル
[mb_substr()]は、文字列の「〜文字目から〜文字目」を指定して抜き出すことができる関数です。
気を付けなければいけないこと
ここで注意点があります。それは、こういったエンティティの内容が複数あるケースです。例えば、変換するべきハッシュタグが2箇所あったとします。すると、あるハッシュタグをプレーンテキストからリッチテキストに変換したら、付けたタグコードの分だけ、つぶやきの文字数が変わってしまいますよね?そうすると、続いてもう1つのハッシュタグを変換しようとした時に、そのエンティティの情報(オフセット、終了位置)が役に立たなくなってしまう場合があります。
こういった問題を防ぐには、つぶやき内の、後ろにあるもの(オフセットの数値が高いもの)から、前にあるもの(オフセットの数値が低いもの)にかけて、順番に変換していくことです。そうすれば、ある変換が、他の変換に影響を与えることがなくなるのが分かりますよね?
7-3関数ライブラリ(PHP)
これまでのことを踏まえて、プレーンテキストにエンティティオブジェクトの内容を反映する(リンクを有効にする)、関数ライブラリを下記に作成しました。ハッシュタグだけでなく、シンボル、URL、メンション、添付メディアにも対応しています。
<?php // $data = twoh10_en_scr($text,$entities) // 第1引数:つぶやきのテキスト // 第2引数:エンティティオブジェクト // 返り値:リンクを付けたつぶやき function twoh10_en_scr($text,$entities){ //エンティティ内の調査対象のキー名 $check_list = array('hashtags','symbols','urls','user_mentions','media'); //エンティティの各項目を1つの配列[$entities]にまとめる $entities_list = array(); foreach($check_list as $check){ foreach($entities->{$check} as $item){ $entities_list[] = array( 'type' => $check, //キー名 'offset' => $item->indices[0], //開始までのオフセット 'end' => $item->indices[1], //終了位置 'value' => $item, //内容 ); } } //配列[$entities]を[$entities[offset]]が高い順に並び替える foreach($entities_list as $key => $value){$offset[$key] = $value['offset'];} array_multisort($offset,SORT_DESC,$entities_list); //変換処理を実行 foreach($entities_list as $item){ //該当箇所の直前・直後を保存 $left = mb_substr($text,0,$item['offset']); $right = mb_substr($text,$item['end'],null); //リッチテキストの用意 switch($item['type']){ //ハッシュタグの場合 case($check_list[0]): $richtext = '#'.$item['value']->text.''; break; //シンボルタグの場合 case($check_list[1]): $richtext = '$'.$item['value']->text.''; break; //URLアドレスの場合 case($check_list[2]): $richtext = ''.$item['value']->display_url.''; break; //メンションの場合 case($check_list[3]): $richtext = '@'.$item['value']->screen_name.''; break; //メディア(添付ファイル)の場合 case($check_list[4]): $richtext = ''.$item['value']->display_url.''; break; } //つぶやきの内容を更新 $text = $left.$richtext.$right; } //リンクを付けたつぶやきを返却 return $text; }
7-4使い方
作成した関数ライブラリは、twoh10_en_scr.php
として読み込んで下さい(2行目)。そして、22、51行目のように使いましょう。
//ライブラリの読み込み require_once './twoh10_en_scr.php'; //取得したJSONデータ[$data[0]]をオブジェクト形式に変換 $object = json_decode($data[0]); //HTMLのヘッダーを出力 echo 'ホームタイムライン
'; //つぶやきデータの配列をループ処理 foreach($object as $obj){ //リツイートの場合 if(isset($obj->retweeted_status) && !empty($obj->retweeted_status)){ //名前・スクリーンネーム・アイコン画像 $name = $obj->retweeted_status->user->name; $screen_name = $obj->retweeted_status->user->screen_name; $icon = $obj->retweeted_status->user->profile_image_url; //つぶやき・投稿日時(整形) $text = twoh10_en_scr($obj->retweeted_status->text,$obj->retweeted_status->entities); $date = date('Y/m/d H:i:s',strtotime($obj->retweeted_status->created_at)); //位置情報を付けている場合、リンクを追加 if(isset($obj->retweeted_status->place->full_name) && !empty($obj->retweeted_status->place->full_name)){ //場所名 $place_name = $obj->retweeted_status->place->full_name; //座標情報があればGoogle Mapsへのリンクを付ける if(isset($obj->retweeted_status->geo->coordinates[1]) && !empty($obj->retweeted_status->geo->coordinates[1])){ $place_name = ''.$place_name.''; } //つぶやきに追加 $text .= $place_name; } //つぶやきの最後に[〜さんがRT]を付ける $text .= ' [@'.$obj->user->screen_name.'さんがRT]'; //それ以外の場合 }else{ //名前・スクリーンネーム・アイコン画像 $name = $obj->user->name; $screen_name = $obj->user->screen_name; $icon = $obj->user->profile_image_url; //つぶやき・投稿日時(整形) $text = twoh10_en_scr($obj->text,$obj->entities); $date = date('Y/m/d H:i:s',strtotime($obj->created_at)); //位置情報を付けている場合、リンクを追加 if(isset($obj->place->full_name) && !empty($obj->place->full_name)){ //場所名 $place_name = $obj->place->full_name; //座標情報があればGoogle Mapsへのリンクを付ける if(isset($obj->geo->coordinates[1]) && !empty($obj->geo->coordinates[1])){ $place_name = ''.$place_name.''; } //つぶやきに追加 $text .= $place_name; } } //出力 echo '@'.$screen_name.'('.$name.') '.$text.'('.$date.')
'; }
7-5デモを確認する
上記ライブラリを利用して、ホームタイムラインを取得したデモを見たい人は、下記ページにアクセスしてみて下さい。
おおお、なんだかホームタイムラインが賑やかになって参りました(笑)。こうやって結果に反映されてくると、プログラミングって本当に面白いですよね!
8添付メディアを反映する
最後に、つぶやきに添付メディアがある場合は、img
タグを使って画像を出力しましょう。
8-1JSONデータ
下記はJSONデータの中から"extended_entities": {〜}
の部分のみを取り出したものです。
[ { ... "extended_entities": { "media": [ { "id": 499392842129629184, "id_str": "499392842129629184", "indices": [ 106, 128 ], "media_url": "http://pbs.twimg.com/media/Bu4zJN6CYAAzKbI.jpg",画像ファイルのURL "media_url_https": "https://pbs.twimg.com/media/Bu4zJN6CYAAzKbI.jpg",画像ファイルのURL(https) "url": "http://t.co/QQNk0UhrYa", "display_url": "pic.twitter.com/QQNk0UhrYa", "expanded_url": "http://twitter.com/SyncerJP/status/499392843618594816/photo/1", "type": "photo",メディアの種類(写真) "sizes": { "medium": {ミディアム(中くらい) "w": 600,幅 "h": 450,高さ "resize": "fit"リサイズ形式(縦横比維持) }, "large": {ミディアム(巨大) "w": 1024,幅 "h": 768,高さ "resize": "fit" }, "thumb": {サムネイル(極小) "w": 150,幅 "h": 150,高さ "resize": "crop" }, "small": {スモール(小) "w": 340,幅 "h": 255,高さ "resize": "fit" } } } ] }, ... } , ... ]
8-2画像のパーマリンクの仕組み
Twitter APIで取得できる添付メディア(画像)は、4種類の中からサイズを選択することができます。JSONデータの"sizes":{〜}
の中身を見れば、「medium(600x450)」「large(1024x780)」「thumb(150x150)」「small(340x255)」の4種類があるのが分かりますよね?
画像ファイル("media_url": "〜"
)を指定した場合、デフォルトではmedium(600x450)の画像が呼び出されるようになっています。サイズを変更して画像を呼び出すには、次のようにURLを組み立てます。
http://pbs.twimg.com[...].jpg:{サイズ名}
例えば、large
の画像を呼び出すには、次のように、URLを組み立てて下さい。
http://pbs.twimg.com[...].jpg:large [LINK]
thumb
の場合も紹介しておきます。用途に分けて使い分けて下さいね!
http://pbs.twimg.com[...].jpg:thumb [LINK]
8-3サンプルプログラム(PHP)
以上を踏まえて、添付メディアがある時はサムネイル画像を表示させて、クリックすると、大きい画像ファイルを見ることができるようにしてみましょう。42〜47行目、75〜81行目が追加した部分です。
//ライブラリの読み込み require_once './twoh10_en_scr.php'; //取得したJSONデータ[$data[0]]をオブジェクト形式に変換 $object = json_decode($data[0]); //HTMLのヘッダーを出力 echo 'ホームタイムライン
'; //つぶやきデータの配列をループ処理 foreach($object as $obj){ //リツイートの場合 if(isset($obj->retweeted_status) && !empty($obj->retweeted_status)){ //名前・スクリーンネーム・アイコン画像 $name = $obj->retweeted_status->user->name; $screen_name = $obj->retweeted_status->user->screen_name; $icon = $obj->retweeted_status->user->profile_image_url; //つぶやき・投稿日時(整形) $text = twoh10_en_scr($obj->retweeted_status->text,$obj->retweeted_status->entities); $date = date('Y/m/d H:i:s',strtotime($obj->retweeted_status->created_at)); //位置情報を付けている場合、リンクを追加 if(isset($obj->retweeted_status->place->full_name) && !empty($obj->retweeted_status->place->full_name)){ //場所名 $place_name = $obj->retweeted_status->place->full_name; //座標情報があればGoogle Mapsへのリンクを付ける if(isset($obj->retweeted_status->geo->coordinates[1]) && !empty($obj->retweeted_status->geo->coordinates[1])){ $place_name = ''.$place_name.''; } //つぶやきに追加 $text .= $place_name; } //つぶやきの最後に[〜さんがRT]を付ける $text .= ' [@'.$obj->user->screen_name.'さんがRT]'; //添付ファイルがある時はサムネイル画像を表示させる if(isset($obj->retweeted_status->extended_entities->media) && !empty($obj->retweeted_status->extended_entities->media)){ $text .= '
'; foreach($obj->retweeted_status->extended_entities->media as $media){ $text .= ''; } } //それ以外の場合 }else{ //名前・スクリーンネーム・アイコン画像 $name = $obj->user->name; $screen_name = $obj->user->screen_name; $icon = $obj->user->profile_image_url; //つぶやき・投稿日時(整形) $text = twoh10_en_scr($obj->text,$obj->entities); $date = date('Y/m/d H:i:s',strtotime($obj->created_at)); //位置情報を付けている場合、リンクを追加 if(isset($obj->place->full_name) && !empty($obj->place->full_name)){ //場所名 $place_name = $obj->place->full_name; //座標情報があればGoogle Mapsへのリンクを付ける if(isset($obj->geo->coordinates[1]) && !empty($obj->geo->coordinates[1])){ $place_name = ''.$place_name.''; } //つぶやきに追加 $text .= $place_name; } //添付ファイルがある時はサムネイル画像を表示させる if(isset($obj->extended_entities->media) && !empty($obj->extended_entities->media)){ $text .= '
'; foreach($obj->extended_entities->media as $media){ $text .= ''; } } } //出力 echo '
@'.$screen_name.'('.$name.') '.$text.'('.$date.')
'; }
8-4デモを確認する
デモを確認したい人は、下記のデモページをご覧下さい。
添付メディアが反映されましたね。この春くらいからTwitterに加わった「複数の画像投稿機能」にも、しっかりと対応できているのが確認できると思います。ここからデザインをあなた好みに変更していって下さい。
9完成版プログラムのダウンロード
この記事で作成したプログラムをダウンロードすることができます。プログラムが動かなくなった確認用などにお使い下さい。
9-1単体作動版
外部ファイルを読み込む必要がなく、単体で動くプログラムです。このファイル内でOAuth1.0認証のフローを行なっています。別途、ライブラリをダウンロードする必要はありません。
9-2ライブラリ利用版
twoh10_scr()
とtwoh10_en_scr()
、2つのライブラリを利用するプログラムです。
9-3関数ライブラリ:twoh10_en_scr()
「7.[entities]を処理しよう!」で作成した、Twitterのつぶやきデータに含まれる[entities]を処理するための関数です。大雑把な置換処理ではなく、オフセットと終了位置の情報を元に処理しています。
9-4関数ライブラリ:twoh10_scr()
前回、「OAUth認証用のライブラリを作ろう」で作成した、OAuth1.0認証を一通り処理してくれる関数ライブラリです。使い方については、該当記事をご参考下さい。
10使えるデータを組み合わせてみよう!
いかがでしたか?ここまで読んでいただき、ありがとうございました。「ユーザープロフィール」や「ホームタイムライン」が取得できるようになれば、もうこの連載を見なくても何らかのwebサービスが作れるんじゃないかと思います。
今回やってみた人は分かると思いますが、たった1つのつぶやきにも、膨大な量のデータが詰まっています。この記事で使ったもの以外にも、工夫すれば面白い見せ方ができるデータはたくさんあると思います。自分なりに工夫してみて下さい。
次回はちょっと休憩気味に…、「ユーザータイムライン」を取得する予定です。プログラムもJSONデータも、今回とほとんど変わりません。それと共に、1回のリクエストではつぶやきを取得し切れない場合にどうすればいいか、「ページング」を行なってみましょう。それでは!
Twitter API
この記事へのコメント
感想、ご指摘などお気軽にお寄せ下さい。「関連記事を書いた」という方はご報告いただければリンクします。
記事の更新履歴
- 記事を公開しました。
2014/08/13 23:30
※Twitter、Facebook、はてな、いずれかのアカウントをお持ちの方は、本人認証(ログイン)を行なうことができます。
※本人認証をすることで、書き込みの待ち時間なし、画像アップロード、アイコンなどが利用できます。
※認証時にサービスと連携しますが、名前とアイコン以外の情報を読み込んだり、また書き込みを行なうことはありません。連携で要求する権限は「公開情報の読み取り」のみです。
コメントは、0件です。