Obtenha o código HTML do site em C #

87

Como obter o código HTML de um site, salvá-lo e localizar algum texto por uma expressão LINQ?

Estou usando o seguinte código para obter o código-fonte de uma página da web:

public static String code(string Url)
{
    HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(Url);
    myRequest.Method = "GET";
    WebResponse myResponse = myRequest.GetResponse();
    StreamReader sr = new StreamReader(myResponse.GetResponseStream(), System.Text.Encoding.UTF8);
    string result = sr.ReadToEnd();
    sr.Close();
    myResponse.Close();

    return result;
 }

Como encontro o texto em uma div na fonte da página da web?

ggcodes
fonte
Depende de como a pesquisa inteligente deve ser. Uma simples Containsligação pode ser "boa o suficiente".
ashes999 de
5
Procure usar o pacote HTMLAgility, Fizzler ou CSQuery para obter o div / texto, uma vez que você tenha o HTML, qualquer outra coisa está muito sujeita a erros.
jammykam de
possível duplicata de Como posso baixar o código-fonte HTML em C #
George Duckett
@GeorgeDuckett Isso não parece uma duplicata desta pergunta, a pergunta para a qual você vincula é apenas sobre como recuperar a fonte, esta pergunta também é sobre consultar o DOM.
Mark Rotteveel
@Mark: Desculpe, você está certo, perdi o texto na parte inferior.
George Duckett

Respostas:

112

Obtendo o código HTML de um site. Você pode usar um código como este.

string urlAddress = "http://google.com";

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlAddress);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

if (response.StatusCode == HttpStatusCode.OK)
{
  Stream receiveStream = response.GetResponseStream();
  StreamReader readStream = null;

  if (String.IsNullOrWhiteSpace(response.CharacterSet))
     readStream = new StreamReader(receiveStream);
  else
     readStream = new StreamReader(receiveStream, Encoding.GetEncoding(response.CharacterSet));

  string data = readStream.ReadToEnd();

  response.Close();
  readStream.Close();
}

Isso fornecerá o código HTML retornado do site. Mas localizar texto via LINQ não é tão fácil. Talvez seja melhor usar uma expressão regular, mas isso não funciona bem com o código HTML

Erro de sintaxe
fonte
4
A ideia de usar regex para html ou XML é uma prática de codificação MUITO ruim ... Indo no seu caminho - devemos usar a palavra-chave goto em todos os lugares ...
Lightning3
Na verdade, usar regex para pesquisar algo preciso no código HTML pode ser uma solução muito decente. Tentar construir um analisador / interpretador HTML baseado em regex, por outro lado, seria pura loucura. Tudo depende do contexto e da tarefa real que precisa ser executada, mas dizer que "regex nunca funciona bem com HTML" simplesmente não é uma verdade global e inalinável. stackoverflow.com/a/1733489/6838730
Mathieu VIALES
177

Melhor você pode usar a classe Webclient para simplificar sua tarefa:

using System.Net;

using (WebClient client = new WebClient())
{
    string htmlCode = client.DownloadString("http://somesite.com/default.html");
}
Santosh Panda
fonte
Alguma ideia de por que recebo esse erro? 'System.Net.WebClient': o tipo usado em uma instrução de uso deve ser implicitamente conversível em 'System.IDisposable'
Dave Chandler
9
Para o usingrequisito mostrado claramente para que todos possam usar: +1
user3916429
37

A melhor coisa a se usar é HTMLAgilityPack . Você também pode usar Fizzler ou CSQuery, dependendo de suas necessidades para selecionar os elementos da página recuperada. Usar LINQ ou Expressões Regukar está sujeito a erros, especialmente quando o HTML pode ser malformado, tags de fechamento ausentes, elementos filho aninhados etc.

Você precisa transmitir a página para um objeto HtmlDocument e, em seguida, selecionar o elemento necessário.

// Call the page and get the generated HTML
var doc = new HtmlAgilityPack.HtmlDocument();
HtmlAgilityPack.HtmlNode.ElementsFlags["br"] = HtmlAgilityPack.HtmlElementFlag.Empty;
doc.OptionWriteEmptyNodes = true;

try
{
    var webRequest = HttpWebRequest.Create(pageUrl);
    Stream stream = webRequest.GetResponse().GetResponseStream();
    doc.Load(stream);
    stream.Close();
}
catch (System.UriFormatException uex)
{
    Log.Fatal("There was an error in the format of the url: " + itemUrl, uex);
    throw;
}
catch (System.Net.WebException wex)
{
    Log.Fatal("There was an error connecting to the url: " + itemUrl, wex);
    throw;
}

//get the div by id and then get the inner text 
string testDivSelector = "//div[@id='test']";
var divString = doc.DocumentNode.SelectSingleNode(testDivSelector).InnerHtml.ToString();

[EDIT] Na verdade, descarte isso. O método mais simples é usar FizzlerEx , uma implementação atualizada de seletores jQuery / CSS3 do projeto Fizzler original.

Amostra de código diretamente de seu site:

using HtmlAgilityPack;
using Fizzler.Systems.HtmlAgilityPack;

//get the page
var web = new HtmlWeb();
var document = web.Load("http://example.com/page.html");
var page = document.DocumentNode;

//loop through all div tags with item css class
foreach(var item in page.QuerySelectorAll("div.item"))
{
    var title = item.QuerySelector("h3:not(.share)").InnerText;
    var date = DateTime.Parse(item.QuerySelector("span:eq(2)").InnerText);
    var description = item.QuerySelector("span:has(b)").InnerHtml;
}

Não acho que possa ser mais simples do que isso.

Jammykam
fonte
E se eu quiser invocar um botão específico na página da web? @jammykam
Jamshaid Kamran
1
Você não pode fazer isso com um raspador de tela afaik, você teria que usar qualquer coisa como Selenium para invocar o botão.
jammykam de
Como você instala o FizzlerEx? Verifico o link e há um .zip mas não vejo nenhum instalador
Juan Carlos Oropeza
5

Estou usando o AngleSharp e estou muito satisfeito com ele.

Aqui está um exemplo simples de como buscar uma página:

var config = Configuration.Default.WithDefaultLoader();
var document = await BrowsingContext.New(config).OpenAsync("https://www.google.com");

E agora você tem uma página da web na variável de documento . Em seguida, você pode acessá-lo facilmente por LINQ ou outros métodos. Por exemplo, se você deseja obter um valor de string de uma tabela HTML:

var someStringValue = document.All.Where(m =>
        m.LocalName == "td" &&
        m.HasAttribute("class") &&
        m.GetAttribute("class").Contains("pid-1-bid")
    ).ElementAt(0).TextContent.ToString();

Para usar seletores CSS, consulte os exemplos do AngleSharp .

Tickseeker
fonte
5

Aqui está um exemplo de como usar a HttpWebRequestclasse para buscar um URL

private void buttonl_Click(object sender, EventArgs e) 
{ 
    String url = TextBox_url.Text;
    HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url); 
    HttpWebResponse response = (HttpWebResponse) request.GetResponse(); 
    StreamReader sr = new StreamReader(response.GetResponseStream()); 
    richTextBox1.Text = sr.ReadToEnd(); 
    sr.Close(); 
} 
Mohamed Sayed
fonte
2
você deve adicionar código em sua resposta em vez de uma imagem.
AJ de
2

Você pode usar o WebClient para baixar o html para qualquer url. Depois de ter o html, você pode usar uma biblioteca de terceiros como HtmlAgilityPack para pesquisar valores no html como no código abaixo -

public static string GetInnerHtmlFromDiv(string url)
    {
        string HTML;
        using (var wc = new WebClient())
        {
            HTML = wc.DownloadString(url);
        }
        var doc = new HtmlAgilityPack.HtmlDocument();
        doc.LoadHtml(HTML);
        
        HtmlNode element = doc.DocumentNode.SelectSingleNode("//div[@id='<div id here>']");
        if (element != null)
        {
            return element.InnerHtml.ToString();
        }   
        return null;            
    }
Ghanendra Singh
fonte
1

Experimente esta solução. Funciona bem.

 try{
        String url = textBox1.Text;
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        StreamReader sr = new StreamReader(response.GetResponseStream());
        HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
        doc.Load(sr);
        var aTags = doc.DocumentNode.SelectNodes("//a");
        int counter = 1;
        if (aTags != null)
        {
            foreach (var aTag in aTags)
            {
                richTextBox1.Text +=  aTag.InnerHtml +  "\n" ;
                counter++;
            }
        }
        sr.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show("Failed to retrieve related keywords." + ex);
        }
youssef
fonte