Emetti l'analisi html utilizzando powershell e xpath

html html-agility-pack html-parsing powershell xpath

Domanda

Questa è una domanda successiva a quella che ho chiesto la scorsa settimana, pubblicata qui . Ho superato il problema originale, ma ora sto riscontrando un problema leggermente diverso.

Ora sono in grado di ottenere l'attributo di un oggetto a cui sono interessato se i tag html non sono nidificati utilizzando il metodo GetAttributeValue, qui è il data-pid ma ora sto riscontrando problemi nell'attribuire l'attributo di un elemento che è nei tag nidificati, nel mio snippet di codice è la data. Sto usando xpath e il pacchetto HtmlAgility per analizzare l'html qui, ma nell'esempio qui sotto la stessa data viene sempre restituita.

Ecco come appare l'oggetto $ item :

Attributes           : {class, data-pid}
ChildNodes           : {#text, a, #text, span...}
Closed               : True
ClosingAttributes    : {}
FirstChild           : HtmlAgilityPack.HtmlTextNode
HasAttributes        : True
HasChildNodes        : True
HasClosingAttributes : False
Id                   : 
InnerHtml            :  <a href="/mod/4175126893.html" class="i"><span class="price">$20</span></a> <span class="star"></span> <span class="pl"> <span class="date">Nov 
                       30</span>  <a href="/mod/4175126893.html">Unlock Any GSM Cell Phone Today!</a> </span> <span class="l2"> <span class="price">$20</span>  <span 
                       class="pnr"> <small> (Des Moines)</small> <span class="px"> <span class="p"> </span></span> </span>  <a class="gc" href="/mod/" 
                       data-cat="mod">cell phones - by dealer</a> </span> 
InnerText            :  $20   Nov 30  Unlock Any GSM Cell Phone Today!   $20    (Des Moines)      cell phones - by dealer  
LastChild            : HtmlAgilityPack.HtmlTextNode
Line                 : 305
LinePosition         : 5408
Name                 : p
NextSibling          : HtmlAgilityPack.HtmlTextNode
NodeType             : Element
OriginalName         : p
OuterHtml            : <p class="row" data-pid="4175126893"> <a href="/mod/4175126893.html" class="i"><span class="price">$20</span></a> <span class="star"></span> 
                       <span class="pl"> <span class="date">Nov 30</span>  <a href="/mod/4175126893.html">Unlock Any GSM Cell Phone Today!</a> </span> <span class="l2"> 
                       <span class="price">$20</span>  <span class="pnr"> <small> (Des Moines)</small> <span class="px"> <span class="p"> </span></span> </span>  <a 
                       class="gc" href="/mod/" data-cat="mod">cell phones - by dealer</a> </span> </p>
OwnerDocument        : HtmlAgilityPack.HtmlDocument
ParentNode           : HtmlAgilityPack.HtmlNode
PreviousSibling      : HtmlAgilityPack.HtmlTextNode
StreamPosition       : 18733
XPath                : /html[1]/body[1]/article[1]/section[1]/div[1]/div[2]/p[11]

Attributes           : {class, data-pid}
ChildNodes           : {#text, a, #text, span...}
Closed               : True
ClosingAttributes    : {}

Voglio estrarre i dati dal valore outerhtml .

OuterHtml            : <p class="row" data-latitude="41.5937565437255" data-longitude="-93.6437636649079" data-pid="4184719674"> <a href="/mod/4184719674.html" class="i"></a> 
               <span class="star"></span> <span class="pl"> <span class="date">Nov 27</span>  <a href="/mod/4184719674.html">iPhone and other Cell Phone Unlocks</a> 
               </span> <span class="l2">   <span class="pnr"> <small> (Des Moines)</small> <span class="px"> <span class="p"> <a href="#" class="maptag" 
               data-pid="4184719674">map</a></span></span> </span>  <a class="gc" href="/mod/" data-cat="mod">cell phones - by dealer</a> </span> </p>

Posso afferrare il data-pid senza problemi. Ecco come appare il codice attuale:

ForEach ($item in $results) {

    # This is working
    $ID = $item.GetAttributeValue("data-pid", "")

    # This is looping over the same item
    $Date = $item.SelectSingleNode("//span[@class='date']").InnerText
}

Quello che voglio fare è essere in grado di prendere gli attributi dai diversi tag che sono contenuti nell'oggetto outerhtml usando le mie istruzioni xpath ma non riesco a capire come farlo. È il modo migliore per risolvere il problema o dovrei semplicemente usare alcune espressioni regolari per ottenere il valore che voglio?

Fammi sapere quali altri dettagli ho bisogno di postare.

Risposta accettata

Non ho usato l'HTML Agility Pack, ma gli strumenti integrati di AFAICS dovrebbero comunque bastare:

$url = 'http://www.example.com/path/to/some.html'

$html = (Invoke-Webrequest $url).ParsedHTML

$html.getElementsByTagName('p') | ? { $_.className -eq 'row' } | % {
  $ID   = $_.getAttributeNode('data-pid').value
  $Date = $_.getElementsByTagName('span') | ? { $_.className -eq 'date' } |
          % { $_.innerText }

  # do stuff with $ID and $Date
  "{0}: {1}" -f $ID, $Date
}

Notare che Invoke-Webrequest richiede PowerShell v3. Utilizzare l'oggetto COM di Internet Explorer se si è limitati a PowerShell v2:

$ie = New-Object -COM InternetExplorer.Application
$ie.Navigate($url)
while ($ie.ReadyState -ne 4) { sleep 100 }
$html = $ie.Document

Se il tuo file HTML è un file locale, sostituisci la linea Invoke-Webrequest con qualcosa del genere:

$htmlfile = 'C:\path\to\some.html'

$html = New-Object -COM HTMLFile
$html.write((Get-Content $htmlfile | Out-String))

Risposta popolare

Sono in ritardo, ma ecco il tuo errore. Hai usato percorsi assoluti.

ForEach ($item in $results) {

    # This is working
    $ID = $item.GetAttributeValue("data-pid", "")

    # This is looping over the same item
    $Date = $item.SelectSingleNode("//span[@class='date']").InnerText

    # This is looping over the different items (i.e. this is what what you want)
    $Date = $item.SelectSingleNode(".//span[@class='date']").InnerText
}


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é