我想从网页中提取多个独立的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 个(。
我也无法弄清楚如何使用name
和streetAddress.
等键名称从此 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"
}
我的最终目标是将键name
、streetAddress
、addressLocality
、addressRegion
和postalCode
中包含的数据导出到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)