Spotify API:如何将不同级别的 JSON 信息提取到一个数据帧中
Posted
技术标签:
【中文标题】Spotify API:如何将不同级别的 JSON 信息提取到一个数据帧中【英文标题】:Spotify API: how to extract JSON information from different levels into one datFrame 【发布时间】:2021-08-28 11:25:16 【问题描述】:如何从这个 JSON 对象中提取“艺术家姓名”、“流行度”和“uri”到数据框中?
"tracks" :
"href" : "https://api.spotify.com/v1/search?query=karma+police&offset=0&limit=20&type=track&market=BR",
"items" : [
"album" :
"album_type" : "album",
"available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "ID", "IE", "IS", "IT", "JP", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "SE", "SG", "SK", "SV", "TR", "TW", "US", "UY" ],
"external_urls" :
"spotify" : "https://open.spotify.com/album/7dxKtc08dYeRVHt3p9CZJn"
,
"href" : "https://api.spotify.com/v1/albums/7dxKtc08dYeRVHt3p9CZJn",
"id" : "7dxKtc08dYeRVHt3p9CZJn",
"images" : [
"height" : 640,
"url" : "https://i.scdn.co/image/f89c1ecdd0cc5a23d5ad7303d4ae231d197dde98",
"width" : 640
,
"height" : 300,
"url" : "https://i.scdn.co/image/1b898f0b8e3ce499d0fc629a1918c144d982e475",
"width" : 300
,
"height" : 64,
"url" : "https://i.scdn.co/image/faf295a70a6531826a8c25d33aad7d2cd9c75c7a",
"width" : 64
],
"name" : "OK Computer",
"type" : "album",
"uri" : "spotify:album:7dxKtc08dYeRVHt3p9CZJn"
,
"artists" : [
"external_urls" :
"spotify" : "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb"
,
"href" : "https://api.spotify.com/v1/artists/4Z8W4fKeB5YxbusRsdQVPb",
"id" : "4Z8W4fKeB5YxbusRsdQVPb",
"name" : "Radiohead",
"type" : "artist",
"uri" : "spotify:artist:4Z8W4fKeB5YxbusRsdQVPb"
]
我可以访问相同级别的信息,但无法获取 JSON 对象的子级别。
【问题讨论】:
嗨@Adelita,你能告诉我们你之前尝试过的没有奏效吗?这将帮助我们帮助您 - 我们可以看到您需要在哪里获得答案。看看这个答案是否有帮助navigating json table in python 我试过 d1 = pd.DataFrame(obj['tracks']['items'])[['name', 'popularity']] 这给了我我需要的部分信息,但无法在此处获取艺术家的姓名,因为要遵循的路径是 ['tracks']['items'][0]['artists']。那么如何在dataFrame中组合得到两者呢? 我在下面给出了一个非常详细的答案——应该让你继续前进!如果您有任何其他问题,请告诉我。 【参考方案1】:嵌套的 json 有时会令人困惑且难以访问,但 pandas 只需几个步骤即可轻松处理。
根据我认为您正在使用的内容,我决定从此处的 spotify tracks API 开始工作。数据示例在这篇文章的底部。
TL;DR:使用json_normalize()
:
# get access to tracks and put it in a nice variable
# use json_normalize to flatten it into a nice df
# rename columns
# normalize the 'artists' column in the df that contains nested json
# rename columns
# concatenate the original df and the artists df
# you can remove the original 'artists' / 'track_artists' field as it is no longer
# necessary, the values have been flattened out into their own columns.
在查看了您的数据结构以及您想要完成的工作后,我认为这是 json_normalize() 的工作!
使用 pandas 的 json_normalize()
会在一定程度上使您的嵌套 json 变得扁平,并让您大部分时间到达那里。
然而,棘手的是,对于每个轨道,'artists'
键中的值包含一个包含结果字典的列表,而不是保存一个值或另一个字典作为值,json_normalize()
可以处理很容易。
请注意,tracks['album'][0][artists]
包含 key:value
对,其键名与“专辑”字典中的名称相同。
看起来你想要的一切都将在轨道内,所以让我们创建一个变量以便于访问:
tracks = data['tracks]
json_normalize() 来救援:
df = pd.json_normalize(tracks)
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 28 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 artists 3 non-null object
1 available_markets 3 non-null object
2 disc_number 3 non-null int64
3 duration_ms 3 non-null int64
4 explicit 3 non-null bool
5 href 3 non-null object
6 id 3 non-null object
7 is_local 3 non-null bool
8 name 3 non-null object
9 popularity 3 non-null int64
10 preview_url 3 non-null object
11 track_number 3 non-null int64
12 type 3 non-null object
13 uri 3 non-null object
14 album.album_type 3 non-null object
15 album.artists 3 non-null object
16 album.available_markets 3 non-null object
17 album.external_urls.spotify 3 non-null object
18 album.href 3 non-null object
19 album.id 3 non-null object
20 album.images 3 non-null object
21 album.name 3 non-null object
22 album.release_date 3 non-null object
23 album.release_date_precision 3 non-null object
24 album.type 3 non-null object
25 album.uri 3 non-null object
26 external_ids.isrc 3 non-null object
27 external_urls.spotify 3 non-null object
如果您此时检查您的数据框,您会看到大多数值都被整齐地展平到各自的行中,但由于我们还需要艺术家信息,所以我们必须更进一步。
# change column names because you know there are dupes
# this will create a properly formatted dictionary for renaming columns
keys = k:f'track_k' for k in df.keys()[:14]
# rename columns
df = df.rename(columns=lambda x: keys.pop(x) if x in keys.keys() else x)
您的 df 现在将在其键前加上“track_”,这样您就知道它们是主轨道字典的一部分。
“艺术家”的价值仍然不平坦,所以让我们将它们拉平。一个特殊情况,因为每个字典都在一个列表中。
# normalize artist column and cat the resulting columns into a dataframe
# we use a list comprehension to get to the dict to use for json_normalize()
df_artists = pd.concat([pd.DataFrame(pd.json_normalize(y)) for x in df.track_artists for y in x], ignore_index=True)
# make a dict of new column names prepended with 'artist_' so we know it came from the 'artist' nested dict
kys = k:f'artist_k' for k in df_artists.keys()
# rename the columns
df_artists = df_artists.rename(columns=lambda x: kys.pop(x) if x in kys.keys() else x)
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 artist_href 3 non-null object
1 artist_id 3 non-null object
2 artist_name 3 non-null object
3 artist_type 3 non-null object
4 artist_uri 3 non-null object
5 artist_external_urls.spotify 3 non-null object
我们已重命名列,以便我们知道它们是否与曲目或艺术家相关,因此我们不会出现任何重复的名称冲突,从而使数据更难在以后找到和排序。
现在我们将所有内容放在一个数据框中:
flat_df = pd.concat([df, df_artists], axis=1)
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 track_artists 3 non-null object
1 track_available_markets 3 non-null object
2 track_disc_number 3 non-null int64
3 track_duration_ms 3 non-null int64
4 track_explicit 3 non-null bool
5 track_href 3 non-null object
6 track_id 3 non-null object
7 track_is_local 3 non-null bool
8 track_name 3 non-null object
9 track_popularity 3 non-null int64
10 track_preview_url 3 non-null object
11 track_track_number 3 non-null int64
12 track_type 3 non-null object
13 track_uri 3 non-null object
14 album.album_type 3 non-null object
15 album.artists 3 non-null object
16 album.available_markets 3 non-null object
17 album.external_urls.spotify 3 non-null object
18 album.href 3 non-null object
19 album.id 3 non-null object
20 album.images 3 non-null object
21 album.name 3 non-null object
22 album.release_date 3 non-null object
23 album.release_date_precision 3 non-null object
24 album.type 3 non-null object
25 album.uri 3 non-null object
26 external_ids.isrc 3 non-null object
27 external_urls.spotify 3 non-null object
28 artist_href 3 non-null object
29 artist_id 3 non-null object
30 artist_name 3 non-null object
31 artist_type 3 non-null object
32 artist_uri 3 non-null object
33 artist_external_urls.spotify 3 non-null object
所以,如果最后,你想要的只是一个只有你提到的 3 列的数据框,它会是这样的:
final_df = flat_df[['artist_name', 'track_popularity', 'artist_uri']]
这是下面的数据对象:
data =
"tracks": [
"album":
"album_type": "single",
"artists": [
"external_urls":
"spotify": "https://open.spotify.com/artist/6sFIWsNpZYqfjUpaCgueju"
,
"href": "https://api.spotify.com/v1/artists/6sFIWsNpZYqfjUpaCgueju",
"id": "6sFIWsNpZYqfjUpaCgueju",
"name": "Carly Rae Jepsen",
"type": "artist",
"uri": "spotify:artist:6sFIWsNpZYqfjUpaCgueju"
],
"available_markets": [
"AD",
"AR",
"AT",
"AU",
"BE",
"BG",
"BO",
"BR",
"CA",
"CH",
"CL",
"CO",
"CR",
"CY",
"CZ",
"DE",
"DK",
"DO",
"EC",
"EE",
"ES",
"FI",
"FR",
"GB",
"GR",
"GT",
"HK",
"HN",
"HU",
"ID",
"IE",
"IL",
"IS",
"IT",
"JP",
"LI",
"LT",
"LU",
"LV",
"MC",
"MT",
"MX",
"MY",
"NI",
"NL",
"NO",
"NZ",
"PA",
"PE",
"PH",
"PL",
"PT",
"PY",
"RO",
"SE",
"SG",
"SK",
"SV",
"TH",
"TR",
"TW",
"US",
"UY",
"VN",
"ZA"
],
"external_urls":
"spotify": "https://open.spotify.com/album/0tGPJ0bkWOUmH7MEOR77qc"
,
"href": "https://api.spotify.com/v1/albums/0tGPJ0bkWOUmH7MEOR77qc",
"id": "0tGPJ0bkWOUmH7MEOR77qc",
"images": [
"height": 640,
"url": "https://i.scdn.co/image/966ade7a8c43b72faa53822b74a899c675aaafee",
"width": 640
,
"height": 300,
"url": "https://i.scdn.co/image/107819f5dc557d5d0a4b216781c6ec1b2f3c5ab2",
"width": 300
,
"height": 64,
"url": "https://i.scdn.co/image/5a73a056d0af707b4119a883d87285feda543fbb",
"width": 64
],
"name": "Cut To The Feeling",
"release_date": "2017-05-26",
"release_date_precision": "day",
"type": "album",
"uri": "spotify:album:0tGPJ0bkWOUmH7MEOR77qc"
,
"artists": [
"external_urls":
"spotify": "https://open.spotify.com/artist/6sFIWsNpZYqfjUpaCgueju"
,
"href": "https://api.spotify.com/v1/artists/6sFIWsNpZYqfjUpaCgueju",
"id": "6sFIWsNpZYqfjUpaCgueju",
"name": "Carly Rae Jepsen",
"type": "artist",
"uri": "spotify:artist:6sFIWsNpZYqfjUpaCgueju"
],
"available_markets": [
"AD",
"AR",
"AT",
"AU",
"BE",
"BG",
"BO",
"BR",
"CA",
"CH",
"CL",
"CO",
"CR",
"CY",
"CZ",
"DE",
"DK",
"DO",
"EC",
"EE",
"ES",
"FI",
"FR",
"GB",
"GR",
"GT",
"HK",
"HN",
"HU",
"ID",
"IE",
"IL",
"IS",
"IT",
"JP",
"LI",
"LT",
"LU",
"LV",
"MC",
"MT",
"MX",
"MY",
"NI",
"NL",
"NO",
"NZ",
"PA",
"PE",
"PH",
"PL",
"PT",
"PY",
"RO",
"SE",
"SG",
"SK",
"SV",
"TH",
"TR",
"TW",
"US",
"UY",
"VN",
"ZA"
],
"disc_number": 1,
"duration_ms": 207959,
"explicit": False,
"external_ids":
"isrc": "USUM71703861"
,
"external_urls":
"spotify": "https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl"
,
"href": "https://api.spotify.com/v1/tracks/11dFghVXANMlKmJXsNCbNl",
"id": "11dFghVXANMlKmJXsNCbNl",
"is_local": False,
"name": "Cut To The Feeling",
"popularity": 63,
"preview_url": "https://p.scdn.co/mp3-preview/3eb16018c2a700240e9dfb8817b6f2d041f15eb1?cid=774b29d4f13844c495f206cafdad9c86",
"track_number": 1,
"type": "track",
"uri": "spotify:track:11dFghVXANMlKmJXsNCbNl"
,
"album":
"album_type": "album",
"artists": [
"external_urls":
"spotify": "https://open.spotify.com/artist/6sFIWsNpZYqfjUpaCgueju"
,
"href": "https://api.spotify.com/v1/artists/6sFIWsNpZYqfjUpaCgueju",
"id": "6sFIWsNpZYqfjUpaCgueju",
"name": "Carly Rae Jepsen",
"type": "artist",
"uri": "spotify:artist:6sFIWsNpZYqfjUpaCgueju"
],
"available_markets": [
"AD",
"AR",
"AT",
"AU",
"BE",
"BG",
"BO",
"BR",
"CA",
"CH",
"CL",
"CO",
"CR",
"CY",
"CZ",
"DE",
"DK",
"DO",
"EC",
"EE",
"ES",
"FI",
"FR",
"GB",
"GR",
"GT",
"HK",
"HN",
"HU",
"ID",
"IE",
"IL",
"IS",
"IT",
"JP",
"LI",
"LT",
"LU",
"LV",
"MC",
"MT",
"MX",
"MY",
"NI",
"NL",
"NO",
"NZ",
"PA",
"PE",
"PH",
"PL",
"PT",
"PY",
"RO",
"SE",
"SG",
"SK",
"SV",
"TH",
"TR",
"TW",
"US",
"UY",
"VN",
"ZA"
],
"external_urls":
"spotify": "https://open.spotify.com/album/6SSSF9Y6MiPdQoxqBptrR2"
,
"href": "https://api.spotify.com/v1/albums/6SSSF9Y6MiPdQoxqBptrR2",
"id": "6SSSF9Y6MiPdQoxqBptrR2",
"images": [
"height": 640,
"url": "https://i.scdn.co/image/2fb20bf4c1fb29b503bfc21516ff4b1a334b6372",
"width": 640
,
"height": 300,
"url": "https://i.scdn.co/image/a7b076ed5aa0746a21bc71ab7d2b6ed80dd3ebfe",
"width": 300
,
"height": 64,
"url": "https://i.scdn.co/image/b1d4c7643cf17c06b967b50623d7d93725b31de5",
"width": 64
],
"name": "Kiss",
"release_date": "2012-01-01",
"release_date_precision": "day",
"type": "album",
"uri": "spotify:album:6SSSF9Y6MiPdQoxqBptrR2"
,
"artists": [
"external_urls":
"spotify": "https://open.spotify.com/artist/6sFIWsNpZYqfjUpaCgueju"
,
"href": "https://api.spotify.com/v1/artists/6sFIWsNpZYqfjUpaCgueju",
"id": "6sFIWsNpZYqfjUpaCgueju",
"name": "Carly Rae Jepsen",
"type": "artist",
"uri": "spotify:artist:6sFIWsNpZYqfjUpaCgueju"
],
"available_markets": [
"AD",
"AR",
"AT",
"AU",
"BE",
"BG",
"BO",
"BR",
"CA",
"CH",
"CL",
"CO",
"CR",
"CY",
"CZ",
"DE",
"DK",
"DO",
"EC",
"EE",
"ES",
"FI",
"FR",
"GB",
"GR",
"GT",
"HK",
"HN",
"HU",
"ID",
"IE",
"IL",
"IS",
"IT",
"JP",
"LI",
"LT",
"LU",
"LV",
"MC",
"MT",
"MX",
"MY",
"NI",
"NL",
"NO",
"NZ",
"PA",
"PE",
"PH",
"PL",
"PT",
"PY",
"RO",
"SE",
"SG",
"SK",
"SV",
"TH",
"TR",
"TW",
"US",
"UY",
"VN",
"ZA"
],
"disc_number": 1,
"duration_ms": 193400,
"explicit": False,
"external_ids":
"isrc": "CAB391100615"
,
"external_urls":
"spotify": "https://open.spotify.com/track/20I6sIOMTCkB6w7ryavxtO"
,
"href": "https://api.spotify.com/v1/tracks/20I6sIOMTCkB6w7ryavxtO",
"id": "20I6sIOMTCkB6w7ryavxtO",
"is_local": False,
"name": "Call Me Maybe",
"popularity": 74,
"preview_url": "https://p.scdn.co/mp3-preview/335bede49342352cddd53cc83af582e2240303bb?cid=774b29d4f13844c495f206cafdad9c86",
"track_number": 3,
"type": "track",
"uri": "spotify:track:20I6sIOMTCkB6w7ryavxtO"
,
"album":
"album_type": "album",
"artists": [
"external_urls":
"spotify": "https://open.spotify.com/artist/6sFIWsNpZYqfjUpaCgueju"
,
"href": "https://api.spotify.com/v1/artists/6sFIWsNpZYqfjUpaCgueju",
"id": "6sFIWsNpZYqfjUpaCgueju",
"name": "Carly Rae Jepsen",
"type": "artist",
"uri": "spotify:artist:6sFIWsNpZYqfjUpaCgueju"
],
"available_markets": [
"AD",
"AR",
"AT",
"AU",
"BE",
"BG",
"BO",
"BR",
"CA",
"CH",
"CL",
"CO",
"CR",
"CY",
"CZ",
"DE",
"DK",
"DO",
"EC",
"EE",
"ES",
"FI",
"FR",
"GB",
"GR",
"GT",
"HK",
"HN",
"HU",
"ID",
"IE",
"IL",
"IS",
"IT",
"JP",
"LI",
"LT",
"LU",
"LV",
"MC",
"MT",
"MX",
"MY",
"NI",
"NL",
"NO",
"NZ",
"PA",
"PE",
"PH",
"PL",
"PT",
"PY",
"RO",
"SE",
"SG",
"SK",
"SV",
"TH",
"TR",
"TW",
"US",
"UY",
"VN",
"ZA"
],
"external_urls":
"spotify": "https://open.spotify.com/album/1DFixLWuPkv3KT3TnV35m3"
,
"href": "https://api.spotify.com/v1/albums/1DFixLWuPkv3KT3TnV35m3",
"id": "1DFixLWuPkv3KT3TnV35m3",
"images": [
"height": 640,
"url": "https://i.scdn.co/image/3f65c5400c7f24541bfd48e60f646e6af4d6c666",
"width": 640
,
"height": 300,
"url": "https://i.scdn.co/image/ff347680d9e62ccc144926377d4769b02a1024dc",
"width": 300
,
"height": 64,
"url": "https://i.scdn.co/image/c836e14a8ceca89e18012cab295f58ceeba72594",
"width": 64
],
"name": "Emotion (Deluxe)",
"release_date": "2015-09-18",
"release_date_precision": "day",
"type": "album",
"uri": "spotify:album:1DFixLWuPkv3KT3TnV35m3"
,
"artists": [
"external_urls":
"spotify": "https://open.spotify.com/artist/6sFIWsNpZYqfjUpaCgueju"
,
"href": "https://api.spotify.com/v1/artists/6sFIWsNpZYqfjUpaCgueju",
"id": "6sFIWsNpZYqfjUpaCgueju",
"name": "Carly Rae Jepsen",
"type": "artist",
"uri": "spotify:artist:6sFIWsNpZYqfjUpaCgueju"
],
"available_markets": [
"AD",
"AR",
"AT",
"AU",
"BE",
"BG",
"BO",
"BR",
"CA",
"CH",
"CL",
"CO",
"CR",
"CY",
"CZ",
"DE",
"DK",
"DO",
"EC",
"EE",
"ES",
"FI",
"FR",
"GB",
"GR",
"GT",
"HK",
"HN",
"HU",
"ID",
"IE",
"IL",
"IS",
"IT",
"JP",
"LI",
"LT",
"LU",
"LV",
"MC",
"MT",
"MX",
"MY",
"NI",
"NL",
"NO",
"NZ",
"PA",
"PE",
"PH",
"PL",
"PT",
"PY",
"RO",
"SE",
"SG",
"SK",
"SV",
"TH",
"TR",
"TW",
"US",
"UY",
"VN",
"ZA"
],
"disc_number": 1,
"duration_ms": 251319,
"explicit": False,
"external_ids":
"isrc": "USUM71507009"
,
"external_urls":
"spotify": "https://open.spotify.com/track/7xGfFoTpQ2E7fRF5lN10tr"
,
"href": "https://api.spotify.com/v1/tracks/7xGfFoTpQ2E7fRF5lN10tr",
"id": "7xGfFoTpQ2E7fRF5lN10tr",
"is_local": False,
"name": "Run Away With Me",
"popularity": 50,
"preview_url": "https://p.scdn.co/mp3-preview/3e05f5ed147ca075c7ae77c01f2cc0e14cfad78d?cid=774b29d4f13844c495f206cafdad9c86",
"track_number": 1,
"type": "track",
"uri": "spotify:track:7xGfFoTpQ2E7fRF5lN10tr"
]
【讨论】:
【参考方案2】:如果我正确理解了问题,你可以尝试不使用列表结构,像这样编辑它
data =
"tracks":
"href": "https://api.spotify.com/v1/search?query=karma+police&offset=0&limit=20&type=track&market=BR",
"items":
"album":
"album_type": "album",
"available_markets": ["AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR",
"CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT",
"HK", "HN", "HU", "ID", "IE", "IS", "IT", "JP", "LI", "LT", "LU", "LV", "MC",
"MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY",
"SE", "SG", "SK", "SV", "TR", "TW", "US", "UY"],
"external_urls":
"spotify": "https://open.spotify.com/album/7dxKtc08dYeRVHt3p9CZJn"
,
"href": "https://api.spotify.com/v1/albums/7dxKtc08dYeRVHt3p9CZJn",
"id": "7dxKtc08dYeRVHt3p9CZJn",
"images": [
"height": 640,
"url": "https://i.scdn.co/image/f89c1ecdd0cc5a23d5ad7303d4ae231d197dde98",
"width": 640
,
"height": 300,
"url": "https://i.scdn.co/image/1b898f0b8e3ce499d0fc629a1918c144d982e475",
"width": 300
,
"height": 64,
"url": "https://i.scdn.co/image/faf295a70a6531826a8c25d33aad7d2cd9c75c7a",
"width": 64
],
"name": "OK Computer",
"type": "album",
"uri": "spotify:album:7dxKtc08dYeRVHt3p9CZJn"
,
"artists":
"external_urls":
"spotify": "https://open.spotify.com/artist/4Z8W4fKeB5YxbusRsdQVPb"
,
"href": "https://api.spotify.com/v1/artists/4Z8W4fKeB5YxbusRsdQVPb",
"id": "4Z8W4fKeB5YxbusRsdQVPb",
"name": "Radiohead",
"type": "artist",
"uri": "spotify:artist:4Z8W4fKeB5YxbusRsdQVPb"
那么这个例子会给你“uri”
print(data["tracks"]["items"]["artists"]["uri"])
如果它不是你可以修复的json,你应该这样做,因为它包含列表
print (data["tracks"]["items"][0]["artists"][0]["uri"])
如果有多个,则可以通过循环获取所有数据
【讨论】:
谢谢!确实,我可以单独获得这些结果,但我的问题是如何一次性打印 uri、流行度和艺术家姓名。以上是关于Spotify API:如何将不同级别的 JSON 信息提取到一个数据帧中的主要内容,如果未能解决你的问题,请参考以下文章
Spotify API:使用 Python 通过 JSON 解析时出错
如何从 Spotify Search API 获取数据并将其解析为 JSON? [在 node.js 中