Obtener código HTML del sitio web en C #


87

¿Cómo obtener el código HTML de un sitio web, guardarlo y encontrar texto mediante una expresión LINQ?

Estoy usando el siguiente código para obtener la fuente de una página 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;
 }

¿Cómo encuentro el texto en un div en la fuente de la página web?


Depende de lo inteligente que deba ser la búsqueda. Una simple Containsllamada podría ser "suficientemente buena".
cenizas999

5
Considere usar HTMLAgility pack, Fizzler o CSQuery para obtener el div / text una vez que tenga el HTML, cualquier otra cosa es demasiado propensa a errores.
jammykam


@GeorgeDuckett Eso no parece un duplicado de esta pregunta, la pregunta a la que enlaza es solo sobre la recuperación de la fuente, esta pregunta también se trata de consultar el DOM.
Mark Rotteveel

@Mark: Lo siento, tienes razón, me perdí el texto en la parte inferior.
George Duckett

Respuestas:


112

Obtener código HTML de un sitio web. Puedes usar un 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();
}

Esto le dará el código HTML devuelto del sitio web. Pero encontrar texto a través de LINQ no es tan fácil. Quizás sea mejor usar expresiones regulares, pero eso no funciona bien con el código HTML


4
La idea de utilizar expresiones regulares para HTML o XML es muy mala práctica de codificación ... El ir en su manera - que deberíamos usar la palabra clave en todas partes ... Goto
Lightning3

En realidad, usar expresiones regulares para buscar algo preciso dentro del código HTML puede ser una solución muy decente. Intentar construir un analizador / intérprete HTML basado en expresiones regulares, por otro lado, sería una locura. Todo depende del contexto y de la tarea real que deba realizarse, pero decir que "la expresión regular nunca funciona bien con HTML" simplemente no es una verdad global e inalcanzable. stackoverflow.com/a/1733489/6838730
Mathieu VIALES

177

Mejor puede usar la clase Webclient para simplificar su tarea:

using System.Net;

using (WebClient client = new WebClient())
{
    string htmlCode = client.DownloadString("http://somesite.com/default.html");
}

¿Alguna idea de por qué recibo este error? 'System.Net.WebClient': el tipo utilizado en una declaración de uso debe ser implícitamente convertible a 'System.IDisposable'
Dave Chandler

9
Para el usingrequisito Se muestra claramente para que todos lo usen: +1
user3916429

37

Lo mejor para usar es HTMLAgilityPack . También puede considerar el uso de Fizzler o CSQuery según sus necesidades para seleccionar los elementos de la página recuperada. El uso de LINQ o Regukar Expressions es propenso a errores, especialmente cuando el HTML puede estar mal formado, faltar etiquetas de cierre, tener elementos secundarios anidados, etc.

Debe transmitir la página a un objeto HtmlDocument y luego seleccionar el elemento requerido.

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

[EDITAR] En realidad, elimine eso. El método más simple es usar FizzlerEx , una implementación actualizada de jQuery / CSS3-selectors del proyecto Fizzler original.

Muestra de código directamente desde su sitio:

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

No creo que pueda ser más simple que eso.


¿Qué pasa si quiero invocar un botón específico en la página web? @jammykam
Jamshaid Kamran

1
No puede hacer eso con un raspador de pantalla afaik, tendría que usar algo como Selenium para invocar el botón.
jammykam

¿Cómo instalas FizzlerEx? Reviso el enlace y hay un .zip pero no veo ningún instalador
Juan Carlos Oropeza

5

Estoy usando AngleSharp y estoy muy satisfecho con él.

A continuación, se muestra un ejemplo simple de cómo obtener una página:

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

Y ahora tienes una página web en variable de documento . Entonces puede acceder fácilmente a él mediante LINQ u otros métodos. Por ejemplo, si desea obtener un valor de cadena de una tabla 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 utilizar selectores CSS, consulte los ejemplos de AngleSharp .


5

A continuación, se muestra un ejemplo del uso de la HttpWebRequestclase para obtener una 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(); 
} 

2
debe agregar código en su respuesta en lugar de una imagen.
AJ

2

Puede utilizar WebClient para descargar el html de cualquier URL. Una vez que tenga el html, puede usar una biblioteca de terceros como HtmlAgilityPack para buscar valores en el html como en el siguiente código:

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

1

Prueba esta solución. Funciona bien.

 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);
        }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.