Twitter (tweepy)

[追記] API 1.1の終了により、現在ではこの方法は使えません。

tweepy(GitHub: tweepy)は Python で Twitter API を呼び出すツールの一つ。

インストール:

pip install tweepy

まずは Twitter の Developer Portal の Dashboard でアプリケーション登録をする。

ここでは API 1.1 の Consumer Key,Consumer Secret,Access Token,Access Token Secret を使う方式について説明する。

ソースコードにこれらを直書きするのは危険なので、別の場所に保存する。例えば ~/.twitter.json に次のように書いて、他人には読めないようにしておく:

{
    "consumer_key": ".....",
    "consumer_secret": ".....",
    "access_token": ".....",
    "access_token_secret": "....."
}

これを読み出すコード:

import json
import os

with open(os.path.expanduser("~/.twitter.json")) as f:
    token = json.load(f)

これを使って api を取得する:

import tweepy

auth = tweepy.OAuth1UserHandler(
    token["consumer_key"], token["consumer_secret"],
    token["access_token"], token["access_token_secret"]
)

api = tweepy.API(auth)

まずは「ホーム」タイムラインを取得してみよう:

home = api.home_timeline(
    # count=20,                      # デフォルト20ツイート取得
    # since_id=1234567890123456789,  # これより大きい
    # max_id=1234567890123456789,    # これ以下
    tweet_mode="extended")           # 280文字対応

取得したツイートの表示例:

import datetime

tz = datetime.timezone(datetime.timedelta(hours=9))  # JST

for t in home:
    print(t.created_at.astimezone(tz).strftime('%Y-%m-%d %H:%M:%S'),
          t.id, t.user.screen_name)
    if hasattr(t, 'retweeted_status'):   # リツイートなら
        t = t.retweeted_status           # 元ツイート
        print(t.created_at.astimezone(tz).strftime('%Y-%m-%d %H:%M:%S'),
              t.id, t.user.screen_name)
    print(t.geo, t.coordinates, t.place)
    s = t.full_text
    s = s.replace("&lt;", "<")
    s = s.replace("&gt;", ">")
    s = s.replace("&amp;", "&")
    for u in t.entities["urls"]:         # t.coを元に戻す
        s = s.replace(u["url"], u["expanded_url"])
    print(s)
    print("-" * 60)

特定の1ツイートだけでよければ次のように取得する:

t = api.get_status(1234567890123456789, tweet_mode="extended")

書き込みはこんな感じ(通常はツイート本文だけでよい):

media = api.media_upload("/path/to/image.jpg")  # 添付メディアがある場合
status = api.update_status(
    "ツイート本文",
    # in_reply_to_status_id=1234567890123456789,  # リプライ先
    # auto_populate_reply_metadata=True, # リプライ先の @... を自動挿入
    # attachment_url="https://twitter.com/.../status/...", # 引用リツイート
    media_ids=[media.media_id],  # 静止画なら4つまで
    lat=34.7468, long=136.5248, display_coordinates=True,
    tweet_mode="extended")
print("Tweeted:", status.id)

引用リツイートは従来のようにツイート本文末尾にURLを書いてもいいが,attachment_url="..." で指定すると文字数カウントに入らない。リプライの先頭に付ける @... も,手で書く代わりに auto_populate_reply_metadata=True にすれば自動で入り,文字数カウントに入らない。

検索は次のようにする:

results = api.search_tweets(
    "検索クエリ",   # 500文字以内
    count=100,      # 最大100、デフォルト15
    result_type="recent",  # or "popular" or "mixed"
    # lang="ja",
    # locale="ja",
    # max_id=1234567890123456789,    # ≦ max_id
    # since_id=1234567890123456789,  # > since_id
    # until="2022-12-31",
    tweet_mode="extended")

公式アプリでの検索と異なり、無料では7日分の検索しかできない。いずれにしても検索クエリに合致するツイートが全部取得できるわけではない。

また、リツイートされたものは重複して取得されてしまう。これが嫌なら、次のように、すでに取得されたものは表示しないための工夫が必要になる:

shown = set()
for t in results:
    if hasattr(t, 'retweeted_status'):
        t = t.retweeted_status
    if t in shown:
        continue
    shown.add(t)
    # ツイートtを表示する

検索クエリの書き方については公式ドキュメント参照。ちなみに、公式アプリでの検索クエリについてはAdvanced Search on Twitterというガイドが参考になる。このガイドでは時刻指定の例は _UTC となっているが、これを _JST とすれば日本時間になる。例えば since:2022-11-19_01:23:45_JST until:2022-11-20_12:34:56_JST のようにできる。リツイートも含めるには include:nativeretweets とするが、これは7〜10日前までのツイートにしか適用されない。