【顔分類その１】PythonとGoogleカスタム検索APIを利用した画像ダウンロード

## 目的

PythonとGoogleカスタム検索APIを利用した画像ファイルのダウンロードを試してみました。
キーワードに一致する画像をダウンロードします。

実装方法は https://blog.aidemy.net/entry/2017/12/17/214715 を参考にさせて頂きました。

## 参考

[【顔分類その１】PythonとGoogleカスタム検索APIを利用した画像ダウンロード](https://qiita.com/kerobot/items/f98b73cbd5f52c1fdac2)
[【顔分類その２】PythonとOpenCVを利用した画像ファイルからの顔の切り出し](https://qiita.com/kerobot/items/e3abe3f21808b4b584bd)
[【顔分類その３】PythonとOpenCVを利用した画像ファイルの水増し](https://qiita.com/kerobot/items/54bc1224424280150d1c)
[【顔分類その４】Pythonとkerasを利用した顔分類モデルの生成](https://qiita.com/kerobot/items/be4fd1a166073fbcff38)
[【顔分類その５】Pythonとkerasを利用して本田翼か佐倉綾音かを分類](https://qiita.com/kerobot/items/1ce75622d173d231d423)
[【顔分類その６】Djangoとkerasを利用した本田翼か佐倉綾音かを分類するWebアプリ](https://qiita.com/kerobot/items/65d4e1942a31c00317e2)

## 環境

* Windows 10 x64 1809
* Python 3.6.5 x64
* Power Shell 6 x64
* Visual Studio Code x64
* Git for Windows x64

## Custom Search API の有効化とキーの取得

1. [Google Cloud Platform](https://console.cloud.google.com/) にログインし、新しいプロジェクトを作成します。

1. 作成したプロジェクトのダッシュボードにある「APIとサービスを有効化」をクリックします。

1. 「APIサービス」で「Custom Search API」を検索してクリックします。

1. 「Custom Search API」が有効であることを確認して「管理」をクリックします。

1. 「Custom Search API」の管理で「認証情報」をクリックします。

1. 「認証情報」でAPIのキーをコピーします。（このキーをあとで利用します。）

## 画像の検索エンジンの作成

1. [カスタム検索エンジン](https://cse.google.com/cse/all)にログインし、検索エンジンを追加します。

1. 「検索するサイト」にwww.google.co.jpを入力、「言語」を選択、「検索エンジンの名前」を入力して「作成」をクリックします。（「検索するサイト」はあとで削除しますので任意のURLで構いません）

1. 作成した検索エンジンを編集します。

1. 「検索エンジン ID」をコピーします。（このIDをあとで利用します。）

1. 「検索するサイト」を削除し、「画像検索」をON、「ウェブ全体を検索」をONにして「更新」をクリックします。

## 環境構築

* Windows 10 x64 に Python 3.6.x x64 をインストールします。

* 環境変数の PATH に、インストールしたPythonのフォルダとPython\Scriptsフォルダを設定しておきます。

* 下記手順で Python の仮想環境を構築し、有効化してpipをアップデートします。

```powershell
> python -m venv venv
> .\venv\Scripts\activate.ps1
(venv)> python -m pip install --upgrade pip
```

* pip でいろいろインストールします。

```powershell
(venv)> pip install pylint
(venv)> pip install requests
(venv)> pip install python-dotenv
(venv)> pip install google-api-python-client
```

* Google API を利用するためのキーとIDを設定した.envファイルを作成します。

> 事前にコピーしたキーとIDを設定します。

```python
# API KEY
API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# 検索エンジンID
CUSTOM_SEARCH_ENGINE = "000000000000000000000:XXXXXXXXXXX"
```

## プログラム作成

* 画像をダウンロードするプログラムを Python で書きます。

* ファイル名は「img_dl_gcs.py」とします。

```python
import os
import sys
from urllib.parse import quote
import requests
import settings

# 指定したキーワードで検索した画像のURLを取得
def get_image_urls(keyword, total_num):
    image_urls = []
    i = 0
    while i < total_num:
        # クエリの組み立て
        query = CUSTOM_SEARCH_URL + "?key=" + settings.API_KEY + \
                "&cx=" + settings.CUSTOM_SEARCH_ENGINE + "&num=" + \
                str(10 if(total_num-i) > 10 else (total_num-i)) + "&start=" + \
                str(i+1) + "&q=" + quote(keyword) + "&searchType=image"
        print(query)
        # GETリクエスト
        response = requests.get(query)
        # JSONデータ取得
        json = response.json()
        # 10件ずつのURLを格納
        for j in range(len(json["items"])):
            image_urls.append(json["items"][j]["link"])
        i = i + 10
    return image_urls

# 画像のURLをもとに画像をダウンロードして保存
def get_image_files(dir_path, keyword_count, image_urls):
    # 画像urlループ
    for (idx, image_url) in enumerate(image_urls):
        try:
            # 画像をダウンロード
            print(image_url)
            image = download_image(image_url)
            # ファイル名を作成
            filename_extension_pair = os.path.splitext(image_url)
            extension = filename_extension_pair[1]
            extension = extension if len(extension) <= 4 else extension[0:4]
            filename = os.path.join(dir_path, f"{keyword_count:02}_{idx+1:03}{extension}")
            print(filename)
            # 画像をファイルとして保存
            save_image(filename, image)
        except RuntimeError as ex:
            print(f"type:{type(ex)}")
            print(f"args:{ex.args}")
            print(f"{ex}")
            continue
        except BaseException as ex:
            print(f"type:{type(ex)}")
            print(f"args:{ex.args}")
            print(f"{ex}")
            continue

# 画像をダウンロード
def download_image(url):
    response = requests.get(url, timeout=100)
    if response.status_code != 200:
        raise RuntimeError("画像が取得できません")
    content_type = response.headers["content-type"]
    if 'image' not in content_type:
        raise RuntimeError("画像ではありません")
    return response.content

# 画像をファイルとして保存
def save_image(filename, image):
    with open(filename, "wb") as file:
        file.write(image)

# ディレクトリまたはディレクトリ内のファイル削除
def delete_dir(dir_path, is_delete_top_dir=True):
    for root, dirs, files in os.walk(dir_path, topdown=False):
        for name in files:
            os.remove(os.path.join(root, name))
        for name in dirs:
            os.rmdir(os.path.join(root, name))
    if is_delete_top_dir:
        os.rmdir(dir_path)

RETURN_SUCCESS = 0
RETURN_FAILURE = -1
# Custom Search Url
CUSTOM_SEARCH_URL = "https://www.googleapis.com/customsearch/v1"
# Download Directory Path
ORIGIN_IMAGE_DIR = "./origin_image"

def main():
    print("===================================================================")
    print("イメージダウンローダー Google Customr Search API 版")
    print("指定したキーワードで検索した画像ファイルをダウンロードします。")
    print("===================================================================")

    # 引数のチェック
    argvs = sys.argv
    if len(argvs) != 2 or not argvs[1]:
        print("キーワードを指定してください。（カンマ区切り可能）")
        return RETURN_FAILURE

    # キーワードの取得
    keywords = [x.strip() for x in argvs[1].split(',')]

    # ディレクトリの作成
    if not os.path.isdir(ORIGIN_IMAGE_DIR):
        os.mkdir(ORIGIN_IMAGE_DIR)
    delete_dir(ORIGIN_IMAGE_DIR, False)

    # キーワードごとに画像ファイル取得
    keyword_count = 1
    for keyword in keywords:
        # キーワード表示
        print(f"キーワード「{keyword}」で検索した画像ファイルをダウンロードします。")
        # 画像URL取得
        image_urls = get_image_urls(keyword, 100)
        # 画像ファイルのダウンロード
        get_image_files(ORIGIN_IMAGE_DIR, keyword_count, image_urls)
        # カウントアップ
        keyword_count = keyword_count + 1

    return RETURN_SUCCESS

if __name__ == "__main__":
    main()
```

* 設定ファイルを読み込むプログラムを Python で書きます。

* ファイル名は「settings.py」とします。

```python
import os
from os.path import join, dirname
from dotenv import load_dotenv

dotenv_path = join(dirname(__file__), '.env')
load_dotenv(dotenv_path)

API_KEY = os.environ.get("API_KEY")
CUSTOM_SEARCH_ENGINE = os.environ.get("CUSTOM_SEARCH_ENGINE")
```

## プログラム実行

* 検索するキーワードを指定して実行します。

```powershell
(venv)> python img_dl_gcs.py あのひと,このひと
```

* origin_imageフォルダにダウンロードした画像が保存されます。

> 拡張子を特定できないファイルも関係なくダウンロードされます。

## 最後に

深層学習で画像の分類を行いたいという勢いから、いろいろな情報を参考にやってみました。
Google の Custom Search API は検索数の制限がありますので、ダウンロード数の上限を100枚としています。