Abrufen von Attributen und Bereichen mithilfe der HTMLAgilityPack-Bibliothek

.net html html-agility-pack html-parsing vb.net

Frage

In diesem Stück HTML-Code:

<div class="item">

    <div class="thumb">
        <a href="http://www.mp3crank.com/wolf-eyes/lower-demos-121866" rel="bookmark" lang="en" title="Wolf Eyes - Lower Demos album downloads">
        <img width="100" height="100" alt="Mp3 downloads Wolf Eyes - Lower Demos" title="Free mp3 downloads Wolf Eyes - Lower Demos" src="http://www.mp3crank.com/cover-album/Wolf-Eyes-–-Lower-Demos.jpg" /></a>
    </div>

    <div class="release">
        <h3>Wolf Eyes</h3>
        <h4>
        <a href="http://www.mp3crank.com/wolf-eyes/lower-demos-121866" title="Wolf Eyes - Lower Demos">Lower Demos</a>
        </h4>
        <script src="/ads/button.js"></script>
    </div>

    <div class="release-year">
        <p>Year</p>
        <span>2013</span>
    </div>

    <div class="genre">
        <p>Genre</p>
        <a href="http://www.mp3crank.com/genre/rock" rel="tag">Rock</a>
        <a href="http://www.mp3crank.com/genre/pop" rel="tag">Pop</a>
    </div>

</div>

Ich weiß, wie man es auf andere Weise analysiert, aber ich möchte diese Info mit der HTMLAgilityPack Bibliothek HTMLAgilityPack :

Title : Wolf Eyes - Lower Demos
Cover : http://www.mp3crank.com/cover-album/Wolf-Eyes-–-Lower-Demos.jpg
Year  : 2013
Genres: Rock, Pop
URL   : http://www.mp3crank.com/wolf-eyes/lower-demos-121866

Welches sind diese HTML-Zeilen:

Title : title="Wolf Eyes - Lower Demos"
Cover : src="http://www.mp3crank.com/cover-album/Wolf-Eyes-–-Lower-Demos.jpg"
Year  : <span>2013</span>
Genre1: <a href="http://www.mp3crank.com/genre/rock" rel="tag">Rock</a>
Genre2: <a href="http://www.mp3crank.com/genre/pop" rel="tag">Pop</a>
URL   : href="http://www.mp3crank.com/wolf-eyes/lower-demos-121866" 

Dies ist, was ich versuche, aber ich bekomme immer eine object reference not set Ausnahme beim Versuch, einen einzigen Knoten zu wählen, Sorry, aber ich bin sehr Neuling mit HTML, habe ich versucht, die Schritte dieser Frage zu folgen HtmlAgilityPack wie um Titel und Link zu bekommen?

Public Class Form1

    Private htmldoc As HtmlAgilityPack.HtmlDocument = New HtmlAgilityPack.HtmlDocument
    Private htmlnodes As HtmlAgilityPack.HtmlNodeCollection = Nothing

    Private Title As String = String.Empty
    Private Cover As String = String.Empty
    Private Genres As String() = {String.Empty}
    Private Year As Integer = -0
    Private URL as String = String.Empty

    Private Sub Test() Handles MyBase.Shown

        ' Load the html document.
        htmldoc.LoadHtml(IO.File.ReadAllText("C:\source.html"))

        ' Select the (10 items) nodes.
        htmlnodes = htmldoc.DocumentNode.SelectNodes("//div[@class='item']")

        ' Loop trough the nodes.
        For Each node As HtmlAgilityPack.HtmlNode In htmlnodes

            Title = node.SelectSingleNode("//div[@class='release']").Attributes("title").Value
            Cover = node.SelectSingleNode("//div[@class='thumb']").Attributes("src").Value
            Year = CInt(node.SelectSingleNode("//div[@class='release-year']").Attributes("span").Value)
            Genres = ¿select multiple nodes?
            URL = node.SelectSingleNode("//div[@class='release']").Attributes("href").Value

        Next

    End Sub

End Class

Akzeptierte Antwort

Dein Fehler hier ist es, zu versuchen, auf ein Attribut eines Childnode von dem, den du gefunden hast, zuzugreifen.

Wenn Sie node.SelectSingleNode("//div[@class='release']") aufrufen, wird das richtige div zurückgegeben, aber das Aufrufen von .Attributes gibt nur die Attribute für das div Tag selbst und nicht für die inneren HTML-Elemente zurück.

Es ist möglich, XPATH-Abfragen zu schreiben, die den Unterknoten auswählen, zB //div[@class='release']/a - siehe http://www.w3schools.com/xpath/xpath_syntax.asp für weitere Informationen zu XPATH. Obwohl die Beispiele für XML gelten, sollten die meisten Prinzipien für ein HTML-Dokument gelten.

Ein anderer Ansatz besteht darin, weitere XPATH-Aufrufe für den gefundenen Knoten zu verwenden. Ich habe Ihren Code so geändert, dass er mit diesem Ansatz funktioniert:

' Load the html document.
htmldoc.LoadHtml(IO.File.ReadAllText("C:\source.html"))

' Select the (10 items) nodes.
htmlnodes = htmldoc.DocumentNode.SelectNodes("//div[@class='item']")

' Loop through the nodes.
For Each node As HtmlAgilityPack.HtmlNode In htmlnodes

    Dim releaseNode = node.SelectSingleNode(".//div[@class='release']")
    'Assumes we find the node and it has a a-tag
    Title = releaseNode.SelectSingleNode(".//a").Attributes("title").Value
    URL = releaseNode.SelectSingleNode(".//a").Attributes("href").Value

    Dim thumbNode = node.SelectSingleNode(".//div[@class='thumb']")
    Cover = thumbNode.SelectSingleNode(".//img").Attributes("src").Value

    Dim releaseYearNode = node.SelectSingleNode(".//div[@class='release-year']")
    Year = CInt(releaseYearNode.SelectSingleNode(".//span").InnerText)

    Dim genreNode = node.SelectSingleNode(".//div[@class='genre']")
    Dim genreLinks = genreNode.SelectNodes(".//a")
    Genres = (From n In genreLinks Select n.InnerText).ToArray()

    Console.WriteLine("Title : {0}", Title)
    Console.WriteLine("Cover : {0}", Cover)
    Console.WriteLine("Year  : {0}", Year)
    Console.WriteLine("Genres: {0}", String.Join(",", Genres))
    Console.WriteLine("URL   : {0}", URL)

Next

Beachten Sie, dass in diesem Code angenommen wird, dass das Dokument korrekt erstellt wurde und dass jeder Knoten / jedes Element / Attribut existiert und korrekt ist. Vielleicht möchten Sie dazu eine Menge Fehler hinzufügen, zB If someNode Is Nothing Then ....

Edit: Ich habe den Code oben leicht geändert, um sicherzustellen, dass jeder .SelectSingleNode das "./" Präfix verwendet - das stellt sicher, dass es funktioniert, wenn es mehrere "Element" -Knoten gibt, andernfalls wählt es die erste Übereinstimmung aus dem Dokument nicht die aktuelle Knoten.

Wenn Sie eine kürzere XPATH-Lösung wünschen, ist hier der gleiche Code, der diesen Ansatz verwendet:

' Load the html document.
htmldoc.LoadHtml(IO.File.ReadAllText("C:\source.html"))

' Select the (10 items) nodes.
htmlnodes = htmldoc.DocumentNode.SelectNodes("//div[@class='item']")

' Loop through the nodes.
For Each node As HtmlAgilityPack.HtmlNode In htmlnodes

    Title = node.SelectSingleNode(".//div[@class='release']/h4/a[@title]").Attributes("title").Value
    URL = node.SelectSingleNode(".//div[@class='release']/h4/a[@href]").Attributes("href").Value

    Cover = node.SelectSingleNode(".//div[@class='thumb']/a/img[@src]").Attributes("src").Value

    Year = CInt(node.SelectSingleNode(".//div[@class='release-year']/span").InnerText)

    Dim genreLinks = node.SelectNodes(".//div[@class='genre']/a")
    Genres = (From n In genreLinks Select n.InnerText).ToArray()

    Console.WriteLine("Title : {0}", Title)
    Console.WriteLine("Cover : {0}", Cover)
    Console.WriteLine("Year  : {0}", Year)
    Console.WriteLine("Genres: {0}", String.Join(",", Genres))
    Console.WriteLine("URL   : {0}", URL)
    Console.WriteLine()

Next

Beliebte Antwort

Sie waren nicht weit von der Lösung entfernt. Zwei wichtige Hinweise:

  • // ist ein rekursiver Aufruf. Dies kann schwerwiegende Auswirkungen auf die Leistung haben, und es kann auch Knoten auswählen, die Sie nicht möchten. Daher schlage ich vor, dass Sie nur verwenden, wenn die Hierarchie tief oder komplex oder variabel ist und Sie nicht den gesamten Pfad angeben möchten.
  • Es gibt eine nützliche XmlNode für XmlNode namens GetAttributeValue der Sie ein Attribut erhalten, auch wenn es nicht existiert (Sie müssen den Standardwert angeben).

Hier ist ein Beispiel, das zu funktionieren scheint:

' select the base/parent DIV (here we use a discriminant CLASS attribute)
' all select calls below will use this DIV element as a starting point
Dim node As HtmlNode = htmldoc.DocumentNode.SelectNodes("//div[@class='item']")

' get to the A tag which is a child or grand child (//) of a 'release' DIV
Console.WriteLine(("Title :" & node.SelectSingleNode("div[@class='release']//a").GetAttributeValue("title", CStr(Nothing))))

' get to the IMG tag which is a child or grand child (//) of a 'thumb' DIV
Console.WriteLine(("Cover :" & node.SelectSingleNode("div[@class='thumb']//img").GetAttributeValue("src", CStr(Nothing))))

' get to the SPAN tag which is a child or grand child (//) of a 'release-year' DIV
Console.WriteLine(("Year  :" & node.SelectSingleNode("div[@class='release-year']//span").InnerText))

' get all A elements which are child or grand child(//) of a 'genre' DIV
Dim nodes As HtmlNodeCollection = node.SelectNodes("div[@class='genre']//a")
Dim i As Integer
For i = 0 To nodes.Count - 1
    Console.WriteLine(String.Concat(New Object() { "Genre", (i + 1), ":", nodes.Item(i).InnerText }))
Next i

' get to the A tag which is a child or grand child (//) of a 'release' DIV
Console.WriteLine(("Url   :" & node.SelectSingleNode("div[@class='release']//a").GetAttributeValue("href", CStr(Nothing))))


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum