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

0 komentarzy