TweepyでURLを入手するときの注意点

戦国時代で嫌味そうだけど、嫌味ではない、やっぱり少し嫌味な武将というと石田三成。
どうも、クリーク・アンド・リバー社 COYOTE CG STUDIO テクニカルチーム 戦国大好き人間の中林です。

PythonでTwitterを操作することが出来る「Tweepy」というパッケージがあり、ツイートやリツイート、ツイート検索などの様々な自動化がお手軽にでき、大変便利です。
今回はこのTweepyの導入事例で、少しだけ苦労した時の事を紹介したいと思います。

そもそものキッカケは?

当ブログ記事は、弊スタジオのTwitterアカウントとゆるく連動していて、新しくブログ記事がリリースされれば、Twitterで告知、以降定期的にそのツイートをリツイートしています。

このリツイート自体は、あらかじめツイートのIDをリストアップしておいたテキストをTweepyで組んだプログラムで読み込み、ランダムで選んで自動リツイートする…といった感じで、半自動で行っていました。

しかし、諸事情により当ブログの記事のURLが全更新されてしまい…、泣く泣くこのIDテキストの中身を一新する必要性が発生しました。
過去Tweetのログを調べて、IDをコピペしてメモする…でもまぁよかったのですが、せっかく目の前にTweepyがあるのだから、これを使って自動で該当のTweet IDを再取得してみることにしました。

URL取得失敗例

簡単に以下の事をやればOKなので作ってみました。

  1. 全ツイートを検索
  2. リツイートとリプライは対象外
  3. URLが埋め込まれているか確認
  4. URLのアドレスがCOYOTEブログだったらID取得

ツイートのログからURLを取得できれば後は文字列の比較だけでできます。
で、運よく早い段階で.entities['urls']の['expanded_url']でURLを取得できることが分かりました。

import tweepy,config

# 情報は念のため別configファイルに保存
CK = config.CONSUMER_KEY
CS = config.CONSUMER_SECRET
AT = config.ACCESS_TOKEN
ATS = config.ACCESS_TOKEN_SECRET

auth = tweepy.OAuthHandler(CK, CS)
auth.set_access_token(AT, ATS)
api = tweepy.API(auth)

# 全ツイートを取得
_allTweets = []

# 直近の200ツイート分を取得、一度に200ツイートしか取得できないため
latest_tweets = api.user_timeline(count=200)
_allTweets.extend(latest_tweets)

# 取得するツイートがなくなるまで繰り返す
while len(latest_tweets)>0:
    latest_tweets = api.user_timeline(count = 200, max_id = _allTweets[-1].id-1)
    _allTweets.extend(latest_tweets)

# URLのあるツイートのIDを取得
for _tweet in _allTweets:
    # リツイートとリプライは対象外
    if (_tweet.text.startswith('RT')) or (_tweet.text.startswith('@')):
        continue
    # ブログへのリンクが無いツイートは対象外
    if len(_tweet.entities['urls']) <= 0:
        continue
    # IDとURLを表示
    for _url in _tweet.entities['urls']:
        print(_tweet.id)
        print(_url['expanded_url'])

・結果:成功例
ID:1324109468423118849
URL:https://tech-coyote.com/archives/402


これでURLとIDが取得できました。
あとはURLの文字列で「tech-coyote」などが含まれてるとIDテキストに保存とかで終わります。
…が、上記をリリース後に、幾つかのブログが含まれてないと報告がありました。

改めて調べると


・結果:失敗例
ID:1326283632013697025
URL:https://twitter.com/i/web/status/1326283632013697025


幾つか社内のブログにリンクされたツイートなのに['expanded_url']の内容が「埋め込まれたURL」ではなく、「そのツイート自体のURL」になっている例がありました。
なまじ、上手く取得できるものと取得できないものがあるので混乱をしました。

URL失敗の犯人は文字数オーバー

色々と調べるとURLのフルパスを含む文字数が140文字(115文字説もあり)を超えると['expanded_url']は圧縮されて取得できないアドレスになるようです。

原因が分かると簡単でしツイートを取得する時にモードを変えるだけで良いだけです。

↓変更前
latest_tweets = api.user_timeline(count=200, tweet_mode="extended")
while len(latest_tweets)>0:
    latest_tweets = api.user_timeline(count = 200, max_id = _allTweets[-1].id-1)
    _allTweets.extend(latest_tweets)
↓変更後
latest_tweets = api.user_timeline(count=200)
while len(latest_tweets)>0:
    latest_tweets = api.user_timeline(count = 200, max_id = _allTweets[-1].id-1, tweet_mode="extended")
    _allTweets.extend(latest_tweets)

これで、モードを「tweet_mode="extended"」変えれば圧縮前のアドレスが取得できます。


・結果:成功例
ID:1326283632013697025
URL:https://tech-coyote.com/archives/682


これで先ほどは失敗したURLを取得できました。
なかなか、文章の文字数は意識できませんでした。

ただし、ここで注意が必要なのはツイートの文章を見るモードが自動で「full_text」モードに変わります。
文章の文字列を見ていて部分はtextからfull_textに変更をする必要があります。

↓変更前
    if (_tweet.text.startswith('RT')) or (_tweet.text.startswith('@')):
↓変更後
    if (_tweet.full_text.startswith('RT')) or (_tweet.full_text.startswith('@')):

もし、文章の内容をみてる場合は注意が必要です。
まさか、ツイートの文字数の違いでこんなに苦労をするとは思いませんでした。

まとめ

今回はTweepyでURLを探すだけでした。やろうと思えば自分の全ツイートを見て色々なことを調べることができます。
もし、機会があればTweepyや他のモジュールでも良いのでツイートの内容を探ると面白い発見があるかもしれません。

--------------------------------------------------------------------------------

COYOTE 3DCG STUDIO

公式HP:https://www.creativevillage.ne.jp/lp/coyote/

COYOTE 3DCG STUDIOはクリーク・アンド・リバー社が運営するゲーム専門3DCG制作集団です。
キャラモデル、背景モデル、3Dアニメーション、テクニカルアーティストによるツール開発などを得意としています。
新規立ち上げにおけるコンサルティングから量産制作まで幅広く対応可能な体制を保有しており、出向にも柔軟に対応しております。

--------------------------------------------------------------------------------

Author: nakabayashinobukazu