Pythonでネット上にある画像をダウンロードして、Twitterなどのapiを使ってアップロードすることがたまにあるのですが、一度ローカルストレージにファイルを保存してからアップロードのが通常かと思います。
コードにするとこんな感じ。
import requests
imgUrl = 'https://www.python.org/static/img/python-logo.png'
r = requests.get(imgUrl)
with open('sample.png', 'wb') as f:
f.write(r.content)
ストレージにPythonのロゴの画像がダウンロードされるはずです。
で、今回はストレージに画像を保存しないでそのままアップロードする方法を見つけたのでシェアハピします。
標準ライブラリのio.BytesIOに画像のバイナリデータを渡してあげるだけです。
import requests
from io import BytesIO
imgUrl = 'https://www.python.org/static/img/python-logo.png'
r = requests.get(imgUrl)
img = BytesIO(r.content)
変数imgにはインメモリーで扱えるファイルオブジェクトが入ります。これにより保存する必要がないファイルの場合にはストレージを圧迫しなくて済みます。GAEなどのread-onlyなPaaSなどで画像ファイルを扱う際にはめちゃくちゃ便利です。
試しにTweepyで画像をアップロードしてみます。
import tweepy
import requests
from io import BytesIO
consumer_key = 'your_consumer_key'
consumer_secret = 'your_consumer_secret'
access_key = 'your_access_key'
access_secret = 'your_access_secret'
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_key, access_secret)
api = tweepy.API(auth)
# 通常
imgUrl = 'https://www.python.org/static/img/python-logo.png'
r = requests.get(imgUrl)
with open('sample.png', 'wb') as f:
f.write(r.content)
api.update_with_media('sample.png', status='test')
# BytesIOを使う場合
imgUrl2 = 'https://www.python.org/static/img/python-logo.png'
r2 = requests.get(imgUrl2)
img2 = BytesIO(r2.content)
result_img = api.media_upload(filename='sample2.png', file=img2)
api.update_status(status='test2', media_ids=[result_img.media_id])
通常ローカルストレージにある画像指定してアップロードするメソッドである、update_with_media
ではファイルオブジェクトを扱うことができないのでmedia_upload
メソッドを使います。これによりアップロードされた画像のmedia_idを通常のツイートメソッドであるupdate_status
のmedia_idsの引数に渡すことでツイートが完了します。
ちなみにですがTweepyの公式リファレンスのupdate_with_mediaメソッドの欄を読むと
Deprecated: Use API.media_upload() instead. Update the authenticated user’s status. Statuses that are duplicates or too long will be silently ignored.
(非推奨:代わりにAPI.media_upload()を使用してください。 認証済みユーザーのステータスを更新します。 重複している、または長すぎる状況は黙って無視されます。)(Google翻訳)
だそうです。update_with_mediaは画像を一枚アップロードするだけなら一行で済むので便利でしたが、今後はmedia_uploadを使ったほうが良さそうです。