意味悲鳴

PythonとかUnityとか.技術ブログでしたが,研究ブログにシフトしました.

Python3でふぁぼったツイートに添付された画像を一括ダウンロードする

こんばんは。

なんとなーくPython3に慣れてきたような気がするので、そろそろ何か面白いことがしたいと思い、使い道がありそうな画像収集するスクリプトを書いてみようと思いました。タイトルがわかりづらいと思いますのでもう少し丁寧に書くと、「特定のアカウントがふぁぼったツイートのうち、画像が添付されたツイートから、一括で画像をダウンロードする」スクリプトです。

参考にさせていただいたページは後ほど。

とりあえずこんな感じ。

# -*- coding:utf-8 -*-

from requests_oauthlib import OAuth1Session
import json
import os
import sys
import urllib
                                                                                                                                           
oath_key_dict = {
    "consumer_key": "なんたらかんたら",
    "consumer_secret": "なんたらかんたら",
    "access_token": "なんたらかんたら",
    "access_token_secret": "なんたらかんたら"
}

save_path = os.path.abspath('任意のファイルパスを指定')

image_number = 0  #画像の通し番号をつけるための変数。お好みで。
get_pages = 10      
count = 200         #count * get_pages だけツイートをさかのぼってくれる。今回は2000ツイート。

def create_oath_session(oath_key_dict):
    oath = OAuth1Session(
    oath_key_dict["consumer_key"],
    oath_key_dict["consumer_secret"],
    oath_key_dict["access_token"],
    oath_key_dict["access_token_secret"]
    )
    return oath

def fav_tweets_get(page, oath_key_dict):
    url = "https://api.twitter.com/1.1/favorites/list.json?"
    params = {
        "screen_name" : "任意のID、@以下の部分。私だったら「zyusou」と入れる",
        "page": page,
        "count" : count,
        "include_entities" : 1     #ツイートのメタデータ取得。これしないと複数枚の画像に対応できない。
        }
    oath = create_oath_session(oath_key_dict)
    responce = oath.get(url, params = params)

    if responce.status_code != 200:
        print("Error code: {0}".format(responce.status_code))
        return None
    
    tweets = json.loads(responce.text)
    return tweets

def image_saver(tweets):
    global image_number 
    for tweet in tweets:
        try:
            image_list = tweet["extended_entities"]["media"]

            for image_dict in image_list:
                url = image_dict["media_url"]
                url_large = url + ":large"
                with open(save_path+ "/" + str(image_number) + "_" + os.path.basename(url), 'wb') as f:
                    img = urllib.request.urlopen(url_large, timeout = 5).read()
                    f.write(img)
                print("done!")
                image_number += 1

        except KeyError:
            print("KeyError:画像を含んでいないツイートです。")
        except:
            print("Unexpected error:", sys.exc_info()[0])

if __name__ == "__main__":
    for i in range(1, get_pages):
        tweets = fav_tweets_get(i, oath_key_dict)
        image_saver(tweets)

json周りの読み方が汚いしいろいろとPythonっぽくない気はしますが、まぁ、動いてるし、便利だし、ね。気になった点としては、twitter側から返ってくるjsonがpage=0とpage=1で全く一緒だったってことでしょうか。理由がわからないのですが、とりあえずpage=1から叩くようにしています。

パラメータの"include_entities"ってやつはtrueか1にしておかないと最初の画像分のURLしか返してくれないみたいです。故に今回は1にしてます。
あと、画像のURLの最後にクエリ(というか文字列)を追加してあげると画像のサイズを指定出来るので、今回は最大サイズだと思われるlargeを指定してあります。

参考にさせていただいたページ
Python で Twitter から情報収集 (Twitter API 編) - Qiita
twitter - TwitterAPI 1.1 REST API の 画像取得方法について - スタック・オーバーフロー
GET favorites/list | Twitter Developers
Entities in Objects | Twitter Developers