LoginSignup
3
5

More than 5 years have passed since last update.

Flickr APIをPythonでたたいて画像検索・EXIF取得する

Last updated at Posted at 2018-05-03

はじめに

Flickrに投稿する人のカメラの設定を分析できるように、Flickr APIを使って画像検索、EXIF取得できるPythonプログラムを作ってみた。
FlickrAPIの導入についてはいろいろなサイトで紹介があるので割愛するが、例えばこちらを参照。

pythonプラグラム

参考文献

以下の情報を参考にして、プログラムを作成した。

上記に対してオリジナルなところはEXIFを取得することで、jsonデータの平滑化をすることでCSVファイルに所望の状態でEXIF情報を書きだすことができた。

作成ポイント

ライブラリ

以下のライブラリをimportして設計した。

Flickr APIへのアクセスはrequestsを使用する。

auth key情報

Flickr APIを使えるようにすると自分のkeyが発行されるので、それをauth_flickr.pyに記載する。

auth_flickr.py
flickr_key = "1234567890abcdefghijklmnopqrstuv"

メインプログラム側では、上記をimportする。

from auth_flickr import(
    flickr_key
)

Flickr画像の検索

画像検索用のペイロードをjson形式で作成し、Flickr APIflickr.photos.searchを使うリクエストを投げて、画像検索する。

#画像検索用のjsonデータ
payload = {
    'method': 'flickr.photos.search',
    'api_key': flickr_key,
    'text': 'mountain moon',
    #'extras': 'date_upload',
    #'has_geo': 1,
    #'place_id' : '36i2ieFQU7uqDINu',
    'per_page': '10',
    'format': 'json',
    'nojsoncallback': '1'
    }

#画像検索
r = requests.get(url, params=payload)
resp = r.json()
#print (json.dumps(resp, sort_keys=True, indent=2))

'text'には、検索したいキーワードを記載する。AND条件は半角スペースで併記すればよいようだが、やや検索結果が所望とは外れてくるようだ。

'text'は日本語もOKだが、(ほぼ)日本人の撮影した写真に限定される。。。

'per_page'で指定した数だけ検索する。この例では10個検索している。

'place_id'を定義すると、写真の撮影された場所を限定できる。'place_id'は、こちらで検索できる。これがなかなか見つけられず苦労した。コメントのものはyokohama'place_id'

画像検索結果の取得とEXIF情報の取得

表示用URLの雛型記述をPhoto Source URLsに従ってtpl_urlに準備する。

#表示用URLの雛型
tpl_url = 'https://farm%s.staticflickr.com/%s/%s_%s.jpg'

以下はfor文で一気に記載している。

検索結果はjson形式でrespに格納されているので、検索結果の情報が格納されているresp['photos']['photo']を順次呼び出して、表示用URLを生成、画像取得する。

次に、EXIF取得用のペイロードをjson形式で作成し、Flickr APIflickr.photos.getExifを使うリクエストを投げて、結果をresp2に格納する。

EXIFが取得できない画像もあるので、リクエスト結果をチェックしてresp2['stat'] == 'fail'であれば、EXIFをCSV化する処理をスキップする。

EXIFが取得出来たらpandasでjsonデータを平たん化して、csvに書き出す。これをやらずにpd.DataFrame(resp2['photo']['exif'])としてしまうと、EXIF情報が1つのセル情報にまとまって書き出されてしまうので、注意。

#検索結果画像の情報処理
count = 1
for i in resp['photos']['photo']:
    #表示用URLの生成
    img_url = tpl_url % (i['farm'],i['server'],i['id'],i['secret'])
    print ("#%04d" % count, img_url)

    #画像取得
    r = requests.get(img_url)
    fname = "%04d.jpg" % count
    f = open(fname, 'wb')
    f.write(r.content)
    f.close()

    #EXIF取得用のjsonデータ
    payload2 = {
        'method': 'flickr.photos.getExif',
        'api_key': flickr_key,
        'photo_id' : i['id'],
        'format': 'json',
        'nojsoncallback': '1'
    }

    #EXIF取得
    r2 = requests.get(url, params=payload2)
    resp2 = r2.json()
    #print (json.dumps(resp2, sort_keys=True, indent=2))

    #EXIFがない場合はスキップする
    if resp2['stat'] == 'fail' :
        count += 1
        continue

    #pandasでjsonデータを平たん化してcsvに書き出す
    df = pd.read_json(json.dumps(resp2, sort_keys=True, indent=2))
    #exif = pd.DataFrame(resp2['photo']['exif'])
    exif = pd.io.json.json_normalize(resp2['photo']['exif'])
    exif.to_csv("%04d.csv" % count)

    count += 1

作成結果

メインプログラム全体は以下。関数化すればよい部分もあるが、実験用の初版なのでこれで良しとした。

GetFlickrImagesExif.py
# -*- coding: utf-8 -*-
import json
import requests
import pandas as pd

url = 'https://api.flickr.com/services/rest/'
from auth_flickr import(
    flickr_key
)

#画像検索用のjsonデータ
payload = {
    'method': 'flickr.photos.search',
    'api_key': flickr_key,
    'text': 'mountain moon',
    #'extras': 'date_upload',
    #'has_geo': 1,
    #'place_id' : '36i2ieFQU7uqDINu',
    'per_page': '10',
    'format': 'json',
    'nojsoncallback': '1'
    }

#画像検索
r = requests.get(url, params=payload)
resp = r.json()
#print (json.dumps(resp, sort_keys=True, indent=2))

#表示用URLの雛型
tpl_url = 'https://farm%s.staticflickr.com/%s/%s_%s.jpg'

#検索結果画像の情報処理
count = 1
for i in resp['photos']['photo']:
    #表示用URLの生成
    img_url = tpl_url % (i['farm'],i['server'],i['id'],i['secret'])
    print ("#%04d" % count, img_url)

    #画像取得
    r = requests.get(img_url)
    fname = "%04d.jpg" % count
    f = open(fname, 'wb')
    f.write(r.content)
    f.close()

    #EXIF取得用のjsonデータ
    payload2 = {
        'method': 'flickr.photos.getExif',
        'api_key': flickr_key,
        'photo_id' : i['id'],
        'format': 'json',
        'nojsoncallback': '1'
    }

    #EXIF取得
    r2 = requests.get(url, params=payload2)
    resp2 = r2.json()
    #print (json.dumps(resp2, sort_keys=True, indent=2))

    #EXIFがない場合はスキップする
    if resp2['stat'] == 'fail' :
        count += 1
        continue

    #pandasでjsonデータを平たん化してcsvに書き出す
    df = pd.read_json(json.dumps(resp2, sort_keys=True, indent=2))
    #exif = pd.DataFrame(resp2['photo']['exif'])
    exif = pd.io.json.json_normalize(resp2['photo']['exif'])
    exif.to_csv("%04d.csv" % count)

    count += 1

デバッグで、EXIF情報の一部を標準出力に出した時の記述は以下。json形式にまだ慣れていなくて、記述方法はけっこう試行錯誤した。

    #標準出力にEXIFの情報を選択して出力する場合
    for j in resp2['photo']['exif']:
        if j['label'] == 'Model' :
            print(j['raw']['_content'])
        elif j['label'] == 'Exposure' :
            print(j['raw']['_content'])
        elif j['label'] == 'Aperture' :
            print(j['raw']['_content'])
        elif j['label'] == 'ISO Speed' :
            print(j['raw']['_content'])

やってみる

以下を実行し、FlickrAPIで所望の画像を検索し、EXIF情報を取得してCSVに書き出すことができた。

$ python3 GetFlickrImagesExif.py

さいごに

これまで作成してきたpythonのrequestsで、FlickrAPIも比較的早く使いこなせるようになった。

今回のプログラムは、EXIFのCSVファイルが画像ファイルごとにできる仕様だが、分析用にはひとつのCSVファイルにまとまっていると使いやすい。

pandasは初めて使ったが、もっと多くの機能があるようなので、使いこなせるようになるとよいと感じた。

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5