Parsing dl mit HtmlAgilityPack

asp.net c# html-agility-pack screen-scraping

Frage

Dies ist der HTML-Beispielcode, den ich mit Html Agility Pack in ASP.Net (C #) analysieren möchte.

<div class="content-div">
    <dl>
        <dt>
            <b><a href="1.html" title="1">1</a></b>
        </dt>
        <dd> First Entry</dd>
        <dt>
            <b><a href="2.html" title="2">2</a></b>
        </dt>
        <dd> Second Entry</dd>
        <dt>
            <b><a href="3.html" title="3">3</a></b>
        </dt>
        <dd> Third Entry</dd>
    </dl>
</div>

Die Werte, die ich möchte, sind:

  • Der Hyperlink -> 1.html
  • Der Ankertext -> 1
  • Innerer Text od dd -> Erster Eintrag

(Ich habe hier Beispiele des ersten Eintrags genommen, aber ich möchte die Werte für diese Elemente für alle Einträge in der Liste)

Dies ist der Code, den ich derzeit verwende,

var webGet = new HtmlWeb();
            var document = webGet.Load(url2);
var parsedValues=
   from info in document.DocumentNode.SelectNodes("//div[@class='content-div']")
   from content in info.SelectNodes("dl//dd")
   from link in info.SelectNodes("dl//dt/b/a")
       .Where(x => x.Attributes.Contains("href"))
   select new 
   {
       Text = content.InnerText,
       Url = link.Attributes["href"].Value,
       AnchorText = link.InnerText,
   };

GridView1.DataSource = parsedValues;
GridView1.DataBind();

Das Problem besteht darin, dass ich die Werte für den Link und den Ankertext richtig erkläre, aber für den inneren Text nur den Wert des ersten Eintrags und den gleichen Wert für alle anderen Einträge für die Gesamtzahl der Male, die das Element auftritt, enthält dann beginnt es mit dem zweiten. Ich bin vielleicht nicht so klar in meiner Erklärung, also hier ist eine Beispielausgabe, die ich mit diesem Code bekomme:

First Entry     1.html  1
First Entry     2.html  2
First Entry     3.html  3
Second Entry    1.html  1
Second Entry    2.html  2
Second Entry    3.html  3
Third Entry     1.html  1
Third Entry     2.html  2
Third Entry     3.html  3

Während ich versuche zu bekommen

First Entry      1.html     1
Second Entry     2.html     2
Third Entry      3.html     3

Ich bin ziemlich neu bei HAP und habe sehr wenig Wissen über XPath, also bin ich mir sicher, dass ich hier etwas falsch mache, aber ich konnte es nicht funktionieren lassen, selbst nachdem ich Stunden damit verbracht habe. Jede Hilfe würde sehr geschätzt werden.

Akzeptierte Antwort

Lösung 1

Ich habe eine Funktion definiert, die bei einem dt Knoten den nächsten dd Knoten dd :

private static HtmlNode GetNextDDSibling(HtmlNode dtElement)
{
    var currentNode = dtElement;

    while (currentNode != null)
    {
        currentNode = currentNode.NextSibling;

        if(currentNode.NodeType == HtmlNodeType.Element && currentNode.Name =="dd")
            return currentNode;
    }

    return null;
}

und jetzt kann der LINQ-Code umgewandelt werden in:

var parsedValues =
    from info in document.DocumentNode.SelectNodes("//div[@class='content-div']")
    from dtElement in info.SelectNodes("dl/dt")
    let link = dtElement.SelectSingleNode("b/a[@href]")
    let ddElement = GetNextDDSibling(dtElement)
    where link != null && ddElement != null
    select new
    {
        Text = ddElement.InnerHtml,
        Url = link.GetAttributeValue("href", ""),
        AnchorText = link.InnerText
    };

Lösung 2

Ohne zusätzliche Funktionen:

var infoNode = 
        document.DocumentNode.SelectSingleNode("//div[@class='content-div']");

var dts = infoNode.SelectNodes("dl/dt");
var dds = infoNode.SelectNodes("dl/dd");

var parsedValues = dts.Zip(dds,
    (dt, dd) => new
    {
        Text = dd.InnerHtml,
        Url = dt.SelectSingleNode("b/a[@href]").GetAttributeValue("href", ""),
        AnchorText = dt.SelectSingleNode("b/a[@href]").InnerText
    });

Beliebte Antwort

Nur ein Beispiel dafür, wie Sie einige Elemente mit Html Agility Pack analysieren können

public string ParseHtml()
{
    string output = null;
    HtmlDocument htmldocument = new HtmlDocument();
    htmldocument.LoadHtml(YourHTML);

    HtmlNode node = htmldocument.DocumentNode;    

    HtmlNodeCollection dds = node.SelectNodes("//dd"); //Select all dd tags
    HtmlNodeCollection anchors = node.SelectNodes("//b/a[@href]"); //Select all 'a' tags that contais href attribute

    for (int i = 0; i < dds.Count; i++)
    {
        string atributteValue = null.
        Text = dds[i].InnerText;
        Url = anchors[i].GetAttributeValue("href", atributteValue);
        AnchorText = anchors[i].InnerText;

        //Your code...
    }
    return output;
}



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