質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Google API

Googleは多種多様なAPIを提供していて、その多くはウェブ開発者向けのAPIです。それらのAPIは消費者に人気なGoogleのサービス(Google Maps, Google Earth, AdSense, Adwords, Google Apps,YouTube等)に基づいています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

Q&A

解決済

1回答

675閲覧

Google Custom Search APIを用いて画像を収集するプログラムを作ったがエラーで収集できない

退会済みユーザー

退会済みユーザー

総合スコア0

Google API

Googleは多種多様なAPIを提供していて、その多くはウェブ開発者向けのAPIです。それらのAPIは消費者に人気なGoogleのサービス(Google Maps, Google Earth, AdSense, Adwords, Google Apps,YouTube等)に基づいています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

0グッド

0クリップ

投稿2018/08/27 17:39

画像を収集するためにGoogle Custom Search APIを用いてプログラムを組みました。
しかし、下記のようなエラーが出てしまいうまく動きません。解決方法をアドバイス頂けると幸いです。

「環境」
MacOSX High Sierra 10.13.6
Python 3.6

「エラー」

Traceback (most recent call last): File "google_api.py", line 19, in <module> items_json = requests.get(API_PATH, PARAMS).json()["items"] KeyError: 'items'

「ソース」

import requests import shutil API_PATH = "https://www.googleapis.com/customsearch/v1" PARAMS = { "cx" : "xxxx:xxxx", #検索エンジンID "key": "xxxxxxxxx", #APIキー "q" : "映画", #検索ワード "searchType": "image", #検索タイプ "start" : 1, #開始インデックス "num" : 10 #1回の検索における取得件数(デフォルトで10件) } LOOP = 100 image_idx = 0 for x in range(LOOP): PARAMS.update({'start': PARAMS["num"] * x + 1}) items_json = requests.get(API_PATH, PARAMS).json()["items"] for item_json in items_json: path = "imgs/" + str(image_idx) + ".png" r = requests.get(item_json['link'], stream=True) if r.status_code == 200: with open(path, 'wb') as f: r.raw.decode_content = True shutil.copyfileobj(r.raw, f) image_idx+=1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

KeyError: 'items'

LOOP = 100
image_idx = 0

for x in range(LOOP):

1検索キーワードの上限(100件)に達してAPIから結果を取得できなくなったのでは。

requests.getの戻り値のレスポンスに対して、raise_for_status()を実行してステータスコードを確認してくださいな。

サンプルコードです。(未テスト)

Python

1from logging import getLogger, StreamHandler, Formatter, DEBUG 2import requests 3import shutil 4 5LOGGER = getLogger('custom_search_api') 6HANDLER = StreamHandler() 7HANDLER.setLevel(DEBUG) 8HANDLER.setFormatter(Formatter('%(message)s')) 9LOGGER.setLevel(DEBUG) 10LOGGER.addHandler(HANDLER) 11 12 13def fetch(url: str, params: dict=None): 14 res = requests.get(url, params) 15 res.raise_for_status() 16 return res 17 18API_PATH = "https://www.googleapis.com/customsearch/v1" 19start_index = 1 20PARAMS = { 21 "cx" : "xxxx:xxxx", #検索エンジンID 22 "key": "xxxxxxxxx", #APIキー 23 "q" : "映画", #検索ワード 24 "searchType": "image", #検索タイプ 25 "start" : start_index, #開始インデックス 26 "num" : 10 #1回の検索における取得件数(デフォルトで10件) 27} 28for _ in range(10): # 10 * 10 = 100 29 res = fetch(API_PATH, params) 30 LOGGER.info('#' * 80) 31 res_json = res.json() 32 for idx, items in enumerate(res_json['items'], start=start_index): 33 path = "imgs/" + str(idx) + ".png" 34 download_link = items['link'] 35 LOGGER.info(f'url:{download_link}') 36 r = requests.get(download_link, stream=True) 37 if r.status_code == 200: 38 with open(path, 'wb') as f: 39 r.raw.decode_content = True 40 shutil.copyfileobj(r.raw, f) 41 start_index = res_json['queries']['nextPage'][0].get('startIndex') 42 LOGGER.info(f'next:{start_index}') 43 params['start'] = start_index

あと、無料枠の場合は1日のクエリ制限100もあります。
参考:Yahoo、Bing、Googleでの画像収集事情まとめ

大手の検索エンジンは画像検索に関しては制限がきついです。


回答の要旨を上手く伝えきれていないので、補足説明。
質問文のコードはnumを考慮していなく1クエリ100件を上手く処理できないコードです。

"num" : 10 #1回の検索における取得件数(デフォルトで10件)

wandbox
私の回答文のコードを参考に10クエリ*10件の総数:100に変更してみてくださいな。


スクレイピングは相手サイトの都合にかなり影響されます。
例外の発生が許容されないのならばtry~exceptを行うようなコードにしてください。
python 再試行、python リトライで検索するといろいろHITするかと。


1,requests.getの戻り値のレスポンスオブジェクトに対して以下のどちらかの処理をいれると、
質問文のエラーより前に問題が発見できるかと。

1-a,try~exceptで囲んで、raise_for_status()を呼び出す。 (回答者:推奨コード)

Python

1 try: 2 res = requests.get(url, params) 3 res.raise_for_status() 4 except Exception as ex: 5 LOGGER.exception(ex)

1-b,HTTPステータスコード:statuscodeをみる。

Python

1 res = requests.get(url, params) 2 print(res.status_code)

2,リトライ処理を行う。
requestsを使っているならば、from urllib3.util.retry import Retry
参考:KeyError の再試行について
3,あと相手サーバーの負荷軽減のために適度なsleepを入れてくださいな。

投稿2018/08/27 18:30

編集2018/08/28 08:42
umyu

総合スコア5846

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/08/27 18:32

ありがとうございます。1日のクエリ制限100というのは知っていたので、0時過ぎてから試したのですがダメでした。もしや何かコードのミスとかがあっても1回ソースを実行してしまうと100にカウントされてダメとかあるのでしょうか?
umyu

2018/08/27 18:40

@toromagurofishさんへ >1日のクエリ制限100というのは知っていたので、0時過ぎてから試した 回答の二度手間を防ぐために、質問文にはできるだけ試した事を書いてくださいな。 https://console.cloud.google.com/apis/library/customsearch.googleapis.com 管理ボタン→割当タブに記載がありますが、「毎日の割り当ては、太平洋時間(PT)の午前 0 時にリセットされます。」 リセット時間はJST(日本標準時)ではないです。
退会済みユーザー

退会済みユーザー

2018/08/28 05:16

すいませんでした。そういうことなのですね。ありがとうございます。以後気をつけます。
退会済みユーザー

退会済みユーザー

2018/08/28 09:33

編集ありがとうございます。参考に致します。
退会済みユーザー

退会済みユーザー

2018/08/31 03:12

なぜかもう1度打ち込み直したら直りました!お騒がせしました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問