Как извлечь несколько независимо вложенных JSON объектов и ключей с веб-сайта, используя Python - PullRequest
1 голос
/ 01 февраля 2020

Я хочу извлечь несколько независимых JSON объектов и связанных ключей с веб-страницы. Под «независимо вложенным» я подразумеваю, что каждый объект JSON вложен в элемент script type = "application/ld+json.

В настоящее время я использую beautifulsoup , json и просит попытаться выполнить sh эту задачу, но я не могу ' заставить его работать. Я прочитал похожие посты (например, здесь , здесь и здесь ), но ни один из них не решает эту проблему. В частности, как извлечь несколько независимо вложенных JSON объектов одновременно, а затем извлечь определенные c ключи из числа этих объектов. Другие примеры предполагают, что все объекты 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 для первого местоположения, однако не могу получить их для других 9 местоположений, перечисленных в переменной spanList. Как я могу Python получить мне JSON данные из других 9 мест? Я пробовал spanList.find_all, но это возвращает AttributeError: ResultSet object has no attribute 'text'. Но если я удаляю .text из json.loads, я получаю TypeError: the JSON object must be str, bytes or bytearray, not ResultSet.

Я догадываюсь, что это сложно, потому что каждый объект JSON имеет свой собственный атрибут script type = "application/ld+jso. Ни один из других примеров, которые я видел, не имел подобной ситуации. Кажется, json.loads только распознает этот первый JSON объект, а затем останавливается.

Другое осложнение заключается в том, что количество мест меняется в зависимости от города. Я надеюсь, что есть решение, которое автоматически вытянет все местоположения, независимо от того, сколько на странице (например, у Рено 10, а в Лас-Вегасе 20).

Я также не мог понять, как извлечь ключи из этой JSON загрузки, используя имена ключей, такие как name и streetAddress.. Это может быть основано на том, как я извлекаю JSON объект через json.dumps, но я не уверен.

Вот пример того, как выложен объект 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.

1 Ответ

1 голос
/ 01 февраля 2020

IIU C, вам просто нужно вызвать метод .find_all в вашем spanList, чтобы получить все 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)
...