HtmlAgilityPack으로 dl 구문 분석하기

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

문제

이것은 ASP.Net (C #)의 HTML 민첩성 팩으로 구문 분석하려고하는 샘플 HTML입니다.

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

내가 원하는 가치는 다음과 같습니다.

  • 하이퍼 링크 -> 1.html
  • 앵커 텍스트 -> 1
  • 내부 텍스트 및 첫 번째 항목

(여기서 첫 번째 항목의 예를 살펴 보았지만 목록의 모든 항목에 대해 이러한 요소의 값을 원합니다.)

이것은 현재 사용중인 코드입니다.

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();

문제는 링크와 앵커 텍스트에 대한 값을 올바르게 얻었지만 내부 텍스트의 경우 첫 번째 항목의 값만 사용하고 요소가 발생한 총 횟수에 대해 다른 모든 항목에 대해 동일한 값을 채 웁니다. 그런 다음 두 번째 것으로 시작합니다. 내 설명에서 그렇게 명확하지 않을 수도 있으므로 여기에이 코드를 사용하여 얻은 샘플 출력이 나와 있습니다.

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

내가 얻으려고하는 반면

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

나는 거의 허풍에 빠지며 xpath에 대한 지식이 거의 없다. 그래서 나는 여기서 뭔가 잘못하고 있다고 확신한다. 그러나 나는 그것에 시간을 투자 한 후에도 일을 할 수 없다. 어떤 도움이라도 대단히 감사 할 것입니다.

수락 된 답변

해결책 1

나는 dt 노드가 주어진 다음 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;
}

이제 LINQ 코드는 다음과 같이 변환 될 수 있습니다.

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
    };

해결책 2

추가 기능이없는 경우 :

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
    });

인기 답변

예를 들어 Html Agility Pack 사용하여 몇 가지 요소를 구문 분석 할 수 있습니다.

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;
}



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.