BETA

Google Custom Search APIを使って自動画像収集ツールを作ったった

投稿日:2019-11-13
最終更新:2019-11-14

GoogleのAPIを使って自動画像収集ツールが作れそうだったので、なんとか頑張って1日で作ってみました。
ターミナル上で検索ワードと保存フォルダ名を指定してコマンドを叩くと、自動で100枚画像をダウンロードしてくれます。
セーフティーサーチをオフにしてあるのでエログロ画像でもなんでもいけます。
画像をいちいちダウンロードしなくていいので、画像集めに使えるかな?

そこで今回は

  • Google Custom Search API を使うまでの流れ
  • 実際に作ったものの紹介と使い方
  • 苦労した点

これらをまとめていこうと思います。

Google Custom Search API を使うまでの流れ

  1. Custom Search APIの利用登録とAPIキーの取得
  2. Custom Search Engineの作成と検索エンジンIDの取得
  3. APIキーと検索エンジンIDを使用してGoogle 検索を実行

イメージとしては、APIキーを使って認証し検索エンジンIDを使って検索する感じです。

Custom Search APIの利用登録とAPIキーの取得

まずCusom Search APIの有効化とAPIキーの取得を行なっていきます。

https://console.cloud.google.com/cloud-resource-manager
最初に上記リンクにアクセス。

プロジェクトの新規作成を選択。

プロジェクト名を適当に決める。
場所は組織なしでOK。そのまま作成を選択。

無事プロジェクトが出来上がったら、次はメニューを開いて「APIとサービス」から「ライブラリ」を選択。

「Custom Search API」を検索し、出てきたらそれをクリック。

「Custom Search API」を有効にする。

無事有効化できたら、次は「APIとサービス」から「認証情報」を選択。

認証情報の作成をクリックし、APIキーを選択。

無事APIキーが作成できたら、次は「キーを制限」を選択。

  • 名前を適当に決める。
  • アプリケーションの制限はとりあえずなしで。
  • 「キーを制限」を選択し、APIから「Custom Search API」を選ぶ。

上記3つが完了したら、保存を選択。

これでAPIキーの作成は完了!
キーの値は後から使うので、どこかにメモっておきましょう。

Custom Search Engineの作成と検索エンジンIDの取得

次に検索するための検索エンジンを作成していきます。

https://cse.google.com/cse/all
まずは上記リンクにアクセス。

検索エンジンの編集から追加を選択。

検索するサイトはwww.google.com/*にして、言語は日本語、あとは名前を適当に決める。終わったら、作成を選択。

作成が無事完了したら、次はコントロールパネルに行く。

  • 検索エンジンIDをメモる。
  • 画像検索をオンに。
  • www.google.com/*を選択して、「ウェブ全体を検索」をオンにする。


上記が完了したら、準備は完了!
いよいよ、ここまでに作成したAPIキーと検索エンジンIDを使っていきます。

APIキーと検索エンジンIDを使用してGoogle 検索を実行

ではGoogle Custom Search APIを使って画像検索していきましょう!
curlコマンドを使って検索エンジンに対してリクエストを送るのですが、基本となるURLは次の通りです。
https://www.googleapis.com/customsearch/v1?key=[APIキー]&cx=[検索エンジンID]&searchType=image&q=[検索ワード]

これにいろいろ加えて

$ crul https://www.googleapis.com/customsearch/v1?key=[APIキー]&cx=[検索エンジンID]&searchType=image&q=[検索ワード]&lr=lang_ja&safe=off&num=10&start=1  

これをターミナルで実行します。
lr=lang_jaで検索言語を日本語に、safe=offでセーフティーサーチをオフに(最重要)、num=10で10件取得(10件がMAXです)、start=1で1つ目から取得、を設定しています。
パラメータはいろいろ設定できるので、詳しくはこちらを↓
https://developers.google.com/custom-search/v1/cse/list

上記コマンドを実行すると、JSON形式で下のようなデータが返ってきたら成功です!

"items": [  
  {  
   "kind": "customsearch#result",  
   "title": "What counts as nature? It all depends | UW News",  
   "htmlTitle": "What counts as \u003cb\u003enature\u003c/b\u003e? It all depends | UW News",  
   "link": "https://s3-us-west-2.amazonaws.com/uw-s3-cdn/wp-content/uploads/sites/6/2017/11/04133712/waterfall.jpg",  
   "displayLink": "www.washington.edu",  
   "snippet": "What counts as nature? It all depends | UW News",  
   "htmlSnippet": "What counts as \u003cb\u003enature\u003c/b\u003e? It all depends | UW News",  
   "mime": "image/jpeg",  
   "image": {  
    "contextLink": "https://www.washington.edu/news/2017/11/15/what-counts-as-nature-it-all-depends/",  
    "height": 1365,  
    "width": 2048,  
    "byteSize": 1760735,  
    "thumbnailLink": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS5cNNFLwJvX7l2Y3uxl7MTqzV0ppcJkPnHmOuLrwrVc6joPAkrk2Oywkg&s",  
    "thumbnailHeight": 100,  
    "thumbnailWidth": 150  
   }  
  },  

注意点

Google Custom Search APIでは一度に100枚までしか画像をとってこられません。
1ページにつき10枚あるので、11ページ以降はとってこられないですね・・。残念。

あと、無料枠は一日につき100回までしかリクエストできません。これ以上やろうとするとエラーが返ってきます。
ですので、上記のコマンドを100回叩くともうそれ以上はできないのでご注意を。

また、100回以上やりたいって方はクレジットカードを登録すればできるようになります。1日の上限は10000回で、1000回につき$5課金らしいです。
詳しくはこちらで確認してください↓
https://developers.google.com/custom-search/v1/overview

実際に作ったものの紹介と使い方

シェルスクリプトを丸ごと貼っておきます。
コマンド名は、その名もimgetです。

#!/bin/sh  

#########################################################  
# 使い方  
# 1. brew install nkf でエンコードツール nkf をインストール  
# 2. apikey と engineid を設定  
# 3. .zshrc などに export PATH=$HOME/bin:$PATH でパスを通す  
# 4. imget "検索ワード" "保存するフォルダ名" で実行  
#########################################################  

apikey=[APIキー]  
engineid=[検索エンジンID]  

# 引数が足りなければ警告を出す  
if [ -z $1 ]  
then  
    echo "検索キーワードを入れてください"  
    echo "下記に例を示します"  
    echo "\$ ${0} \"ペンギン 壁紙\" pengin-img"  
    exit  
elif [ -z $2 ]  
then  
    echo "保存するフォルダ名を入れてください"  
    echo "下記に例を示します"  
    echo "\$ ${0} \"ペンギン 壁紙\" pengin-img"  
    exit  
fi  

# 1個目の引数にエンコード処理を施して$keywordに代入  
keyword=$1  
echo $keyword | nkf -wMQLu | tr = % | tr \\n ! | sed -e 's/!//g' -e 's/%%/%/g' > keyword.txt #小文字が入った時上手くいかなかったので修正  
keyword=`cat keyword.txt`  
rm keyword.txt  

# 2個目の引数の名前のディレクトリを作って移動  
dir=$2  
mkdir $dir  
cd $dir  

start=1  
results=`mktemp`  
list_url=`mktemp`  

# keywordで画像検索して10回リクエストする、画像リンクを$list_urlに格納  
while [ $start -lt 100 ]  
do  
    curl "https://www.googleapis.com/customsearch/v1?key=${apikey}&cx=${engineid}&searchType=image&q=${keyword}&safe=off&lr=lang_ja&num=10&start=${start}" > $results  

    cat $results | grep "link" | sed -e 's/^[ \t]*"link": "//' -e 's/",//g' | sed 1d >> $list_url  

    start=`expr $start + 10`  
done  

# 画像リンクから画像を一気にダウンロード  
wget -T 30 -t 1 -i $list_url  

# 全ての画像に実行権限を与えて、拡張子がおかしいものを直す  
chmod u+rwx *  
find . -name '*.jpg[.?]*' | sed -e "s/^\(.*\)\.jpg[.?].*$/mv '&' \1\.jpg/g" | sh  
find . -name '*.png[.?]*' | sed -e "s/^\(.*\)\.png[.?].*$/mv '&' \1\.png/g" | sh  
find . -name '*.jpeg[.?]*' | sed -e "s/^\(.*\)\.jpeg[.?].*$/mv '&' \1\.jpeg/g" | sh  
find . -name '*.gif[.?]*' | sed -e "s/^\(.*\)\.gif[.?].*$/mv '&' \1\.gif/g" | sh  

# 画像ファイル以外は削除  
find . -not -name "*.jpg" -a -not -name "*.png" -a -not -name "*.jpeg" -a -not -name "*.gif" | xargs rm  
rm $results $list_url  

ホームディレクトリに bin という名前のディレクトリを作って、「imget」とかいう名前でそこに上記のスクリプトをおいてください。(名前はなんでもいいです)
あとは .zshrc 等の設定ファイルを作って、そこにexport PATH=$HOME/bin:$PATHみたいに記述してパスを通します。
終わったらターミナルを再起動。

これでターミナル上で$ imget "検索ワード" "保存するフォルダ名"と実行すれば画像100枚とってこれます!
簡単ですね!!

工夫した点

工夫した点としては、

  • 拡張子がおかしいものを全部正しく変換するようにした。
  • 画像ファイル以外は最後に全て消えるようにした。

上記2点ですかね。
特に一気にダウンロードしてくると、jpg?xxxxx_xxx.xxx とか jpg.12.3 とかいう拡張子の物がたくさんできたので、それらを全て .jpg で終わるようにしました。
また、変換しても直らなかったもの(例えば .php とかのファイル)は最後に消すようにしました。

苦労した点

画像ファイル名を一括置換する方法

元のファイル名から、sedコマンドで正規表現を使って置換したものにファイル名を変更するのか全然わからず、めちゃくちゃ調べまくりました。
いやあ、これは大変だった・・。
そこで以下の記事が一番参考になった↓

findとsedを利用した一行野郎のファイル名変換

どうやら、コマンドを実行する文字列を作って、それをshで実行してしまえばいいらしい。
ただ、ダウンロードしてきたファイルたちには実行権限がないので、あらかじめchmod u+rwx *で所有ユーザーには全ての権限を与えておく。

これでなんとかうまくいった!!
今後も一括置換はどこかで使えそうなので、調べてみて良かった。
(「1行でやろうとせず、複数行に分ければもっと簡単にできるんじゃ?」と後々思ったんですけど、まあそんなのは気にしない。)

sedでの正規表現がうまくいかない

これが一番ハマりましたねぇ。
「正しい正規表現を書いているはずなのに全然マッチしない!!おい!!!なんとかいったらどうなんだ!!!!このポンコツめ!!!!!!」
ってのが多くて多くて笑。

grepでこういう時はどうする?

ここら辺を見まくりながら、なんとかしました。
特に$ find . -name '*.jpg[.?]*' | sed -e "s/^\(.*\)\.jpg[.?].*$/mv '&' \1\.jpg/g" | shの部分。
これは

  1. aaaa.jpg?xxxxbbbb.jpg.12.3 といったファイルを全部見つけ出す
  2. mv aaaa.jpg?xxxx aaaa.jpg といった文字列に置換する。
  3. それをshコマンドで実行。

こういったことをしているのですが、この&の部分。
これは全体一致と言って置換前のものを全部持ってこれるのですが、 最初は''で囲んでおらず、$ mv aaaa.jpg?xxxx aaaa.jpgを実行するときに「aaaa.jpg?xxxと言ったファイル名はないよ?」と怒られました。
原因は ? とかの記号がターミナル上で別の意味で認識されていたからでした。
ターミナルでは ? とか & は特殊な意味を持つんですね。

解決策としては、''で囲んであげることでエスケープされ、? という文字がそのまま認識されるようになりました。
いやはや、これは時間かかった笑

パイプラインでつなげたものを引数に次のコマンド実行する方法

$ find . -not -name "*.jpg" -a -not -name "*.png" -a -not -name "*.jpeg" -a -not -name "*.gif" | xargs rm
この部分ですね。
これも最初はわからなかったけど、なんとかできた。

xargs コマンド

xargsコマンドを使うと、渡ってきたものをそのまま引数にコマンドを実行できるらしい。
これでfindコマンドで見つけたものを、そのまま削除することができた。
めでたし、めでたし。

感想

正規表現のとこでハマり散らかしてめちゃくちゃ時間かかったけど、なんとかできた・・。
もっといい書き方はたくさんあるんだろうけれど、シェルスクリプトを書いたのなんて初めてだし、今は動けば正直それでいいや。
もっと賢くなったときに書き方を改めることにする。

ファイル名の一括置換とパイプラインでの値の受け取り方とか、かなり勉強になったのでまあ作ってみて良かったかな。
これで画像100枚一気にダウンロードできるしね!!(いつ使うかは不明だけど)
皆さんも是非使ってみてね!

参考にしたサイト等

Google Custom Search API を使って画像検索をしてみた
sedで指定した行の削除をする方法
findコマンドで複数の名前条件を指定
findとsedを利用した一行野郎のファイル名変換
grepでこういう時はどうする?
xargs コマンド

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

BЯunoの技術ブログ。日々学んだことを記録していくよ。

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう