Twitterのツイート検索APIを使って画像を自動収集する

こんにちは。

9月頃から趣味で機械学習の勉強をしています。機械学習に取り組む上での最重要作業のひとつとして「テストデータの収集」があります。例えば画像を使って物体認識させたいなら、大量の画像データが必要です。

ではそれらの画像を一つ一つ手作業で集めるのかと言えば、Noです。各検索プロバイダのAPIを使うことで手軽に大量*1の画像データを集めることができます。

ということで、Twitterのツイート検索APIを用いて画像を自動収集するプログラムを作成したので紹介します。

Twitterアプリケーションの登録

TwitterAPIを利用するにはアプリケーション登録を行い、Oauth認証用のキーを取得する必要があります。

まずはTwitter Application Managementへアクセスし、自分のTwitterアカウントでログインします。
Twitter Application Manager

次に右上の「Create New App」をクリックします。 f:id:WorldWorldWorld:20171224102650p
(私の画面では登録済みのアプリケーションが表示されていますが、初利用時にはこの画面は空白です。)

登録するアプリケーションの入力フォームが出ます。
Create an application

「Name」「Description」「Website」は必須入力項目です。適当な内容で入力します。

  • Name:アプリケーションの登録名
  • Description:アプリケーションの説明文
  • Website:アプリケーションの問い合わせ先が分かるようなURLを入力します。私の場合はとりあえず当ブログのURLを登録しています。
  • CallbackURL:画像収集用にAPIを利用する場合は入力不要です。

入力したらページ最下部の「Create your application」をクリックします。 Create your twitter application

これでアプリケーションの登録が完了しました。
f:id:WorldWorldWorld:20171224104225p:plain

続いてAPIの利用に必要となるAccess Tokenの発行を行います。表示されたページのタブ「Keys And Access Tokens」から「Create my access token」をクリックします。
f:id:WorldWorldWorld:20171224104509p:plain

これで準備は完了です。先程のページに表示されている「Consumer Key」「Consumer Secret」「Access Token」「Access Token Secret」をプログラム内で利用します。
f:id:WorldWorldWorld:20171224104655p:plain

ツイッター画像収集プログラム

今回はPython3.6.1(Anaconda 4.4.0)で作成しました。

なおTwitterのsearch APIは画像のみを対象に検索することはできません。キーワードで検索した全ツイートから、画像を含むものを抽出します。


こちらが検索プログラム本体です。「Consumer Key」「Consumer Secret」「Access Token」「Access Token Secret」にアプリケーション登録で取得した値を設定します。

https://github.com/quotto/imagecrawler/blob/master/twitter_image_crawler.py

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

import requests
import requests_oauthlib
import json
import math
import imgutil

# image save path
directory = "/path/to/img"
imgutil.mkdir(directory)

url = "https://api.twitter.com/1.1/search/tweets.json"

# parameters
query = "キーワード"
lang = "ja"
result_type="recent" # 最新のツイートを取得
count = 100 # 1回あたりの最大取得ツイート数(最大100)
max_id = ''

total_count = 1000 # 取得ツイートのトータル
offset = math.floor(total_count/count) # ループ回数

# oauthの設定
consumer_key = "xxxxxxxxxx"
consumer_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
access_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
access_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
oauth = requests_oauthlib.OAuth1(consumer_key,consumer_secret,access_token,access_secret)

for i in range(offset):
    params = {'q':query,'lang':lang,'result_type':result_type,'count':count,'max_id':max_id}
    r = requests.get(url=url,params=params,auth=oauth)
    json_data = r.json()
    for data in json_data['statuses']:
        # 最後のidを格納
        max_id = str(data['id']-1)
        if 'media' not in data['entities']:
            continue
        else:
            for media in data['entities']['media']:
                if media['type'] == 'photo':
                    image_url = media['media_url']
                    try:
                        imgutil.download_img(directory,image_url)
                    except Exception as e:
                        print("failed to download image at {}".format(image_url))
                        print(e)
                        continue

注意点として、Twitterのツイート検索APIでは一回あたりに取得できる最大ツイート件数が100件です。そのため、100件を超えて検索したい場合は2回目以降のリクエストパラメータ「max_id」に、「前回検索で取得した最後のid - 1」を設定しています。これにより次の検索ではmax_id以下のidを持つツイートを検索します。


他のプログラムで再利用できる部分はimgutil.pyにまとめました。URLをハッシュ化したものをファイル名として端末内に保存します。

https://github.com/quotto/imagecrawler/blob/master/imgutil.py

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

import os
import requests
import urllib
import hashlib
import sha3
import os

def mkdir(path):
    if not os.path.exists(path):
        os.makedirs(path)

# 引数fをファイル名と拡張子(.は含まない)に分割する
def split_filename(f):
    split_name = os.path.splitext(f)
    file_name =split_name[0]
    extension = split_name[-1].replace(".","")
    return file_name,extension

def download_img(path,url):
    mkdir(path)
    _,extension  = split_filename(url)
    if extension.lower() in ('jpg','jpeg','gif','png','bmp'):
        encode_url = urllib.parse.unquote(url).encode('utf-8')
        hashed_name = hashlib.sha3_256(encode_url).hexdigest()
        full_path = os.path.join(path,hashed_name + '.' + extension.lower())

        r = requests.get(url)
        if r.status_code == requests.codes.ok:
            with open(full_path,'wb') as f:
                f.write(r.content)
            print('saved image...{}'.format(url))
        else:
            print("HttpError:{0}  at{1}".format(r.status_code,image_url))

パラメータや取得データの詳細は公式のAPIドキュメントを参照してください。
Standard search API — Twitter Developers


以上、Twitterのツイート検索APIを用いて画像収集するプログラムのご紹介でした。

次はGoogleとBingを使っての検索プログラムを作成してみたいと思います。

Twitter API ポケットリファレンス (POCKET REFERENCE)

Twitter API ポケットリファレンス (POCKET REFERENCE)

*1:ここで言う大量とは「趣味で取り組む程度には」くらいの意味