Como usar o pacote HTML Agility

629

Como uso o HTML Agility Pack ?

Meu documento XHTML não é totalmente válido. É por isso que eu queria usá-lo. Como eu o uso no meu projeto? Meu projeto está em c #.

carla
fonte
79
Esta pergunta foi muito útil para mim.
BigJoe714
26
Nota: com um Visual Studio que lida com o NuGet, agora você pode clicar com o botão direito do mouse em "Referências" e escolher "Gerenciar pacotes NuGet ...", pesquise "HtmlAgilityPack" e clique em "Instalar". Em seguida, comece a jogar com o código com uma instrução using / Import.
28411 patridge
Com relação ao comentário acima de @patridge: descobri que precisava remover e adicionar novamente minha referência ao HtmlAgilityPack ao buscar o projeto pela primeira vez em svn via ankhsvn.
Andrew Coonce
14
Qualquer pessoa que procure o HTMLAgilityPack deve considerar o CsQuery, é uma biblioteca muito mais nova com uma interface muito mais moderna da minha experiência. Por exemplo, o código inteiro da primeira resposta pode ser resumido no CsQuery como var body = CQ.CreateFromFile(filePath)["body"].
Benjamin Gruenbaum 01/01
2
@BenjaminGruenbaum: perfeito para a sua sugestão CsQuery - configurada em minutos, muito fácil de usar.
Neolisk

Respostas:

358

Primeiro, instale o pacote de nuget HTMLAgilityPack no seu projeto.

Então, como um exemplo:

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 é apenas um exemplo e não necessariamente a melhor / única abordagem. Não o use cegamente em seu próprio aplicativo.)

O HtmlDocument.Load()método também aceita um fluxo que é muito útil na integração com outras classes orientadas a fluxo na estrutura .NET. While HtmlEntity.DeEntitize()é outro método útil para processar corretamente entidades html. (obrigado Matthew)

HtmlDocumente HtmlNode são as classes que você mais usará. Semelhante a um analisador XML, ele fornece os métodos selectSingleNode e selectNodes que aceitam expressões XPath.

Preste atenção às HtmlDocument.Option?????? propriedades booleanas. Eles controlam como os métodos Loade LoadXMLirão processar seu HTML / XHTML.

Há também um arquivo de ajuda compilado chamado HtmlAgilityPack.chm que possui uma referência completa para cada um dos objetos. Normalmente, isso está na pasta base da solução.

Cinza
fonte
11
Observe também que o Load aceita um parâmetro Stream, o que é conveniente em muitas situações. Eu usei para um fluxo HTTP (WebResponse.GetResponseStream). Outro bom método para conhecer é o HtmlEntity.DeEntitize (parte do HTML Agility Pack). Isso é necessário para processar entidades manualmente em alguns casos.
Matthew Flaschen
1
nota: na versão beta mais recente do Html Agility Pack (1.4.0 Beta 2 lançado em 3 de outubro de 2009), o arquivo de ajuda foi transferido para um download separado devido às dependências do Sandcastle, DocProject e Visual Studio 2008 SDK.
precisa saber é o seguinte
SelectSingleNode() parece ter sido removido há um tempo atrás
Chris S
3
Não, SelectSingleNode e SelectNodes definitivamente ainda estão lá. Acho que é um pouco interessante que ele deve ser htmlDoc.ParseErrors.Count (), não. Count
Mike Blandford
1
@MikeBlandford // Parcialmente sim. Parece ter sido removido (ou não existia desde o início) na versão PCL do HtmlAgailityPack. nuget.org/packages/HtmlAgilityPack-PCL
Joon Hong
166

Não sei se isso ajudará você, mas escrevi alguns artigos que apresentam o básico.

O próximo artigo está 95% completo, basta escrever explicações das últimas partes do código que escrevi. Se você estiver interessado, tentarei me lembrar de postar aqui quando publicá-lo.

rtpHarry
fonte
16
Finalmente terminou esse artigo dois anos mais tarde :) Um método simples para detectar feeds RSS e Atom em sites com HtmlAgilityPack
rtpHarry
3
Recentemente, no Code Project , foi lançado um artigo muito bom do HTMLAgilityPack. Você pode lê-lo aqui #
Victor Sigler
64

O HtmlAgilityPack usa a sintaxe XPath e, embora muitos argumentem que está mal documentado, não tive problemas em usá-lo com a ajuda desta documentação do XPath: https://www.w3schools.com/xml/xpath_syntax.asp

Para analisar

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

Eu fiz isso:

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
fonte
Completamente verdade. É totalmente dependente do XPathpadrão. Deve-se primeiro aprender esse padrão e tudo será fácil depois disso.
FindOut_Quran
O link que você forneceu não está mais disponível. Este é provavelmente o novo: w3schools.com/xsl/xpath_syntax.asp
Piotrek
Também não consigo ver nenhuma função SelectNodes () no objeto DocumentNode. É renomeado?
Piotrek
Qual versão você está usando e de onde baixou? De acordo com htmlagilitypack.codeplex.com/SourceControl/latest#Release/1_4_0/… , deve haver um método SelectNodes na classe HtmlNode.
Kent Munthe Caspersen
Fazer a ligação não estiver disponível, novo link: www.w3schools.com/xml/xpath_syntax.asp
Tyrmos
6

O principal código relacionado ao HTMLAgilityPack é o seguinte

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
fonte
4
O site não está mais disponível #
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
fonte
0

Introdução - 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);
Meysam
fonte
0

tente isso

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
fonte