Ottieni codice HTML dal sito Web in C #


89

Come ottenere il codice HTML da un sito Web, salvarlo e trovare del testo tramite un'espressione LINQ?

Sto usando il codice seguente per ottenere l'origine di una pagina 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;
 }

Come trovo il testo in un div nel codice sorgente della pagina web?


Dipende da quanto dovrebbe essere la ricerca intelligente. Una semplice Containschiamata potrebbe essere "abbastanza buona".
ceneri999

5
Cerca di utilizzare HTMLAgility pack, Fizzler o CSQuery per ottenere il div / text una volta che hai l'HTML, qualsiasi altra cosa è troppo soggetta a errori.
jammykam


@GeorgeDuckett Non sembra un duplicato di questa domanda, la domanda a cui ti colleghi riguarda solo il recupero della fonte, questa domanda riguarda anche l'interrogazione del DOM.
Mark Rotteveel

@Mark: Scusa hai ragione, ho perso il testo in fondo.
George Duckett

Risposte:


113

Recupero del codice HTML da un sito web. Puoi usare un codice come questo.

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

Questo ti darà il codice HTML restituito dal sito web. Ma trovare testo tramite LINQ non è così facile. Forse è meglio usare l'espressione regolare, ma questo non funziona bene con il codice HTML


4
L'idea di usare regex per html o XML è MOLTO pessima pratica di codifica ... Going in Your Way - dovremmo usare la parola chiave goto ovunque ...
Lightning3

1
In realtà, l'utilizzo di espressioni regolari per cercare una cosa precisa all'interno del codice HTML può essere una soluzione molto decente. Il tentativo di costruire un parser / interprete HTML basato su regex, d'altra parte, sarebbe pura follia. Tutto dipende dal contesto e dall'effettiva attività che deve essere eseguita, ma dire che "le espressioni regolari non funzionano mai bene con l'HTML" semplicemente non è una verità globale e inalinabile. stackoverflow.com/a/1733489/6838730
Mathieu VIALES

183

Meglio puoi usare la classe Webclient per semplificare il tuo compito:

using System.Net;

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

Qualche idea sul perché ricevo questo errore? 'System.Net.WebClient': il tipo utilizzato in un'istruzione using deve essere convertibile in modo implicito in 'System.IDisposable'
Dave Chandler

10
Per il usingrequisito chiaramente mostrato a tutti da utilizzare: +1
user3916429

Per coloro che ricevono un errore http 403, aggiungi client.Headers.Add ("user-agent", "Fiddler"); Sostituisci Fiddler con il testo che desideri.
Himanshu Patel

37

La cosa migliore da usare è HTMLAgilityPack . Puoi anche esaminare l'utilizzo di Fizzler o CSQuery a seconda delle tue esigenze per selezionare gli elementi dalla pagina recuperata. L'uso di LINQ o Regukar Expressions è soggetto a errori, soprattutto quando l'HTML può essere malformato, tag di chiusura mancanti, elementi figlio nidificati ecc.

È necessario eseguire lo streaming della pagina in un oggetto HtmlDocument e quindi selezionare l'elemento richiesto.

// 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] In realtà, scarta quello. Il metodo più semplice è usare FizzlerEx , un'implementazione aggiornata dei selettori jQuery / CSS3 del progetto Fizzler originale.

Esempio di codice direttamente dal loro sito:

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

Non credo che possa essere più semplice di così.


E se volessi richiamare un pulsante specifico sulla pagina web? @jammykam
Jamshaid K.

1
Non puoi farlo con un raschietto per schermi afaik, dovresti usare qualcosa come Selenium per richiamare il pulsante.
jammykam

Come installi FizzlerEx? Controllo il collegamento e c'è un file .zip ma non vedo alcun programma di installazione
Juan Carlos Oropeza

6

Sto usando AngleSharp e ne sono rimasto molto soddisfatto.

Ecco un semplice esempio di come recuperare una pagina:

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

E ora hai una pagina web nella variabile del documento . Quindi puoi accedervi facilmente tramite LINQ o altri metodi. Ad esempio, se desideri ottenere un valore stringa da una tabella HTML:

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

Per utilizzare i selettori CSS, vedere gli esempi di AngleSharp .


5

Ecco un esempio di utilizzo della HttpWebRequestclasse per recuperare un 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
dovresti aggiungere il codice nella tua risposta invece di un'immagine.
AJ

2

Puoi usare WebClient per scaricare l'html per qualsiasi URL. Una volta che hai l'html, puoi utilizzare una libreria di terze parti come HtmlAgilityPack per cercare i valori nell'html come nel codice seguente -

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

Prova questa soluzione. Funziona bene.

 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);
        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.