Prawie w pełni funkcjonalna klasa do pobierania danych za pomocą protokołu HTTP
Anthony
Witam,
Ponieważ ostatnio zaciekawił mnie trochę C# (programuję głównie w VB.NET) - postanowiłem więc na początek przepisać na ten język klasę której używam często i gęsto do pobierania danych ze stron internetowych. Jest to to mój pierwszy tak duży kawałek kodu w C#, więc proszę o wyrozumiałość jeżeli chodzi o pewne jego aspekty. ;)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
public class PobierzDaneHTTPClass
{
private string _linkPobierania, _danePOST, _referer, _serwerProxy, _userAgent;
private bool _obslugaCiasteczek, _autoRedirect;
private int _timeout; //w milisekundach
private System.Text.Encoding _kodowanie;
private System.Net.NetworkCredential _autoryzacja;
private List<string> _magazynCiasteczek;
private WynikPobieraniaClass _wynikPobierania;
public string LinkPobierania
{
get { return _linkPobierania; }
set { _linkPobierania = value; }
}
public string DanePOST
{
get { return _danePOST; }
set { _danePOST = value; }
}
public string Referer
{
get { return _referer; }
set { _referer = value; }
}
/// <summary>Użycie serwera proxy.<para>Format: Host:Port</para><para>Przykład: jakies-proxy.pl:8080</para></summary>
public string SerwerProxy
{
get { return _serwerProxy; }
set { _serwerProxy = value; }
}
public string UserAgent
{
get { return _userAgent; }
set { _userAgent = value; }
}
public bool ObslugaCiasteczek
{
get { return _obslugaCiasteczek; }
set { _obslugaCiasteczek = value; }
}
/// <summary>Określa czy zezwolić i wykonać automatyczne przekierowania.</summary>
public bool AutoRedirect
{
get { return _autoRedirect; }
set { _autoRedirect = value; }
}
/// <summary>Czas w sekundach po jakim nastąpi rezygnacja z żądania.</summary>
public int Timeout
{
get { return _timeout / 1000; }
set { _timeout = value * 1000; }
}
/// <summary>Kodowanie znaków używane w żądaniach.<para>Domyślne: UTF-8</para></summary>
public string Kodowanie
{
get { return _kodowanie.EncodingName; }
set { _kodowanie = System.Text.Encoding.GetEncoding(value); }
}
public NetworkCredential Autoryzacja
{
get { return _autoryzacja; }
set { _autoryzacja = value; }
}
/// <summary>Magazyn przechowujący ciasteczka (cross-domain).<para>Format: nazwa=wartość</para><para>Przekazywane przez referencję.</para></summary>
public List<string> MagazynCiasteczek
{
get { return _magazynCiasteczek; }
set { _magazynCiasteczek = value; }
}
/// <summary>Magazyn przechowujący ciasteczka (cross-domain).<para>Format: nazwa=wartość</para><para>Uwaga: Przekazywana kopia obiektu, brak referencji!</para></summary>
public List<string> MagazynCiasteczek_NoRef
{
get { return new List<string>(_magazynCiasteczek); }
set { _magazynCiasteczek = new List<string>(value); ; }
}
public WynikPobieraniaClass Wynik
{
get { return _wynikPobierania; }
}
public PobierzDaneHTTPClass()
{
_userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 (.NET CLR 3.5.30729)";
_kodowanie = System.Text.Encoding.GetEncoding("UTF-8");
_wynikPobierania = new WynikPobieraniaClass();
_magazynCiasteczek = new List<string>();
_obslugaCiasteczek = false;
_autoRedirect = false;
_danePOST = null;
_referer = null;
_serwerProxy = null;
_autoryzacja = null;
_timeout = 0;
}
public void Pobierz(string LinkPobierania)
{
this.LinkPobierania = LinkPobierania;
this.Pobierz();
}
public void Pobierz()
{
System.Net.ServicePointManager.Expect100Continue = false;
try
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(_linkPobierania);
req.UserAgent = _userAgent;
req.AllowAutoRedirect = _autoRedirect;
req.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate"); //Zgłaszanie obsługi kompresji.
req.Headers.Add(HttpRequestHeader.AcceptLanguage, "pl,en-us;q=0.7,en;q=0.3");
req.Headers.Add(HttpRequestHeader.AcceptCharset, "UTF-8,ISO-8859-2;q=0.7,*;q=0.7");
req.ContentType = "application/x-www-form-urlencoded";
req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
if (_obslugaCiasteczek) { req.Headers.Add(HttpRequestHeader.Cookie, String.Join("; ", _magazynCiasteczek)); }
if (_timeout != 0) { req.Timeout = _timeout; }
if (_referer != null) { req.Referer = _referer; }
if (_autoryzacja != null) { req.Credentials = _autoryzacja; }
if (_serwerProxy != null)
{
string[] _daneProxy = _serwerProxy.Split(':');
req.Proxy = new System.Net.WebProxy(_daneProxy[0], Convert.ToInt32(_daneProxy[1]));
}
DateTime dataRozpoczecia = DateTime.Now;
if (_danePOST != null)
{ //Jeśli żądanie ma być wysłane metodą POST
byte[] bDanePOST = _kodowanie.GetBytes(_danePOST);
req.ContentLength = bDanePOST.Length;
req.Method = "POST";
req.GetRequestStream().Write(bDanePOST, 0, bDanePOST.Length);
req.GetRequestStream().Close();
}
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
_wynikPobierania.NaglowkiHTTP = res.Headers;
DateTime czasSerwera = DateTime.MinValue;
DateTime.TryParse(res.Headers[HttpResponseHeader.Date].ToString(), out czasSerwera);
_wynikPobierania.CzasSerwera = czasSerwera;
if (_obslugaCiasteczek && (res.Headers[HttpResponseHeader.SetCookie].ToString() != ""))
{ //Ręczna obsługa ciasteczek... bo .NET nie zawsze sobie radzi
// TODO: Kiedyś trzeba to zastąpić RegularExpressions
string[] tmpCiasteczka = res.Headers[HttpResponseHeader.SetCookie].ToString().Replace("Mon,", "#").Replace("Tue,", "#").Replace("Wed,", "#").Replace("Thu,", "#").Replace("Fri,", "#").Replace("Sat,", "#").Replace("Sun,", "#").Split(',');
List<string> nCiasteczka = new List<string>();
foreach (string tmpCiasteczko in tmpCiasteczka)
{
try
{
string nCiasteczko, nNazwa, nZawartosc;
nNazwa = tmpCiasteczko.Substring(0, tmpCiasteczko.IndexOf('='));
if (tmpCiasteczko.Contains(';'))
{
nZawartosc = tmpCiasteczko.Substring(0, tmpCiasteczko.IndexOf(";")).Substring(tmpCiasteczko.IndexOf("=") + 1);
}
else
{
nZawartosc = tmpCiasteczko.Substring(tmpCiasteczko.IndexOf("=") + 1);
}
nCiasteczko = nNazwa + "=" + nZawartosc;
if (_magazynCiasteczek.IndexOf(nCiasteczko) == -1) { _magazynCiasteczek.Add(nCiasteczko); }
if (nCiasteczka.IndexOf(nCiasteczko) == -1) { nCiasteczka.Add(nCiasteczko); }
}
catch (Exception) { } //Wyciszamy ewentualne błędy, to raczej mało ważne
}
_wynikPobierania.Ciasteczka = nCiasteczka;
_wynikPobierania.MagazynCiasteczek = _magazynCiasteczek;
}
string wynik;
StreamReader czytaj;
_wynikPobierania.PobranoBajtow = Convert.ToInt32(res.Headers[HttpResponseHeader.ContentLength].ToString());
switch (res.Headers[HttpResponseHeader.ContentEncoding].ToString())
{
case "gzip":
System.IO.Compression.GZipStream resGZipStream = new System.IO.Compression.GZipStream(res.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress);
czytaj = new StreamReader(resGZipStream, _kodowanie);
wynik = czytaj.ReadToEnd();
resGZipStream.Close();
break;
case "deflate":
System.IO.Compression.DeflateStream resDeflateStream = new System.IO.Compression.DeflateStream(res.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress);
czytaj = new StreamReader(resDeflateStream, _kodowanie);
wynik = czytaj.ReadToEnd();
resDeflateStream.Close();
break;
default:
Stream resStream = res.GetResponseStream();
czytaj = new StreamReader(resStream, _kodowanie);
wynik = czytaj.ReadToEnd();
resStream.Close();
break;
}
czytaj.Close();
res.Close();
req.Abort(); //Na wszelki wypadek
_wynikPobierania.DataRozpoczecia = dataRozpoczecia;
_wynikPobierania.DataZakonczenia = DateTime.Now;
_wynikPobierania.Status = true;
_wynikPobierania.Dane = wynik;
}
catch (Exception ex)
{
_wynikPobierania.Status = false;
_wynikPobierania.Blad = ex;
}
}
public class WynikPobieraniaClass
{
private bool _status;
private string _dane, _czasPobierania;
private Exception _blad;
private DateTime _dataRozpoczecia, _dataZakonczenia, _czasSerwera;
private List<string> _ciasteczka, _magazynCiasteczek;
private int _pobranoBajtow;
private System.Net.WebHeaderCollection _naglowkiHTTP;
/// <summary>Status pobierania danych.<para>True jeśli brak błędów, False jeśli błąd.</para></summary>
public bool Status
{
get { return _status; }
set { _status = value; }
}
/// <summary>Dane pobrane z zasobu.</summary>
public string Dane
{
get { return _dane; }
set { _dane = value; }
}
/// <summary>Zwraca całkowity czas pobierania danych.<para>Format: 00:00:00:00.000 (dni:godzin:minut:sekund.milisekund, 3 pierwsze warunkowe)</para></summary>
public string CzasPobierania
{
get
{
if (_czasPobierania == null)
{
TimeSpan czasPobierania = (_dataZakonczenia - _dataRozpoczecia);
string wynik = "";
if (czasPobierania.Days != 0) { wynik += czasPobierania.Days.ToString("00") + ":"; }
if (czasPobierania.Hours != 0) { wynik += czasPobierania.Hours.ToString("00") + ":"; }
if (czasPobierania.Minutes != 0) { wynik += czasPobierania.Minutes.ToString("00") + ":"; }
wynik += czasPobierania.Seconds.ToString("00") + "." + czasPobierania.Milliseconds.ToString("000");
_czasPobierania = wynik;
}
return _czasPobierania
}
}
/// <summary>Instancja błędu (jeżeli wystąpił).</summary>
public Exception Blad
{
get { return _blad; }
set { _blad = value; }
}
/// <summary>Data rozpoczęcia pobierania.</summary>
public DateTime DataRozpoczecia
{
get { return _dataRozpoczecia; }
set { _dataRozpoczecia = value; }
}
/// <summary>Data zakończenia pobierania.</summary>
public DateTime DataZakonczenia
{
get { return _dataZakonczenia; }
set { _dataZakonczenia = value; }
}
/// <summary>Czas na serwerze.<para>Z nagłówka HTTP Date.</para></summary>
public DateTime CzasSerwera
{
get { return _czasSerwera; }
set { _czasSerwera = value; }
}
/// <summary>Przechowuje ciasteczka ustawione przez serwer przy aktualnym żądaniu.<para>Z nagłówka HTTP Set-Cookie.</para></summary>
public List<string> Ciasteczka
{
get { return _ciasteczka; }
set { _ciasteczka = value; }
}
/// <summary>Przechowuje wszystkie ciasteczka (wysłane do serwera oraz otrzymane w odpowiedzi na żądanie).</summary>
public List<string> MagazynCiasteczek
{
get { return _magazynCiasteczek; }
set { _magazynCiasteczek = value; }
}
/// <summary>Rzeczywista ilość pobranych bajtów (uwzględnia kompresję).</summary>
public int PobranoBajtow
{
get { return _pobranoBajtow; }
set { _pobranoBajtow = value; }
}
/// <summary>Wszystkie nagłówki HTTP uzyskane w odpowiedzi.</summary>
public System.Net.WebHeaderCollection NaglowkiHTTP
{
get { return _naglowkiHTTP; }
set { _naglowkiHTTP = value; }
}
public WynikPobieraniaClass()
{
_status = false;
_dane = null;
_blad = null;
_dataZakonczenia = DateTime.MinValue;
_czasSerwera = DateTime.MinValue;
_ciasteczka = null;
_magazynCiasteczek = null;
_czasPobierania = null;
_pobranoBajtow = 0;
_naglowkiHTTP = null;
}
}
}
No i może jeszcze mały przykład użycia na koniec:
List<string> magazynCiasteczek = new List<string>();
magazynCiasteczek.Add("gameapi_console=0");
magazynCiasteczek.Add("sid=f048cea2c86f2daf743e30cbfd2c7bf4");
PobierzDaneHTTPClass pobieranie = new PobierzDaneHTTPClass();
pobieranie.ObslugaCiasteczek = true;
pobieranie.MagazynCiasteczek = magazynCiasteczek;
pobieranie.AutoRedirect = true;
pobieranie.LinkPobierania = "http://jakis-adres.pl";
pobieranie.DanePOST = "json={\"push.gST\":{}}";
pobieranie.Pobierz();
if (pobieranie.Wynik.Status)
{
Clipboard.SetText(pobieranie.Wynik.Dane);
}
Myślę, że przyda się ludziom którzy zaczynają dopiero swoją przygodę z C# i poszukują prostego w obsłudze rozwiązania. :)
Pozdrawiam,
Anthony