如何使用 Python 从网站中提取多个独立嵌套的 JSON 对象和密钥



我想从网页中提取多个独立的JSON对象和相关键。通过"独立嵌套",我的意思是每个 JSON 对象都嵌套在script type = "application/ld+json元素中。

我目前正在使用 beautifulsoup、json 和请求来尝试完成此任务,但我无法让它工作。我已经阅读了类似的帖子(例如,这里,这里和这里(,但没有一个解决这个问题。具体来说,如何同时提取多个独立嵌套的 JSON 对象,然后从这些对象中提取特定键。其他示例假定 JSON 对象都位于一个嵌套中。

这是我目前所处的工作示例:

# Using Python 3.8.1, 32 bit, Windows 10
from bs4 import BeautifulSoup
import requests
import json

#%% Create variable with website location
reno = 'https://www.foodpantries.org/ci/nv-reno'

#%% Downlod the webpage
renoContent = requests.get(reno)

#%% Make into nested html
renoHtml = BeautifulSoup(renoContent.text, 'html.parser')

#%% Keep only the HTML that contains the JSON objects I want
spanList = renoHtml.find("div", class_="span8")

#%% Get JSON objects.
data = json.loads(spanList.find('script', type='application/ld+json').text)
print(data)

这就是我被困住的地方。我可以获取第一个位置的 JSON 数据,但是,我无法获取spanList变量中列出的其他 9 个位置的 JSON 数据。如何让 Python 从其他 9 个位置获取 JSON 数据?我确实尝试了spanList.find_all但这返回了一个AttributeError: ResultSet object has no attribute 'text'.但是如果我从json.loads中删除.text,我会得到TypeError: the JSON object must be str, bytes or bytearray, not ResultSet.

我的预感是这很复杂,因为每个 JSON 对象都有自己的script type = "application/ld+jso属性。我看到的其他例子都没有类似的情况。似乎json.loads只识别第一个 JSON 对象,然后停止。

另一个复杂因素是位置的数量会根据城市而变化。我希望有一种解决方案可以自动拉取所有位置,无论页面上有多少位置(例如,里诺有 10 个,但拉斯维加斯有 20 个(。

我也无法弄清楚如何使用namestreetAddress.等键名称从此 JSON 加载中提取密钥 这可能基于我如何通过json.dumps提取 JSON 对象,但我不确定。

下面是 JSON 对象如何布局的示例

<script type = "application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"address": {
"@type":"PostalAddress",
"streetAddress":"2301 Kings Row",
"addressLocality":"Reno",
"addressRegion":"NV",
"postalCode": "89503"
},
"name": "Desert Springs Baptist Church"
,"image": 
"https://www.foodpantries.org/gallery/28591_desert_springs_baptist_church_89503_wzb.jpg"
,"description": "Provides a food pantry.  Must provide ID and be willing to fill out intake 
form Pantry.Hours: Friday 11:00am - 12:00pmFor more information, please call. "
,"telephone":"(775) 746-0692"
}

我的最终目标是将键namestreetAddressaddressLocalityaddressRegionpostalCode中包含的数据导出到CSV文件。

IIUC,您只需要在spanList中调用.find_all方法即可获取所有json对象。

试试这个:

from bs4 import BeautifulSoup
import requests
import json
reno = 'https://www.foodpantries.org/ci/nv-reno'
renoContent = requests.get(reno)
renoHtml = BeautifulSoup(renoContent.text, 'html.parser')
json_scripts = renoHtml.find("div", class_="span8").find_all('script', type='application/ld+json')
data = [json.loads(script.text, strict=False) for script in json_scripts] 
#use strict=False to bypass json.decoder.JSONDecodeError: Invalid control character
print(data)

最新更新