Salta al contenuto

Introduzione rapida all'analisi di JSON con JSONPath in Python

JSON è diventato di fatto lo standard per lo scambio di dati sul web. API, servizi Web e siti Web moderni utilizzano ampiamente JSON per l'invio di dati tra server e client.

Ad esempio, secondo BuiltWith, oltre il 70% dei 10,000 siti Web principali utilizza API JSON. Il formato JSON è facile da generare e analizzare in qualsiasi linguaggio di programmazione.

Tuttavia, estrarre in modo efficiente informazioni significative da documenti JSON di grandi dimensioni può ancora essere difficile. È qui che entra in gioco JSONPath: un linguaggio di query specializzato per semplificare il modo in cui individuare e trasformare i dati JSON.

Il problema con l'analisi JSON

Tradizionalmente, i dati JSON vengono elaborati nelle applicazioni analizzandoli completamente in strutture dati native come i dict Python. Analizzeresti l'intera risposta JSON anche se avessi bisogno solo di un piccolo sottoinsieme di dati.

Questo approccio presenta alcuni svantaggi:

  • Rallentamento delle prestazioni – L'analisi di file JSON di grandi dimensioni in oggetti è computazionalmente costosa
  • Elevato utilizzo della memoria – L'intera struttura JSON deve essere mantenuta in memoria
  • Codice dettagliato – Spesso è necessario scrivere molto codice di loop/attraversamento per scavare negli oggetti analizzati

Un'alternativa è utilizzare le espressioni regolari per estrarre direttamente i frammenti JSON corrispondenti. Tuttavia, le espressioni regolari diventano disordinate con complesse strutture nidificate. Ha anche problemi con nomi di chiavi dinamici o profondità di nidificazione arbitrarie.

JSONPath fornisce un modo più chiaro e conciso per eseguire query su JSON rispetto all'analisi non elaborata o alla corrispondenza regex.

Presentazione di JSONPath

Le espressioni JSONPath descrivono come accedere a parti di un documento JSON. È concettualmente simile a XPath che consente di interrogare elementi e attributi in XML:

//node/child::*  - XPath for all child nodes
$.node.child     - Equivalent JSONPath 

Alcuni vantaggi dell'approccio JSONPath:

  • leggibilità – Le espressioni di query sono facili da comprendere
  • concisione – Non è necessario un codice di attraversamento dettagliato
  • Flessibilità – Supporta ricerche, filtri, corrispondenze con caratteri jolly
  • Prestazione – Algoritmi di corrispondenza molto ottimizzati
  • Scalabilità – Può elaborare rapidamente anche documenti JSON di grandi dimensioni

JSONPath fornisce un'alternativa semplice e scalabile per l'estrazione dei dati da JSON. Successivamente esaminiamo come funziona.

Interrogazione di JSON con JSONPath

Un'espressione JSONPath è una stringa che descrive come individuare i valori all'interno di una struttura JSON. Per esempio:

data = {
  "store": {
    "books": [
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      }
    ]
  }
}

# All book titles
books = jsonpath(data, ‘$.store.books[*].title‘) 

# Filter fiction books 
fiction_books = jsonpath(data, ‘$.store.books[?(@.category=="fiction")].title‘)

JSONPath utilizza operatori come:

  • . – Operatore bambino
  • [] – Operatore di pedice per l'accesso all'array
  • * – Carattere jolly per tutti gli elementi corrispondenti
  • ?() – Filtraggio dei predicati

Concatenarli insieme consente di eseguire query in modo efficiente in JSON complessi:

# Get all authors of books over 10 dollars 
authors = jsonpath(data, ‘$.store.books[?(@.price > 10)].author‘)

Niente più codice di loop annidato in profondità! JSONPath abbina gli oggetti direttamente senza la necessità di analizzare completamente l'intero albero JSON.

Operatori JSONPath disponibili

Ecco un riepilogo degli operatori disponibili in JSONPath:

Operatori di percorso

  • $ – Oggetto radice
  • @ – Oggetto corrente
  • . or [] – Operatore bambino
  • .. – Cerca ricorsivamente i discendenti

Operatori di filtro

  • [?(<expression>)]– Filtra oggetti
  • [(<condition>)]– Filtra in base alla condizione

Operatori di matrice

  • * – Il carattere jolly indicizza tutti gli elementi
  • [<index>] – Posizione dell'indice
  • [start:end] – Porzione di array
  • [?(<condition>)] – Filtro

Operatori per la proiezione

  • [] – Proiezione – Estrae le proprietà elencate
  • [@] – Proiezione dell'indice – Appiattisce gli array

Altri operatori

  • | – Operatore sindacale
  • () – Operatore prioritario
  • , – Delimita più risultati

Questi ti offrono un'ampia flessibilità per eseguire query, filtrare e trasformare i dati JSON utilizzando semplici stringhe di percorso.

JSONPath e XPath per XML

Poiché JSONPath condivide molte somiglianze con XPath, vale la pena confrontare i due:

XPath

  • Linguaggio di query per XML
  • Consente di attraversare l'albero XML
  • Supporta assi avanzati come //, /*, //@
  • Utilizzare per estrarre i nodi XML

Percorso JSON

  • Linguaggio di query equivalente per JSON
  • Sintassi ispirata a XPath
  • La sintassi più semplice poiché JSON è rappresentativamente più semplice di XML
  • Implementazione rapida poiché non è necessaria l'analisi XML

Entrambi consentono di selezionare nodi in strutture di dati gerarchiche. JSONPath potrebbe essere considerata una versione semplificata di XPath specializzata per JSON anziché XML.

JSONPath è stato implementato per molti linguaggi di programmazione. Alcune librerie popolari per Python sono:

BibliotecaDescrizione
jsonpath-ngLibreria consigliata, veloce con funzionalità avanzate
jsonpath-rwImplementazione di riferimento conforme
jsonpathImplementazione semplice ma funzionalità limitate

Per la maggior parte degli usi, jsonpath-ng fornisce la migliore combinazione di conformità, funzionalità e prestazioni.

Vediamo come utilizzarlo in modo più dettagliato.

Interrogazioni e filtri con jsonpath-ng

Innanzitutto, installa jsonpath-ng:

pip install jsonpath-ng

Importare:

from jsonpath_ng import jsonpath, parse

Qualche esempio:

data = { "name": "John",
          "age": 30,
          "cars": [
            { "model": "BMW", "year": 2019 },
            { "model": "Tesla", "year": 2020 } 
          ]
        }

# Extract name
name = jsonpath(data, ‘$.name‘)

# Get first car 
first_car = jsonpath(data, ‘$.cars[0]‘)

# Filter Tesla cars
teslas = jsonpath(data, ‘$.cars[?(@.model=="Tesla")]‘) 

# Get all car years 
years = jsonpath(data, ‘$..cars[*].year‘)

È inoltre possibile utilizzare il parse() metodo che compila il percorso per prestazioni migliori:

parser = parse(‘$.cars[*].year‘)

for obj in json_data:
   years = parser.find(obj)
   print(years)

Funziona più velocemente quando si applica lo stesso percorso a più documenti JSON.

Filtraggio dei dati JSON

Una delle funzionalità più potenti di JSONPath è la sua sintassi di filtro.

I filtri consentono di selezionare oggetti che corrispondono a criteri specifici. Per esempio:

RecentCars = jsonpath(data, ‘$.cars[?(@.year > 2015)]‘)

Questo rende le auto più nuove del 2015.

Puoi filtrare utilizzando confronti come:

  • Matematico: =, !=, >, <=, ecc.
  • Logico: and, or, not
  • Espressioni regolari: =~, !=~
  • Esistenza: exists(), ?()

I filtri possono anche essere combinati:

ElectricCars = jsonpath(data, 
   ‘$.cars[?(@.year > 2010 && @.model =~ "Tesla|Volt")]`
)

Ciò consentirà di produrre auto elettriche dopo il 2010.

Trasformazione dei dati JSON

Oltre a estrarre i dati, JSONPath può trasformare oggetti JSON utilizzando operatori come:

  • [] – Proiezione per rimodellare gli oggetti
  • [@] – Indicizzazione degli array da appiattire

Ad esempio, appiattindo i dati dell'auto in un semplice elenco:

all_models = jsonpath(data, ‘$..cars[*].model‘)
all_years = jsonpath(data, ‘$..cars[*].@year‘) 

I @ esegue proiezioni basate su indici.

Il concatenamento di filtri, proiezioni e sezioni consente di ristrutturare JSON a livello di codice.

Funzionalità avanzate di jsonpath-ng

Alcune funzionalità avanzate aggiuntive fornite da jsonpath-ng:

Funzioni personalizzate

Puoi registrare funzioni personalizzate per estendere JSONPath:

def format_price(x):
  return f‘${x:,.2f}‘

jsonpath.register_custom_function(format_price, ‘format‘)

prices = jsonpath(data, ‘$.prices[*].format(@)‘) 

Ciò consente di implementare trasformazioni di dati complesse direttamente all'interno delle espressioni JSONPath.

Caching e ottimizzazione

jsonpath-ng compila e ottimizza le query per le prestazioni. Supporta anche:

  • Memorizzazione nella cache per la velocità
  • Corrispondenza pigra per evitare scansioni non necessarie
  • Ottimizzazione della resa in uscita

Quindi funziona bene anche con enormi documenti JSON.

Operatori aggiuntivi

Alcuni altri operatori utili:

  • ?() – Verifica dell'esistenza
  • =~, !=~ – Corrispondenza regex
  • in – Contiene assegno
  • all – Quantificatore universale

Metodi JSONPath

Metodi di supporto come:

  • find() – Restituisce le corrispondenze
  • parse() – Compila il percorso

Fornire un'API più semplice per le query comuni.

Utilizzo di JSONPath per il Web Scraping

Una delle applicazioni più utili di JSONPath è l'estrazione dei dati durante il web scraping.

I siti Web moderni fanno molto affidamento su JSON per la trasmissione dei dati:

  • API – JSON è il formato standard per le API REST
  • Dati asincroni – JSON viene utilizzato con JavaScript per gli aggiornamenti dinamici delle pagine
  • Metadati della pagina – Dati del sito spesso archiviati in script come JSON

Analizzare manualmente tutto questo JSON sarebbe complicato. JSONPath consente di eseguire facilmente query solo sui frammenti necessari.

Ad esempio, ecco come estrarre i dati di prodotto da una pagina di e-commerce:

import requests
from jsonpath_ng import jsonpath, parse

# Fetch product page
url = "http://www.example.com/product/123"  
response = requests.get(url)

# Extract JSON data 
data = response.json()

# Parse out product details 
name = jsonpath(data, ‘$.product.name‘)[0]
price = jsonpath(data, ‘$.product.price‘)[0] 
image = jsonpath(data, ‘$.product.images[0]‘)

print(name, price, image)

La chiave sta nell'utilizzare JSONPath per acquisire direttamente solo i campi necessari invece dell'elaborazione manuale.

Ecco alcuni casi d'uso comuni:

  • Raschiamento API – Estrai i dati dalle risposte dell'API REST
  • Siti JavaScript – Interrogare gli oggetti utilizzati dai frontend
  • applicazioni mobili – Analizza i dati JSON dal traffico dell'app
  • Contenuto dinamico – Crea set di dati da JavaScript lato client

JSONPath consente lo scraping scalabile di migliaia di documenti JSON con semplici stringhe di percorso.

Analisi di file JSON di grandi dimensioni

Anche se JSONPath si adatta bene, l'analisi di enormi documenti JSON può ancora presentare sfide:

  • Utilizzo della memoria – Caricamento dell'intero JSON in memoria
  • Carico della CPU – L'analisi di documenti complessi richiede un uso intensivo del processore
  • Trasferimento in rete – Documenti di grandi dimensioni significano più larghezza di banda

Alcuni suggerimenti quando si lavora con dati JSON di grandi dimensioni:

  • Utilizza parser di streaming per evitare il caricamento completo di JSON
  • Compila percorsi con parse() invece di ripetere l'analisi
  • Estrai solo i campi effettivamente necessari invece degli oggetti completi
  • Usa il laziness per evitare scansioni di oggetti non necessarie
  • Esegui su potenti server cloud quando gestisci dati su scala TB+
  • Distribuisci l'analisi tra i cluster per l'elaborazione parallela

Nella maggior parte dei casi, JSONPath può estrarre in modo efficiente i dati anche da file JSON di grandi dimensioni con centinaia di migliaia di record se ottimizzato correttamente.

Perché mi piace usare JSONPath

In qualità di ingegnere proxy esperto che lavora ampiamente con i dati JSON, ecco perché adoro utilizzare JSONPath:

  • Sintassi concisa – Le espressioni del percorso sono meravigliosamente concise rispetto al codice di analisi tradizionale
  • Produttività incrementata – Puoi interrogare JSON con la stessa facilità con cui interroga un database grazie alla sintassi intuitiva
  • Filtraggio robusto – I filtri dei predicati semplificano la selezione dei dati corrispondenti
  • Prestazioni incredibilmente veloci – jsonpath-ng utilizza algoritmi estremamente ottimizzati che consentono un'estrazione dei dati rapidissima anche su set di dati di grandi dimensioni
  • Memoria efficiente – Poiché analizza JSON in modo selettivo, l'impronta di memoria è bassa rispetto all'analisi completa in oggetti nativi
  • Potenza di web scraping – La facile estrazione dei dati dalle API e dalle risposte JavaScript è il punto in cui JSONPath brilla

Sebbene strumenti come jq e grep siano ottimi, trovo che JSONPath sia più semplice ed elegante per la maggior parte delle mie esigenze di analisi JSON. Il supporto dell'ecosistema Python con librerie come jsonpath-ng lo rende la mia scelta preferita per affettare e tagliare i dati JSON.

Supporto JSONPath in altre lingue

Anche se ci siamo concentrati su Python, JSONPath è disponibile in molti linguaggi di programmazione:

Poiché JSON è un formato di dati universale, è utile poterlo interrogare in modo efficiente da qualsiasi lingua. Per fortuna JSONPath è ampiamente supportato.

Perché JSONPath è importante

JSON è diventato rapidamente essenziale per API Web, microservizi e applicazioni front-end. JSONPath porta funzionalità di query simili a XPath nel mondo dei dati JSON.

Avere un linguaggio di percorso standardizzato per estrarre facilmente valori JSON nidificati presenta molti vantaggi:

  • Semplifica l'estrazione dei dati JSON su piattaforme e linguaggi diversi
  • Fornisce un'alternativa leggibile alla brutta analisi delle espressioni regolari
  • Abilita il web scraping scalabile senza la necessità di analizzare intere risposte
  • Consente trasformazioni complesse utilizzando proiezioni e filtri
  • Sblocca la capacità di interrogare in modo efficiente enormi set di dati JSON
  • Si adatta naturalmente alle pipeline insieme ad altri strumenti JSON come jq

Poiché JSON continua a dominare come formato di interscambio di dati di fatto, disporre di un set di operatori JSONPath comuni aiuterà a domare la complessità della navigazione di documenti JSON di grandi dimensioni.

Conclusione

JSONPath fornisce un modo elegante per estrarre e trasformare valori dai dati JSON tramite espressioni di percorso concise.

Biblioteche come jsonpath-ng semplifica l'integrazione di JSONPath nei tuoi progetti Python.

Le prelibatezze chiave:

  • JSONPath consente di eseguire facilmente query nelle strutture JSON utilizzando "." e gli operatori '[]'
  • Il filtraggio in base ai valori delle proprietà utilizzando i predicati è ben dimensionato
  • Le trasformazioni possono essere applicate utilizzando proiezioni ed espansione di array
  • JSONPath evita la necessità di analizzare interi oggetti JSON durante lo scraping
  • La sintassi è modellata sulle espressioni XPath per eseguire query su XML
  • Supportato in molti linguaggi di programmazione

Per lavorare con servizi Web basati su JSON, JSONPath è uno strumento indispensabile per il toolkit di qualsiasi sviluppatore. JSONPath ti consente di porre domande semplici e ottenere solo i dati di cui hai bisogno da documenti JSON complessi.

Partecipa alla conversazione

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati con *