Cómo usar el paquete de agilidad HTML

629

¿Cómo uso el paquete de agilidad HTML ?

Mi documento XHTML no es completamente válido. Por eso quería usarlo. ¿Cómo lo uso en mi proyecto? Mi proyecto está en C #.

carla
fuente
79
Esta pregunta fue muy útil para mí.
BigJoe714
26
Nota al margen: con un Visual Studio que maneja NuGet, ahora puede hacer clic derecho en "Referencias" y elegir "Administrar paquetes NuGet ...", buscar "HtmlAgilityPack" y hacer clic en "Instalar". Luego, comienza a jugar con el código con una instrucción using / Import.
patridge
Con respecto al comentario anterior de @patridge: descubrí que necesitaba eliminar y luego volver a agregar mi referencia al HtmlAgilityPack cuando obtuve el proyecto desde svn a través de ankhsvn.
Andrew Coonce
14
Cualquier persona que busque en HTMLAgilityPack debería considerar CsQuery, es una biblioteca mucho más nueva con una interfaz mucho más moderna desde mi experiencia. Por ejemplo, todo el código de la primera respuesta se puede resumir en CsQuery como var body = CQ.CreateFromFile(filePath)["body"].
Benjamin Gruenbaum
2
@BenjaminGruenbaum: aprobado por su sugerencia de CsQuery, configurado en minutos, muy fácil de usar.
Neolisco

Respuestas:

358

Primero, instale el paquete nuget HTMLAgilityPack en su proyecto.

Entonces, como ejemplo:

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

(Nota: este código es solo un ejemplo y no necesariamente el mejor / único enfoque. No lo use a ciegas en su propia aplicación).

El HtmlDocument.Load()método también acepta una secuencia que es muy útil para integrarse con otras clases orientadas a la secuencia en el marco .NET. Mientras que HtmlEntity.DeEntitize()es otro método útil para procesar entidades html correctamente. (gracias Matthew)

HtmlDocumenty HtmlNode son las clases que usarás más. Similar a un analizador XML, proporciona los métodos selectSingleNode y selectNodes que aceptan expresiones XPath.

Presta atención a las HtmlDocument.Option?????? propiedades booleanas. Estos cómo el control de Loady LoadXMLmétodos de procesar la HTML / XHTML.

También hay un archivo de ayuda compilado llamado HtmlAgilityPack.chm que tiene una referencia completa para cada uno de los objetos. Esto normalmente está en la carpeta base de la solución.

Ceniza
fuente
11
También tenga en cuenta que Load acepta un parámetro Stream, que es conveniente en muchas situaciones. Lo usé para una secuencia HTTP (WebResponse.GetResponseStream). Otro buen método para tener en cuenta es HtmlEntity.DeEntitize (parte del paquete de agilidad HTML). Esto es necesario para procesar entidades manualmente en algunos casos.
Matthew Flaschen
1
nota: en la última versión beta de Html Agility Pack (1.4.0 Beta 2 lanzada el 3 de octubre de 2009), el archivo de ayuda se ha movido a una descarga separada debido a las dependencias de Sandcastle, DocProject y Visual Studio 2008 SDK.
rtpHarry
SelectSingleNode() parece haber sido eliminado hace un tiempo
Chris S
3
No, SelectSingleNode y SelectNodes definitivamente siguen ahí. Me parece un poco interesante que debería ser htmlDoc.ParseErrors.Count (), no .Count
Mike Blandford
1
@MikeBlandford // Parcialmente sí. Parece que se eliminó (o no existió desde el principio) en la versión PCL de HtmlAgailityPack. nuget.org/packages/HtmlAgilityPack-PCL
Joon Hong
166

No sé si esto será de alguna ayuda para usted, pero he escrito un par de artículos que presentan los conceptos básicos.

El siguiente artículo está completo en un 95%, solo tengo que escribir explicaciones de las últimas partes del código que he escrito. Si está interesado, intentaré recordar publicar aquí cuando lo publique.

rtpHarry
fuente
16
Finalmente terminé ese artículo dos años después :) Un método sencillo para detectar fuentes RSS y Atom en sitios web con HtmlAgilityPack
rtpHarry
3
Recientemente en Code Project se ha lanzado un muy buen artículo de HTMLAgilityPack. Puedes leerlo aquí
Victor Sigler
64

HtmlAgilityPack usa la sintaxis XPath, y aunque muchos argumentan que está mal documentado, no tuve problemas para usarlo con la ayuda de esta documentación de XPath: https://www.w3schools.com/xml/xpath_syntax.asp

Analizar

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

Hice esto:

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);
}
Kent Munthe Caspersen
fuente
Totalmente cierto. Es totalmente dependiente del XPathestándar. Primero se debe aprender ese estándar y todo será fácil después de eso.
FindOut_Quran
El enlace que proporcionó ya no está disponible. Este es probablemente el nuevo: w3schools.com/xsl/xpath_syntax.asp
Piotrek
Tampoco puedo ver ninguna función SelectNodes () en el objeto DocumentNode. ¿Se renombró?
Piotrek
¿Qué versión estás usando y de dónde la descargaste? De acuerdo con htmlagilitypack.codeplex.com/SourceControl/latest#Release/1_4_0/… debería haber un método SelectNodes en la clase HtmlNode.
Kent Munthe Caspersen
Enlace no disponible, nuevo enlace: www.w3schools.com/xml/xpath_syntax.asp
Tyrmos
6

El código principal relacionado con HTMLAgilityPack es el siguiente

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;
        }
    }
}
captainsac
fuente
44
El sitio web ya no está disponible
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";
        }

    }
ibrahim ozboluk
fuente
0

Primeros pasos: paquete de agilidad HTML

// 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);
Meysam
fuente
0

prueba esto

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;
        }
PK-1825
fuente