Микро-робот для чтения данных из веб-страниц и сохранения в файл

Блог 16 апреля 2014

Теги: C#, программирование,центр дистанционного обучения

Часто требуется считать однотипные данные из веб- страниц, отформатировать и сохранить в файл.
Выбор как всегда прост, найти готовое приложение или разрабртать свое. В учебных целях создаем свое консольное приложение на C#. В конфигурационный файл будем помещать управляющие команды. Потребуются команды:
@SAVE - файл, куда сохранять,
@LINK - адреса веб-страниц и заголовки (через разделитель | ),
@START, @END - для указния, где искать данные,
@INPUT - шаблон (регулярное-выражение) для входных данных,
@OUTPUT - шаблон (регулярное-выражение) для выходных данных.

Пример конфигурационного файла.

@SAVE C:\temp\weather.csv

@INPUT <tr[^>]*>\s*<th[^>]*>([^<]*?)</th>

s*<td[^>]*>(.*?)</td>\s*<td[^>]*>(.*?)</td>\s*<td[^>]*>(.*?)</td>\s*<td[^>]*>(.*?)</td>\s*<td[^>]*>(.*?)</td>\s*</tr>




@OUTPUT {0};{1};{2};{3};{4};{5}

@START <table cellSpacing=1 cellPadding=2 border=0>
@END </table>

@LINK



http://www.pogodaiklimat.ru/monitor.php?id=27612|Москва
http://www.pogodaiklimat.ru/monitor.php?id=26063|Санкт-Петербург

Код программы.

namespace Weather
{
    class Program
    {
        static string fconfig = 

"weather.config.txt";
        static string freport = @"C:\temp\weather.csv";
        static string start, end, input, output;
        static 

List<string> lstLink = new List<string>();
        static List<string> lstTitle = new List<string>();
        static bool bRus = true;

     

   static void Main(string[] args)
        {
            string s = "";
            try
            {
                //парсим конфиг-файл
      

          Parse();
                //создаем регулярное выражение для выборки данных
                Regex _regexInp = new Regex(input, 

RegexOptions.Singleline | RegexOptions.IgnoreCase);

                //объект для создания результирующего текста
                System.Text.StringBuilder 

sb = new System.Text.StringBuilder();

                for (int i = 0; i < lstLink.Count; i++)
                {
                    

Console.WriteLine(lstLink[i]);
                    //получить данные из веб-страницы
                    s = GetUrl(lstLink[i], Encoding.UTF8);
            

        s = GetBody(s).Replace("\n", "").Replace("\r", "");

                    //добавить заголовок
                    sb.Append(lstTitle[i] + 

"\n");

                    //найти все совпадения с шаблоном
                    Match match = _regexInp.Match(s);
                    while 

(match.Success)
                    {
                        //временная строка указывает на выходной шаблон
                        string sCode = 

output;
                        for (int j = 1; j < match.Groups.Count; j++)
                        {
                            //провести замену во 

временной строке всех подстрок, которые соответствуют результатам поиска по шаблону
                            sCode = sCode.Replace("{" + (j-1) + "}", 

match.Groups[j].Value.Trim());
                        }
                        //если нужен русский формат чисел
                        if( bRus )
   

                         sCode = sCode.Replace(".", ",");
                        //добавить к результату
                        sb.Append(sCode + "\n

");
                        match = match.NextMatch();
                    }
                }
                //записать в выходной файл
           

     File.WriteAllText(freport, sb.ToString(), Encoding.GetEncoding(1251));
            }
            catch (Exception e)
            {
                

Console.WriteLine("Error: " + e.ToString());
            }
            finally
            {
            }
            Console.WriteLine("Press 

any key!");
            Console.ReadKey();
        }

        //считать данные из URL
        static string GetUrl(string url, Encoding enc)
     

   {
            string s = "";
            try
            {
                WebRequest request = WebRequest.Create(url);
                

request.Proxy.Credentials = CredentialCache.DefaultCredentials;

                WebResponse response = request.GetResponse();
                Stream data 

= response.GetResponseStream();
                using (StreamReader sr = new StreamReader(data, enc))
                {
                    s = 

sr.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(url + ", " + 

ex.ToString());
                s = "";
            }
            return s;
        }
        
        //вычленить область с данными
        

static string GetBody(string s)
        {
            int ip = s.IndexOf(start);
            if (ip < 0) return "";

            int ip2 = 

s.IndexOf(end, ip);
            if (ip2 < 0) return "";

            return s.Substring(ip, ip2 - ip);
        }

        //парсим конфиг-

файл
        static void Parse()
        {
            string dir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly

().Location);
            string[] lines = File.ReadAllLines(dir + "\\" + fconfig, Encoding.UTF8);
            for (int i = 0; i < lines.Length; i+

+)
            {
                string s = lines[i].Trim();
                if (s == "" || s.Substring(0, 1) == "#")
                    continue;



                if (s.Contains("@SAVE"))
                {
                    freport = s.Replace("@SAVE", "").Trim();
                    

continue;
                }

                if (s.Contains("@INPUT"))
                {
                    input = s.Replace("@INPUT", 

"").Trim();
                    continue;
                }

                if (s.Contains("@OUTPUT"))
                {
                    

output = s.Replace("@OUTPUT", "").Trim();
                    continue;
                }

                if (s.Contains("@START"))
           

     {
                    start = s.Replace("@START", "").Trim();
                    continue;
                }

                if 

(s.Contains("@END"))
                {
                    end = s.Replace("@END", "").Trim();
                    continue;
                }




                //для отладки - выход из парсинга
                if (s.Contains("@BREAK"))
                {
                    break;
        

        }

                string [] arr = s.Split('|');
                if (arr.Length != 2)
                    continue;

                

lstLink.Add(arr[0]);
                lstTitle.Add(arr[1]);
            }
        }
    }
}

Пояснения к коду программы.

Делаем парсинг конфиг-файла, создаем регулярное выражение для выборки данных и объект для создания результирующего текста. В цикле по всем ссылкам получаем данные из веб-страницы, добавить заголовок, потом применяем регулярное выражение. Для каждого совпадения с входным шаблоном провести замену в выходном шаблоне всех подстрок, которые соответствуют результатам поиска по входному шаблону, добавить к результату. При выходе из цикла результат записать в выходной файл.
Пример текста, который будет найден по шаблону @INPUT из приведенного выше конфигурационного файла.



<tr align="middle" bgcolor="#ffffff">
      <th class="black">2</th>
      <td class="blue1">-3.3</td>
      <td class="green

">0.1</td>
      <td class="red1">2.2</td><td class="blue1">-2.1</td><td class="blue3">0.0</td></tr>
Ему будет соответствовать выходная строка - 2;-3.3;0.1;2.2;-2;0.0

Комментарии

yura: 02-10-2014 23:48

мне надо качать данные с сайта http://www.finam.ru/analysis/quotes/?0=&t=2558404   там есть архив, так вот оттуда. это возможно?

4- за то, что длинные строки вылезают за границы , например @INPUT <tr[^>]*>\s*<th[^>]*>([^<]*?)</th>\s*<td[^>]*>(.*?)</td>\s*<td[^>

Добавить комментарий могут только авторизованные пользователи. Авторизоваться
Комментарий

Оценка





Авторизоваться через http://www.pvobr.ru
Логин
Пароль
Регистрация

Авторизоваться через соцсети
Наверх