JMESPathウェブスクレイピング:宣言的にJSON APIをクエリする
Advanced Data Extraction Specialist
TL;DR:
- jmespathはJSONを宣言的にクエリする。 一つの式でネストされたAPIレスポンスをフラットなレコードに再構成できる — ループなし、手動で辞書を歩く必要なし。
- JSON APIは最もクリーンなスクレイピング対象。 多くのサイトはバックエンドのJSONエンドポイントからページを構築している; そのJSONを取得すると、データはすでに構造化されて到着する。
- jmespathはデータを取得することはしない。 HTTPクライアントはなく、HTMLを解析しない; デコードされたJSONオブジェクトを渡すと、それをクエリする。
- APIが保護されている場合はScrapelessを使って取得する。 実行中にScrapeless Universal Scraping APIを通して商品APIを取得し、その後jmespathを使用して結果を選択、フィルタリング、ソートした。
- フィルタとプロジェクションは1行で。
products[?price < \50`].titleは$50未満の6つの製品を返し;sort_by(products, &price)[0]`は最も安いものを返した。 - 取得側は無料で開始。 app.scrapeless.comでScrapeless APIキーを作成。
jmespathとは、そしてそれが何でないか
jmespathはJSON用のクエリ言語です。必要な形を説明する式を書き、そのライブラリがドキュメントを歩いて結果を返します — プロジェクションはリストのすべての要素からフィールドを引き出し、フィルタは条件にマッチする要素のみを保持し、マルチセレクトハッシュは各要素を小さなレコードに再構築します。これはAWS CLIがその--queryフラグに使っている同じ式言語であり、JMESPath仕様によって標準化されており、小さなPythonライブラリとして利用可能です。
これはクエリ言語であり、スクレイパーではありません。jmespathにはHTTPクライアントがなく、URLを取得せず、HTMLを解析することはありません — すでにデコードされたJSON値で動作します。これは、JSONデータ交換標準によって定義されています。したがって、「jmespathウェブスクレイピング」セットアップは二層で構成されています: JSONを返す何かと、それを再構成するjmespathです。これは、現代のサイトのデータの大部分がバックエンドのJSON APIによって提供され、そのページがバックグラウンドで呼び出すため重要です; そのエンドポイントに直接アクセスすることでHTML解析を完全にスキップできます。エンドポイントが地理的に制限されている場合やレート制限がある場合、このガイドはScrapeless Universal Scraping APIを通じて取得する方法を示します。スクレイピングのHTML側については、Pythonウェブスクレイピングチュートリアルがセレクタを扱います。
インストール
jmespathとrequestsがツールチェーン全体です。このガイドが書かれたバージョンはjmespath 1.0.1です:
bash
pip install "jmespath==1.0.1" requests
キーは環境に保持し、ソースの中には決して保存しないでください:
bash
export SCRAPELESS_API_KEY="sk_your_scrapeless_key"
Scrapelessを通じてJSON APIを取得
取得層は生のJSONを返します。エンドポイントがJSONを提供するため、レンダリングされたページではなく、js_renderはオフのままです; Scrapeless APIがリクエスト、プロキシルーティング、エンドポイントの前のアクセス制御を処理し、HTTPセマンティクス標準によって定義されたボディを返します。一度デコードすると、jmespathが引き継ぎます:
python
# fetch.py — Scrapelessを通じてJSON APIを取得し、その後クエリする
import json
import os
import jmespath
import requests
resp = requests.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"Content-Type": "application/json", "x-api-token": os.environ["SCRAPELESS_API_KEY"]},
json={"actor": "unlocker.webunlocker", "input": {"url": "https://dummyjson.com/products?limit=10", "js_render": False}},
timeout=120,
)
resp.raise_for_status()
payload = json.loads(resp.json()["data"])
print("ページ内の製品:", jmespath.search("length(products)", payload))
print("最初のタイトル:", jmespath.search("products[0].title", payload))
print("利用可能な総数:", jmespath.search("total", payload))
この実行はレスポンスの形状を一度もループすることなく読み取ります:
text
ページ内の製品: 10
最初のタイトル: Essence Mascara Lash Princess
利用可能な総数: 194
Scrapeless呼び出しが取得層です — Universal Scraping APIはJSONボディを返し、payloadはjmespathがクエリできる通常のPythonオブジェクトです。
jmespathで再構成しフィルタリング
jmespathのポイントは冗長なレスポンスを正確に必要なレコードに変換することです。プロジェクションとマルチセレクトハッシュは各製品を再構築し; フィルタ式はマッチするものだけを保持し; sort_byはそれらを並べ替え — すべてが式として、手続き型コードではありません:
python
# query.py — 三つの式で再構成し、フィルタリングし、ソートする
import json
import os
import jmespath
import requests
resp = requests.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"Content-Type": "application/json", "x-api-token": os.environ["SCRAPELESS_API_KEY"]},
json={"actor": "unlocker.webunlocker", "input": {"url": "https://dummyjson.com/products?limit=10", "js_render": False}},
timeout=120,
)
resp.raise_for_status()
payload = json.loads(resp.json()["data"])
records = jmespath.search("products[].{title: title, price: price, rating: rating}", payload)
under_50 = jmespath.search("products[?price < `50`].title", payload)
cheapest = jmespath.search("sort_by(products, &price)[0].{title: title, price: price}", payload)
print("records:", len(records))
print("first record:", json.dumps(records[0], ensure_ascii=False))
print("under $50:", len(under_50))
print("cheapest:", json.dumps(cheapest, ensure_ascii=False))
各行はループの作業を行うクエリです:
text
records: 10
first record: {"title": "エッセンス マスカラ ラッシュ プリンセス", "price": 9.99, "rating": 2.56}
under $50: 6
cheapest: {"title": "赤いネイルポリッシュ", "price": 8.99}
これが全体の抽出器です:JSONを取得するための1回のPOST、そしてそれを整形するための3つの式。マルチセレクトハッシュ {title: title, price: price} が主力です — 不要なフィールドを削除し、保持するフィールドの名前を変更するので、保存するものは正に要求したものです。
無料プランでAPIキーを取得してください: app.scrapeless.com
高度なパターン
- プロジェクトの前にフィルタリングを行います。
products[?rating > \4.5`].{title: title}` は、最初にマッチを保持し、その後整形します。このようにパイプの順序を保つことで、式を読みやすくし、結果を小さく保ちます。 []でネストされたリストをフラットにします。 レコードが独自のリストをネストする場合、products[].reviews[].ratingは、すべての製品のレビュー評価を1つのリストにフラットにします — フラット演算子は二重ループが行うことを実行します。|で式をパイプします。products | length(@)とsort_by(@, &price) | [0]は、結果を次の式にチェーンします;@は現在のノードであり、これは1つのクエリの出力を別のクエリに渡す方法です。- 欠落キーに対してガードします。 jmespathは、出発点が存在しない場合、エラーを引き上げるのではなく
Noneを返します。したがって、一部のレコードのみが持つフィールドは、クエリをクラッシュさせません — 保存するときにNoneに対してチェックします。
トラブルシューティング
json.loadsがレスポンスでエラーを起こします。 エンドポイントはHTMLを返し、JSONではありません — しばしばエラーまたはブロックページです。URLがJSON APIであり、HTMLページではないことを確認し、デコードする前にフェッチが成功したことを確認します。- プロジェクションが空のリストを返します。 パスがドキュメントの形状と一致していません。最上位のキーを印刷し、1レベルずつ降りていきます;JSON APIはその配列を
productsやresultsのようなキーの下にネストし、ルートには置きません。 - フィルタが何もマッチしません。 フィルタの数値や文字列にはバックティックリテラルが必要です —
price < \50`, ではなくprice < 50`。バックティックなしでは値はフィールド名として読み取られます。 - 結果が不要なフィールドを保持します。 あなたはマルチセレクトハッシュの代わりに裸のプロジェクション
products[]を使いました。選択したいフィールドのみに.{title: title, price: price}を追加します。
結論
jmespathは、JSONレスポンスを手続き的コードなしでレコードに変換するレイヤーとしてその地位を確立します:プロジェクション、フィルタ、ソートは単一の式として。そして、JSONを取得するのはフェッチであり、バックエンドAPIは最もクリーンなソースであり、1回のScrapeless POSTはエンドポイントを守るものを超えてそのボディを返します。これら2つを一緒に接続して、冗長な商品フィードが実際に保存する4つのフィールドになります。
無料のScrapelessアカウントを作成してAPIキーを取得し、開発者ドキュメントが unlocker.webunlocker パラメータをカバーします。定期的なジョブを計画するときは、Scrapelessの価格を確認してください。
FAQ
Q: jmespathは自らウェブサイトをスクレイピングできますか?
いいえ。jmespathは既に持っているJSON値をクエリします。HTTPクライアントはなく、URLを取得したりHTMLを解析したりしません。フェッチレイヤーと組み合わせる必要があります — ここではScrapeless Universal Scraping APIがJSONボディを返します — そしてjmespathはそれをレコードに再整形します。
Q: なぜHTMLページの代わりにJSON APIをスクレイピングするのですか?
データがすでに構造化されて到着するからです。多くのページは、バックグラウンドで呼び出すバックエンドのJSONエンドポイントからレンダリングされます;そのエンドポイントにアクセスすることで、HTMLの解析やセレクターのメンテナンスを完全にスキップでき、jmespathはレスポンスを正確に望むレコードに変換します。
Q: jmespathはjsonpathとどのように異なりますか?
両方ともクエリJSONですが、jmespathには正式な仕様と、出力を再形成する投影、フィルター、関数、およびマルチセレクトハッシュを備えたコンパクトな表現言語があります。そのマルチセレクト構文 — クエリ内のフィールドの名前変更や削除 — は、抽出に適した特徴です。
Q: サイトにJSON APIがない場合はどうしますか?
それなら、代わりにHTMLを解析します:Scrapelessを通じてレンダリングされたページを取得し、セレクタライブラリを使用します。jmespathは、ソースがJSONである場合のみ適用されます。この2つのアプローチは、データが存在する2つの形をカバーしています。
Q: JSON APIをスクレイピングすることは合法ですか?
クエリ言語は収集ルールを変更しません。公開エンドポイントのみを取得し、サイトの利用規約とロボット排除プロトコルに基づいたロボットの指示を尊重し、ボリュームを制限し、あなたに適用される法律に従って個人データを扱ってください。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



