jqでJSONをパースしてファイル作成する

今回はLinux(Ubuntu)でJSONをパース処理する方法をまとめます。未来の自分のためへの備忘です。

企業から商品や検索結果のデータを取得するときは、多くの場合は用意されたREST APIにrequestして返却されたJSONだと思います。

JSONは人間が読みやすいデータですが、量が多くなると中々大変です。ecサイトで大量に返却されたときは必要な情報だけ読み取りたいですね。

そこで便利なのがjqです。指定した項目だけ取得して出力すればすっきりしたデータになります。

また、jqとcronの合わせ技は効果抜群。サーバーが定期的に情報を取ってきてシンプルなファイルにまとめてくれます。手動でせかせかと作業しなくてもデータが作られるので最高ですね。

事前準備 jqのインストール

最初にJSONをパースするために必要となるjqをインストールします。インストール前にupdateで確認しておきましょう。

sudo apt -y update
sudo apt install jq

CentOSだと下のようです。

sudo yum -y install epel-release
sudo yum -y install jq

jqを用いてJSONをparseする

curlでAPIにrequestして、戻って来たJSONをjqでパースして、テキストファイルとして出力します。

まずは下のコマンドを打ってテキストファイルを新規作成しておきましょう。ファイル名は自由に決めてください。拡張子は.shです。

touch [your_filename].sh

.shファイルを下のように編集します[URL]はAPIのURLを指定してください。

シェルの#bashでは”&”や”?”は特殊な意味を持ちます。URLのパロメーターでこれらがよく使われているので、エスケープさせることを忘れないでください。特殊記号の前に”\”を書くとエスケープできます。

[parse]はJSONをどんな風に抽出するかの条件を記述します。どんなふうに書くかは次で記述します。

[OutputPath]はファイル出力先です。

#!/bin/bash
curl [URL] | jq '[parse]' >> [outputPath]
# エスケープの例 URLがgoogle(https://google.ne.jp/search?q=abc)の場合
curl https://google.co.jp/search\?q=abc | jq '[parse]' >> [outputPath]

parseの指定の仕方

具体的な例を挙げて説明します。APIが下のようのJSONを返却するとします。

"result":
{
	"status":200,
	"result_count":2,
	items":[
	{
		"service_code":"comic",
		"product_id":"c_100000",
		"price": "660",
		"title":"Jujutsu Kaisen"
	}
	{
		"service_code":"business",
		"product_id":"b_999999",
		"price": "1,500",
		"title":"Yaruki wo dasu 50 no houhou."
	}
	]
}

指定の項目を取得

タイトルのプロパティを取得したい時は[parse]部分に下のように記述します。

itemsにあるtitleの2つが該当するので、2つ目のようにファイルにはtitleの2行が出力されます。

'.result.items[].title'
# 結果
"Jujutsu kaisen"
"Yaruki wo dasu 50 no houhou."

一つ目だけ取得

ではitemsの最初の一個だけtitleのプロパティを取得したい場合はどう指定すれば良いでしょうか?

下のように記述します。itmesの配列の何番目が欲しいかを指定してあげれば良いみたいですね。

'.result.items[0].title'
# 結果
"Jujutsu Kaisen"

ダブルクォートを削除する

データは基本的に文字列ですが、ファイル出力するときはダブルクォートが不要になることもあります。そんなときはあらかじめダブルクォートを除外して出力します。

オプションの-rを指定することで、出力結果からダブルクォートが除外されます。

curl [URL] | jq -r '[parse]' >> [outputPath]

フィルタリングする

ではECサイトなどで必ず使うシチュエーションも考えてみましょう。

priceが1000の商品を取得したい場合はどうすればよいでしょうか?下のようにselectで記述します。

'.result.items[] | select(.price == "1,500")'
# 結果
"service_code":"business"
"product_id":"b_999999"
"price": "1,500"
"title":"Yaruki wo dasu 50 no houhou."

取得できました。このフィルタリングは必ずと言っていいほど使うと思うので覚えておきましょう。

priceがもっと深い階層にあって指定するのが面倒な場合は、下のように全ての経路を検索する[..]を指定して、パイプで条件をつけて検索しましょう。

'.. | select(.price == "1,500")'

priceが1500に該当する商品のtitleだけを取りたい場合は下です。パイプでnameの条件を追加します。

'.. | select(.price == "1,500") | .title'

おわりに

jqの代表的な使い方でした。

自作したシェルで利用したjqだけをまとめましたが、オプションの指定は山ほどありますし、もっと細かく指定してデータを取得することも出来ます。

サーバーを使うなら是非覚えておきたい処理ですね。

WEB備忘録のHOMEへ戻る

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA