【2021最新】AzureのBing Search APIで大量に画像をPythonでスクレイピングする方法 | COMMONS NOTE

【2021最新】AzureのBing Search APIで大量に画像をPythonでスクレイピングする方法

こんにちは、マダラです!

最近azureのBing Search APIを使用して大量画像をスクレイピンングする実装を行なったので、同じ作業を行いたい人のために記事に起こそうと思います!!

Azureを選択した背景

そもそもなぜ、Azureを選択したのかという背景を簡単にまとめます。

なぜなら、スクレイピングしたいなら、自前でコードを実装する方法やGoogle Cloud Platformを使用する方法もあるわけです。

はじめはgoogle-images-downloadを使用しようと思いました。
もともと以前実装したコードがあり、これなら労せず画像を取得できたからですね!

ところが、以前動いたコードがうまく動きません、、調べていくうちにGoogleがスクレイピング対策を強化したことでこのライブラリを使用したスクレイピングはできなくなったことが調査の結果わかりました。。。

次にGCPですが、どうも100枚までしか取得できないという縛りがあるようで、キーワードを変えて色々工夫しないと大量画像を取得できません。

数年前から発覚している問題ですがずっと解決していないようですね。
私も学生時代に、100枚しか取れず機械学習のデータセット集めに苦労した思いがあります、、

そこで出てきたのがAzureのBing Search APIですね!
ネットで少し調べると情報がたくさん出てくるのですが、一回の実行で1000枚近くの画像を集めることができるようでした。

こういった背景からAzure を利用した画像スクレイピングを行うことにしたのでした!

画像の取得をするPythonコード

それではさっそくコードの方を紹介します!正直ここだけが皆さんきになるかと思います!笑

読み飛ばした方もいるでしょう!

Bing Search API 画像取得Pythonコード


# -*- coding:utf-8 -*-
import requests
import matplotlib.pyplot as plt
from PIL import Image
from io import BytesIO
import math
import os
import time
import urllib
import hashlib
import argparse
import sys


SUBSCRIPTION_KEY = "INPUT APIKEY"
ENDPOINT = "https://api.bing.microsoft.com/v7.0/images/search"
path = "getImages"
headers = {"Ocp-Apim-Subscription-Key" : SUBSCRIPTION_KEY, 'Content-Type': 'multipart/form-data'}


def get_args():
# オブジェクト生成
parser = argparse.ArgumentParser()
if sys.stdin.isatty():
parser.add_argument("-q", "--query", type=str, required=True, nargs='*')
parser.add_argument("-c", "--count", type=int, default=3)
parser.add_argument("-n", "--reqnum", type=int, default=1)
args = parser.parse_args()
return(args)


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,quary,id,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')
filename = '_'.join(quary)+"_"+id
full_path = os.path.join(path,filename + '.' + extension.lower())


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


if __name__ == "__main__":
args = get_args()


# パラメータ
# license: パブリックドメインで画像を検索する
# imageType: photo指定で写真のみに絞る
query = args.query
count = args.count # 1リクエストあたりの最大取得件数 default:35 max:150
mkt = "ja-JP" # 取得元の国コード。指定すると応答が最適化される
num_per = args.reqnum # リクエスト回数(count * num_per=取得画像数)
offset = math.floor(count / num_per) # ループ回数。countの数でページング


for offset_num in range(offset):
params = {'q':query,'count':count,'offset':offset_num*offset,'mkt':mkt}
res = requests.get(ENDPOINT,headers=headers,params=params)
res.raise_for_status()
data = res.json()


for values in data['value'][:16]:
image_id = values['imageId']
image_url = values['contentUrl']
try:
download_img(path,query,image_id,image_url)
except Exception as e:
print("【INFO】failed to download image at {}".format(image_url))
print(e)
time.sleep(0.5)

INPUT APIKEYのところに皆さんが取得したBing Search APIの鍵を入力して使用してください!

鍵の取り方はネットで検索すればすぐ出てきます。
Azureの検索フォームから「Marketplace」を入力して移動、次にMarketplaceの検索フォームからBing Search APIを選択。

そこからAPIKEYを取得する設定をしていきましょう!

コードの使い方

一応コードの実行方法も載せておきますねー!

作ったマニュアルからコピペしてくるだけなので、あとはコードと照らし合わせながらご自由にカスタマイズしてください!

オプション

  • - q: クエリ 半角スペースで複数指定可能(必須)
  • - c: 1リクエストで取得する画像枚数。デフォルトで3。max150
  • - n: ページング処理数
c*n枚数画像を取得する

実行

$ py getImage.py -q キーワード -c 1リクエストの枚数 -n ページ数
キーワード「cat dog」で画像を20枚取得する例
$ py getImage.py -q cat dog -c 10 -n 2
同ディレクトリ配下に「getImages」フォルダが作成され、取得した画像が並ぶ

複数キーワード使用したい場合はスペースをつけて続けて入力すればおkです!
環境構築に関してはpip installなどで頑張ってください!!

ではでは!!