如何使用HTML Agility Pack

655

我该如何使用 HTML Agility Pack

我的XHTML文档不完全有效,所以我想使用它。我该如何在我的C#项目中使用它?


84
这个问题对我非常有帮助。 - BigJoe714
26
附注:使用能处理NuGet的Visual Studio,您现在可以右键点击“引用”,然后选择“管理NuGet程序包...”,搜索“HtmlAgilityPack”并单击“安装”。然后通过使用/导入语句立即开始编写代码。 - patridge
@AndrewCoonce 听起来 NuGet 上的“还原缺失的包”选项可能有助于解决这个问题。 - Cornelius
14
对于那些正在研究HTMLAgilityPack的人,应该考虑使用CsQuery,它是一个更新的库,从我的经验来看,具有更现代化的接口。例如,第一个答案中的整个代码可以用CsQuery简化为var body = CQ.CreateFromFile(filePath)["body"] - Benjamin Gruenbaum
2
@BenjaminGruenbaum:感谢您的CsQuery建议-几分钟即可设置,非常易于使用。 - Victor Zakharov
显示剩余4条评论
7个回答

366

首先,将HTMLAgilityPack nuget包安装到您的项目中。

然后,作为示例:

HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();

// There are various options, set as needed
htmlDoc.OptionFixNestedTags=true;

// filePath is a path to a file containing the html
htmlDoc.Load(filePath);

// Use:  htmlDoc.LoadHtml(xmlString);  to load from a string (was htmlDoc.LoadXML(xmlString)

// ParseErrors is an ArrayList containing any errors from the Load statement
if (htmlDoc.ParseErrors != null && htmlDoc.ParseErrors.Count() > 0)
{
    // Handle any parse errors as required

}
else
{

    if (htmlDoc.DocumentNode != null)
    {
        HtmlAgilityPack.HtmlNode bodyNode = htmlDoc.DocumentNode.SelectSingleNode("//body");

        if (bodyNode != null)
        {
            // Do something with bodyNode
        }
    }
}

(NB: 此代码仅为示例,不一定是最佳/唯一的方法。请勿盲目在您自己的应用程序中使用它。)

HtmlDocument.Load() 方法还接受流参数,这在与.NET框架中的其他面向流类集成时非常有用。而 HtmlEntity.DeEntitize() 是处理HTML实体的另一个有用方法。(感谢Matthew)

HtmlDocumentHtmlNode 是你将会经常使用的类。类似于XML解析器,它提供了selectSingleNode和selectNodes方法,这些方法接受XPath表达式。

注意 HtmlDocument.Option?????? 布尔属性。它们控制LoadLoadXML方法如何处理您的HTML/XHTML。

还有一个名为HtmlAgilityPack.chm的编译帮助文件,其中包含每个对象的完整参考文档。通常位于解决方案的基本文件夹中。


11
请注意,Load方法接受一个流(Stream)参数,在许多情况下这是很方便的。我用它来处理HTTP流(WebResponse.GetResponseStream)。另一个需要注意的好方法是HtmlEntity.DeEntitize(HTML Agility Pack的一部分),在某些情况下需要手动处理实体。 - Matthew Flaschen
1
请注意:在最新的 Html Agility Pack beta 版本(1.4.0 Beta 2,发布于2009年10月3日),帮助文件已经移出到单独的下载中,因为它依赖于 Sandcastle、DocProject 和 Visual Studio 2008 SDK。 - rtpHarry
3
不,SelectSingleNode和SelectNodes仍然存在。有趣的是应该使用htmlDoc.ParseErrors.Count()而不是.Count。 - Mike Blandford
1
@MikeBlandford // 部分是的。在HtmlAgailityPack的PCL版本中,它似乎已被删除(或从一开始就不存在)。http://www.nuget.org/packages/HtmlAgilityPack-PCL/ - Joon Hong
htmlDoc.ParseErrors.Count() > 0 替换为 htmlDoc.ParseErrors.Any() - mathewsun
显示剩余2条评论

167

17
终于在两年后完成了那篇文章 :) [使用HtmlAgilityPack在网站中检测RSS和Atom订阅源的简单方法](http://runtingsproper.blogspot.co.uk/2012/07/a-straightforward-method-to-detecting.html) - rtpHarry
3
最近在_Code Project_ 上发布了一篇关于 HTMLAgilityPack 的优秀文章。您可以在这里阅读。 - Victor Sigler

67

HtmlAgilityPack使用XPath语法,虽然很多人认为它文档不够好,但在这个XPath文档的帮助下,我没有遇到任何问题:https://www.w3schools.com/xml/xpath_syntax.asp

解析:

<h2>
  <a href="">Jack</a>
</h2>
<ul>
  <li class="tel">
    <a href="">81 75 53 60</a>
  </li>
</ul>
<h2>
  <a href="">Roy</a>
</h2>
<ul>
  <li class="tel">
    <a href="">44 52 16 87</a>
  </li>
</ul>

我做了这件事:

string url = "http://website.com";
var Webget = new HtmlWeb();
var doc = Webget.Load(url);
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//h2//a"))
{
  names.Add(node.ChildNodes[0].InnerHtml);
}
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//li[@class='tel']//a"))
{
  phones.Add(node.ChildNodes[0].InnerHtml);
}

完全正确。它完全依赖于XPath标准。一个人应该先学习这个标准,然后一切都会变得容易。 - FindOut_Quran
您提供的链接已不再可用。这可能是新链接:http://www.w3schools.com/xsl/xpath_syntax.asp - Piotrek
同时我在 DocumentNode 对象中找不到 SelectNodes() 函数。它被重命名了吗? - Piotrek
你使用的是哪个版本,从哪里下载的?根据http://htmlagilitypack.codeplex.com/SourceControl/latest#Release/1_4_0/HtmlAgilityPack/HtmlNode.cs,HtmlNode类应该有一个SelectNodes方法。 - Kent Munthe Caspersen
链接不可用,新链接:www.w3schools.com/xml/xpath_syntax.asp - Tyrmos
感谢 @Tyrmos,我已添加了你的链接。 - Kent Munthe Caspersen

6
主要的 HTMLAgilityPack 相关代码如下:
using System;
using System.Net;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;
using System.Text.RegularExpressions;
using HtmlAgilityPack;

namespace GetMetaData
{
    /// <summary>
    /// Summary description for MetaDataWebService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    [System.Web.Script.Services.ScriptService]
    public class MetaDataWebService: System.Web.Services.WebService
    {
        [WebMethod]
        [ScriptMethod(UseHttpGet = false)]
        public MetaData GetMetaData(string url)
        {
            MetaData objMetaData = new MetaData();

            //Get Title
            WebClient client = new WebClient();
            string sourceUrl = client.DownloadString(url);

            objMetaData.PageTitle = Regex.Match(sourceUrl, @
            "\<title\b[^>]*\>\s*(?<Title>[\s\S]*?)\</title\>", RegexOptions.IgnoreCase).Groups["Title"].Value;

            //Method to get Meta Tags
            objMetaData.MetaDescription = GetMetaDescription(url);
            return objMetaData;
        }

        private string GetMetaDescription(string url)
        {
            string description = string.Empty;

            //Get Meta Tags
            var webGet = new HtmlWeb();
            var document = webGet.Load(url);
            var metaTags = document.DocumentNode.SelectNodes("//meta");

            if (metaTags != null)
            {
                foreach(var tag in metaTags)
                {
                    if (tag.Attributes["name"] != null && tag.Attributes["content"] != null && tag.Attributes["name"].Value.ToLower() == "description")
                    {
                        description = tag.Attributes["content"].Value;
                    }
                }
            } 
            else
            {
                description = string.Empty;
            }
            return description;
        }
    }
}

4
网站已不再可用。 - Dimitar Tsonev

5
    public string HtmlAgi(string url, string key)
    {

        var Webget = new HtmlWeb();
        var doc = Webget.Load(url);
        HtmlNode ourNode = doc.DocumentNode.SelectSingleNode(string.Format("//meta[@name='{0}']", key));

        if (ourNode != null)
        {


                return ourNode.GetAttributeValue("content", "");

        }
        else
        {
            return "not fount";
        }

    }

0

入门 - HTML Agility Pack

// From File
var doc = new HtmlDocument();
doc.Load(filePath);

// From String
var doc = new HtmlDocument();
doc.LoadHtml(html);

// From Web
var url = "http://html-agility-pack.net/";
var web = new HtmlWeb();
var doc = web.Load(url);

0

试一下这个

string htmlBody = ParseHmlBody(dtViewDetails.Rows[0]["Body"].ToString());

private string ParseHmlBody(string html)
        {
            string body = string.Empty;
            try
            {
                var htmlDoc = new HtmlDocument();
                htmlDoc.LoadHtml(html);
                var htmlBody = htmlDoc.DocumentNode.SelectSingleNode("//body");
                body = htmlBody.OuterHtml;
            }
            catch (Exception ex)
            {

                dalPendingOrders.LogMessage("Error in ParseHmlBody" + ex.Message);
            }
            return body;
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接