matsulibの日記

Ingredients as Code

Twitter API を使う

Pythonによるデータ分析入門を読んでいたらTwitter APIを使ってデータを集める方法が書いてあったけれど、出版当時とはAPIの仕様が変わっていてサンプルコードが動かなかったのでメモ。

ソースコード
from pandas import DataFrame
import pandas as pd
from requests_oauthlib import OAuth1Session
import json

consumer_key = 'XXXXXXXXXXXXXXXXXXXXXX'
consumer_secret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
access_token = 'XXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
access_token_secret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

twitter = OAuth1Session(consumer_key, consumer_secret, access_token, access_token_secret)

url = 'https://api.twitter.com/1.1/statuses/home_timeline.json'
# url = 'https://api.twitter.com/1.1/search/tweets.json?q=検索ワード'
params = {'count': 20, 'include_rts': False}  # 取得するツイート数(10~200),リツイートの有無
resp = twitter.get(url, params=params)
data = json.loads(resp.text)

tweet_fields = ['created_at', 'text', 'id']
tweets = DataFrame(data, columns=tweet_fields)
# tweets = DataFrame(data['statuses'], columns=tweet_fields)

user_fields = ['name', 'screen_name']
tweets[user_fields] = DataFrame([d['user'] for d in data], columns=user_fields)
# tweets[user_fields] = DataFrame([d['user'] for d in data['statuses']], columns=user_fields)

data(検索ならdata['statuses'])は取得したツイートからなるリストで、各ツイート要素は下記のように大きな辞書になっているので、データフレームにするときは使いたいフィールドを列に指定する。userは辞書の入れ子になってるので別のデータフレームを作ったあとにtweetsに結合した。

In [51]: data[1]
Out[51]:
{'place': None,
 'in_reply_to_status_id': None,
 'favorited': False,
 'truncated': False,
 'id_str': '571327535436292096',
 'lang': 'en',
 'contributors': None,
 'source': '<a href="http://twipple.jp/" rel="nofollow">ついっぷる\u3000</a>',
 'in_reply_to_user_id_str': None,
 'retweeted': False,
 'text': 'hoge',
 'in_reply_to_user_id': None,
 'in_reply_to_screen_name': None,
 'created_at': 'Fri Feb 27 15:14:33 +0000 2015',
 'user': {'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png',
  'description': '死にかけ院生。好きな言語:Python',
  'profile_text_color': '333333',
  'protected': False,
  'friends_count': 103,
  'default_profile_image': False,
  'is_translation_enabled': False,
  'id_str': '636457417',
  'lang': 'ja',
  'notifications': False,
  'profile_background_color': 'C0DEED',
  'following': False,
  'profile_background_tile': False,
  'url': 'http://t.co/0IdlKznLSe',
  'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png',
  'screen_name': 'matsulib',
  'profile_banner_url': 'https://pbs.twimg.com/profile_banners/636457417/1420178021',
  'location': '京都',
  'profile_sidebar_fill_color': 'DDEEF6',
  'profile_sidebar_border_color': 'C0DEED',
  'profile_image_url_https': 'https://pbs.twimg.com/profile_images/444071974105382912/04h61MUk_normal.png',
  'default_profile': True,
  'created_at': 'Sun Jul 15 20:56:47 +0000 2012',
  'profile_image_url': 'http://pbs.twimg.com/profile_images/444071974105382912/04h61MUk_normal.png',
  'name': 'まつ',
  'profile_location': None,
  'profile_use_background_image': True,
  'time_zone': 'Irkutsk',
  'listed_count': 2,
  'utc_offset': 32400,
  'contributors_enabled': False,
  'entities': {'description': {'urls': []},
   'url': {'urls': [{'display_url': 'matsulib.hatenablog.jp',
      'expanded_url': 'http://matsulib.hatenablog.jp/',
      'indices': [0, 22],
      'url': 'http://t.co/0IdlKznLSe'}]}},
  'profile_link_color': '0084B4',
  'favourites_count': 654,
  'is_translator': False,
  'follow_request_sent': False,
  'geo_enabled': False,
  'statuses_count': 1956,
  'followers_count': 101,
  'id': 636457417,
  'verified': False},
 'in_reply_to_status_id_str': None,
 'favorite_count': 0,
 'geo': None,
 'retweet_count': 0,
 'coordinates': None,
 'entities': {'symbols': [], 'user_mentions': [], 'hashtags': [], 'urls': []},
 'id': 571327535436292096}

該当するデータフレームの行は次のようになる。これを使ったデータ分析のアイデアはない。

In [52]: tweets.ix[1]
Out[52]:
created_at     Fri Feb 27 15:14:33 +0000 2015
text                                     hoge
id                         571327535436292096
name                                       まつ
screen_name                          matsulib
Name: 1, dtype: object

タイムゾーンのアレで時間がズレてる。本では最後のほうで解説されるらしいから放置(´・ω・`)
以下、追記

データベース

いろいろなデータベース(ここではMongoDB)に書き出したり、逆にデータベースからデータフレームに抜き出すこともできる。さっき作ったデータフレームtweetsを保存して読み出してみる。

import pymongo

con = pymongo.Connection()
twidb = con.db.twidb
for tweet in tweets.T.to_dict().values():
    twidb.save(tweet)

# 自分のツイートを検索
cursor = twidb.find({'screen_name': 'matsulib'})
simple_fields = ['name', 'text', 'created_at']
result = DataFrame(list(cursor), columns=simple_fields)
print(result)
  name            text                      created_at
0   まつ  MongoDBやってる。。。  Fri Feb 27 18:58:32 +0000 2015
1   まつ   twitter API と  Fri Feb 27 18:58:15 +0000 2015