Невозможно извлечь все URL-адреса, доступные на разной глубине, из некоторого содержимого json

#python #json #python-3.x #web-scraping

#python #json #python-3.x #веб-очистка

Вопрос:

Я пытаюсь проанализировать все значения URL-адресов, доступных на разной глубине, в некотором содержимом json. Я прикрепляю файл, содержащий URL-адреса разной глубины, для вашего рассмотрения.

Вот как они структурированы (усечены):

 {'hasSub': True,
 'navigationTitle': 'Products',
 'nodeName': 'products',
 'pages': [{'hasSub': True,
            'navigationTitle': 'Enclosures',
            'nodeName': 'PG0002SCHRANK1',
            'pages': [{'hasSub': True,
                       'navigationTitle': 'Hygienic Design',
                       'nodeName': 'PG0125SCHRANK1',
                       'pages': [{'hasSub': False,
                                  'navigationTitle': 'Hygienic Design Terminal '
                                                     'box HD',
                                  'nodeName': 'PRO0130',
                                  'target': '_self',
                                  'url': '/com-en/products/PG0002SCHRANK1/PG0125SCHRANK1/PRO0130'},
                                 {'hasSub': False,
                                  'navigationTitle': 'Hygienic Design Compact '
                                                     'enclosure HD, '
                                                     'single-door',
                                  'nodeName': 'PRO0131',
                                  'target': '_self',
                                  'url': '/com-en/products/PG0002SCHRANK1/PG0125SCHRANK1/PRO0131'},
 

Если я рассмотрю вышеуказанный контент, результат, который я ищу:

 /com-en/products/PG0002SCHRANK1/PG0125SCHRANK1/PRO0130
/com-en/products/PG0002SCHRANK1/PG0125SCHRANK1/PRO0131
 

Сценарий, который я написал для создания содержимого json:

 import requests
from pprint import pprint

url = 'https://www.rittal.com/.rest/nav/menu/tree?'
params = {
    'path': 'com',
    'locale': 'en',
    'deep': '10'
}
with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
    s.headers['Accept'] = 'application/json, text/plain, */*'
    r = s.get(url,params=params)
    pprint(r.json()['pages'][0])
 

Как я могу удалить все URL-адреса с разной глубины из содержимого json?

Ответ №1:

Хорошо, кажется, я нашел решение в другом месте для извлечения всех доступных ссылок из любого вложенного json.

 import requests
from pprint import pprint

url = 'https://www.rittal.com/.rest/nav/menu/tree?'
params = {
    'path': 'com',
    'locale': 'en',
    'deep': '10'
}

def json_extract(obj, key):
    arr = []

    def extract(obj, arr, key):
        if isinstance(obj, dict):
            for k, v in obj.items():
                if isinstance(v, (dict, list)):
                    extract(v, arr, key)
                elif k == key:
                    arr.append(v)
        elif isinstance(obj, list):
            for item in obj:
                extract(item, arr, key)
        return arr

    values = extract(obj, arr, key)
    return values

with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
    s.headers['Accept'] = 'application/json, text/plain, */*'
    r = s.get(url, params=params).json()
    for item in json_extract(r,'url'):
        print(item)
 

Количество ссылок, создаваемых скриптом, составляет около 3500.

Ответ №2:

Что вы можете сделать, так это выполнить рекурсию по JSON. Это лучший способ справиться с разной глубиной URL-адресов.

Следующая рекурсия извлечет самые глубокие URL-адреса путем рекурсии по JSON.

 import requests
from pprint import pprint

url = 'https://www.rittal.com/.rest/nav/menu/tree'
params = {
    'path': 'com',
    'locale': 'en',
    'deep': '10'
}

def recurse(data):
    if 'pages' in data:
        for page in data['pages']:
            recurse(page)
    elif 'url' in data and data['url'].startswith('/com-en/'):
        urls.append(data['url'])

urls = []
with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
    s.headers['Accept'] = 'application/json, text/plain, */*'
    r = s.get(url, params=params).json()
    recurse(r)
    pprint(urls)
 

Вот как это работает:

  • Рекурсивный случай — если на текущем уровне есть страницы, выполните рекурсию для каждой page на текущем уровне
  • Базовый вариант — если URL-адрес отображается на текущем уровне, добавьте его в список URL-адресов

Кроме того, если вы отключите elif for an if , он предоставит вам все URL-адреса на любом уровне.

Обновление: кажется, в этом JSON есть 2 URL-адреса rouge. В частности, один есть https://www.eplan-software.com/solutions/eplan-platform/ , а другой пуст! Таким образом, я добавил условие data['url'].startswith('/com-en/') для добавления только тех URL-адресов, которые соответствуют ожидаемому шаблону.