Tag di analisi non chiusi dalla pagina Web con HtmlAgilityPack

c# html-agility-pack linq

Domanda

Sto cercando di analizzare l'elenco delle stazioni dal sito web NOAA (weather.noaa.gov). Se guardi la fonte di una pagina come le stazioni bielorusse , puoi vedere l'elenco delle stazioni disponibili presentato come:

<select name="cccc">
    <option selected>Select a location
    <OPTION VALUE="UMBB"> Brest
    <OPTION VALUE="UMGG"> Gomel'
    <OPTION VALUE="UMMG"> Grodno
    <OPTION VALUE="UMMM"> Loshitsa / Minsk International 1
    <OPTION VALUE="UMMS"> Minsk
    <OPTION VALUE="UMII"> Vitebsk
</select>

Puoi vedere che i tag 'OPTION' non sono chiusi. Le opzioni predefinite in HtmlAgilityPack chiudono i tag in questo modo:

<select name="cccc">
    <option selected>Select a location
    <OPTION VALUE="UMBB"> Brest
    <OPTION VALUE="UMGG"> Gomel'
    <OPTION VALUE="UMMG"> Grodno
    <OPTION VALUE="UMMM"> Loshitsa / Minsk International 1
    <OPTION VALUE="UMMS"> Minsk
    <OPTION VALUE="UMII"> Vitebsk
</select>

Il che rende doloroso analizzare o attraversare. Ho inventato il seguente metodo per recurse di ogni tag, ma mi chiedo se c'è un modo più elegante, magari usando LINQ?

Il mio metodo:

<select name="cccc">
    <option selected>Select a location
    <OPTION VALUE="UMBB"> Brest
    <OPTION VALUE="UMGG"> Gomel'
    <OPTION VALUE="UMMG"> Grodno
    <OPTION VALUE="UMMM"> Loshitsa / Minsk International 1
    <OPTION VALUE="UMMS"> Minsk
    <OPTION VALUE="UMII"> Vitebsk
</select>

Che è chiamato così:

<select name="cccc">
    <option selected>Select a location
    <OPTION VALUE="UMBB"> Brest
    <OPTION VALUE="UMGG"> Gomel'
    <OPTION VALUE="UMMG"> Grodno
    <OPTION VALUE="UMMM"> Loshitsa / Minsk International 1
    <OPTION VALUE="UMMS"> Minsk
    <OPTION VALUE="UMII"> Vitebsk
</select>

Mi sento come se stessi usando un metodo di forza bruta per ottenere l'elenco delle stazioni e potrei perdere parte della potenza della libreria HtmlAgilityPack. C'è un modo migliore? Ci sono impostazioni che potrebbero rendere questo un non-problema? LINQ può gestirlo più facilmente?

Sto cercando XPATH, in quanto sembra il meccanismo più semplice per ottenere un sottoinsieme di tag. Tuttavia, a causa della mancata chiusura dei tag, ricevo tutti i tag di opzione sulla pagina, mentre voglio solo quelli all'interno del tag 'select'. Quindi, un qualificatore, come puoi vedere, è che i tag 'option' che voglio abbiano un valore @ = 'XXXX' dove 'XXXX' è un id della stazione in maiuscolo di 4 caratteri. C'è un modo per specificare che voglio solo i tag di opzione nel documente che hanno un attributo chiamato 'valore' con un valore di 4 caratteri maiuscolo? Posso passare una funzione di confronto ad una istruzione xpath?

Risposta accettata

Grazie per tutti i suggerimenti. Ho fatto più ricerche per la sintassi xpath, e ho trovato questo che funziona:

//select[@name='cccc']/descendant::option[@value]

questo mi dà tutti i tag 'option' sotto il tag 'select' con un attributo @ name = 'cccc' dove il tag 'option ha un attributo @value.

Molto meno lavoro di quello che stavo facendo. Ora per rifattorizzare tutto il mio altro codice che scorre attraverso il DOM usando HAP e vedere come XPATH può semplificarmi la vita!


Risposta popolare

HtmlAgilityPack può correggere automaticamente il tag di chiusura ma forse non esattamente come ti aspetti :

HtmlNode.ElementsFlags["option"] = HtmlElementFlag.Closed;
var doc = new HtmlDocument();
doc.LoadHtml(html);

Ad ogni modo, a questo punto puoi ancora selezionare il testo che dovrebbe trovarsi all'interno del tag <option> usando XPath following-sibling::text()[1] , ad esempio:

HtmlNode.ElementsFlags["option"] = HtmlElementFlag.Closed;
var doc = new HtmlDocument();
doc.LoadHtml(html);



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché