Pobierz kod HTML ze strony internetowej w C #

87

Jak pobrać kod HTML ze strony internetowej, zapisać go i znaleźć tekst za pomocą wyrażenia LINQ?

Używam następującego kodu, aby pobrać źródło strony internetowej:

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

Jak znaleźć tekst w div w źródle strony internetowej?

ggcodes
źródło
Zależy, jak powinno być inteligentne wyszukiwanie. Proste Containswezwanie może być „wystarczająco dobre”.
popiół 999
5
Spróbuj użyć pakietu HTMLAgility, Fizzler lub CSQuery do pobrania div / text, gdy masz już HTML, wszystko inne jest zbyt podatne na błędy.
jammykam
możliwy duplikat Jak mogę pobrać źródło HTML w C #
George Duckett
@GeorgeDuckett To nie wygląda na duplikat tego pytania, pytanie, do którego linkujesz, dotyczy tylko pobrania źródła, to pytanie dotyczy również odpytywania DOM.
Mark Rotteveel
@Mark: Przepraszam, masz całkowitą rację, przegapiłeś tekst na dole.
George Duckett

Odpowiedzi:

112

Pobieranie kodu HTML ze strony internetowej. Możesz użyć takiego kodu.

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

W ten sposób otrzymasz kod HTML zwrócony ze strony internetowej. Ale znajdowanie tekstu za pośrednictwem LINQ nie jest takie proste. Być może lepiej jest użyć wyrażenia regularnego, ale to nie działa dobrze z kodem HTML

Błąd składni
źródło
4
Pomysł użycia wyrażenia regularnego dla html lub XML jest BARDZO złą praktyką w kodowaniu ... Idziemy po drodze - wszędzie powinniśmy używać słowa kluczowego goto ...
Lightning3
W rzeczywistości użycie wyrażenia regularnego do wyszukiwania konkretnych elementów w kodzie HTML może być bardzo przyzwoitym rozwiązaniem. Z drugiej strony próba zbudowania parsera / interpretatora HTML w oparciu o regex byłaby czystym szaleństwem. Wszystko zależy od kontekstu i rzeczywistego zadania, które należy wykonać, ale stwierdzenie, że „regex nigdy nie działa dobrze z HTML” po prostu nie jest globalną, niemożliwą do przecenienia prawdą. stackoverflow.com/a/1733489/6838730
Mathieu VIALES
177

Lepiej możesz użyć klasy Webclient, aby uprościć swoje zadanie:

using System.Net;

using (WebClient client = new WebClient())
{
    string htmlCode = client.DownloadString("http://somesite.com/default.html");
}
Santosh Panda
źródło
Masz jakiś pomysł, dlaczego otrzymuję ten błąd? „System.Net.WebClient”: typ używany w instrukcji using musi być niejawnie konwertowany na „System.IDisposable”
Dave Chandler
9
Dla usingwymogu wyraźnie widoczne dla każdego do użytku: +1
user3916429
37

Najlepszą rzeczą do użycia jest HTMLAgilityPack . Możesz również przyjrzeć się użyciu Fizzlera lub CSQuery w zależności od potrzeb w zakresie wybierania elementów z pobranej strony. Używanie wyrażeń LINQ lub Regukar jest po prostu podatne na błędy, zwłaszcza gdy HTML może być zniekształcony, brakuje tagów zamykających, ma zagnieżdżone elementy podrzędne itp.

Musisz przesłać strumieniowo stronę do obiektu HtmlDocument, a następnie wybrać wymagany element.

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

[EDYCJA] Właściwie, wyrzuć to. Najprostszą metodą jest użycie FizzlerEx , zaktualizowanej implementacji selektorów jQuery / CSS3 z oryginalnego projektu Fizzlera.

Przykład kodu bezpośrednio z ich witryny:

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

Nie sądzę, żeby było to prostsze.

jammykam
źródło
A jeśli chcę wywołać określony przycisk na stronie internetowej? @jammykam
Jamshaid Kamran
1
Nie możesz tego zrobić za pomocą skrobaka do ekranu afaik, musiałbyś użyć czegoś takiego jak Selenium, aby wywołać przycisk.
jammykam
Jak zainstalować FizzlerEx? Sprawdzam link i jest .zip, ale nie widzę żadnego instalatora
Juan Carlos Oropeza
5

Używam AngleSharp i jestem z niego bardzo zadowolony.

Oto prosty przykład, jak pobrać stronę:

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

A teraz masz stronę internetową w zmiennej dokumentu . Następnie możesz łatwo uzyskać do niego dostęp za pomocą LINQ lub innych metod. Na przykład, jeśli chcesz pobrać wartość ciągu z tabeli HTML:

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

Aby użyć selektorów CSS, zobacz przykłady AngleSharp .

Tickseeker
źródło
5

Oto przykład użycia HttpWebRequestklasy do pobrania adresu 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
źródło
2
powinieneś dodać kod w swojej odpowiedzi zamiast obrazka.
AJ
2

Możesz użyć WebClient, aby pobrać kod HTML dla dowolnego adresu URL. Gdy masz już kod HTML, możesz użyć biblioteki innej firmy, takiej jak HtmlAgilityPack, do wyszukiwania wartości w html, jak w poniższym kodzie -

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
źródło
1

Wypróbuj to rozwiązanie. To działa dobrze.

 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
źródło