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
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
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. 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))))