Yvision.kz
kk
Разное
Разное
399 773 постов41 подписчиков
Всяко-разно
5
06:10, 02 апреля 2012

Простой граббинг, сложных сайтов. C# (на примере Yvision.kz)

Столкнулся с задачей: есть сайт который нужно клонировать, но на нем около 50 рубрик и больше 40 000 статей, и все эти записи нужно перенести на сайт клона.

"Остается запастись терпения и несколько месяцев свободного времени для переноса материалов в базу данных нового сайта" - подумал заказчик.

Но мы ведь программисты и не любим рутину, у нас долг такой "Облегчать людям жизнь", вот я и решил написать граббера который сам все сделает в течении одного часа, и сайт можно будет запускать!  И в этом посте я расскажу и даже покажу как написать это на технологии ASP.NET с использованием языка C#. Поехали.

Инструменты.

Для данного опыта нам понадобится софт:

  • Visual Studio 2010
  • .Net Framework 4.0

В качестве парсера HTML воспользуемся HTML Agility Pack, но прежде чем парсить нам нужно сначала получить HTML, можно воспользоватся стандартным WebClient(), но далеко не секрет что сейчас все сайты усыпаны JavaScript который генерирует часть разметки, информации, а WebClient() к сожалению не может ждать пока отработает JS и только после этого забирать HTML. Значит нам он не подойдет. И на помощь приходит библиотека Watin!

Watin - библиотека которая помогает тестировать приложения, программируешь тест, и в реальном времени открывается браузер и выполняются различные нажатия кнопок ввод текст и т.д.

Но мы будем использовать её не совсем по назначению.

Начнем.

В Visual Studio создаем новое консольное приложение

Blog post image

Далее устанавливаем нужные библиотеки

Blog post image

Открываем раздел "Online" и в строке поиска пишем "watin"

Blog post image

и жмем установить WatiN

Далее пишем в поиске HTMLAgilityPack и тоже устанавливаем

Blog post image

Установка библиотек завершена.

Далее добавляем файл конфигурации в наш проект с именем app.config

Blog post image

во внутрь файл положите это:

  1. <?xml version="1.0"?>
  2. <configuration>
  3. <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

Далее изменим конфигурацию приложения, в солюшене нажмем на Properties два раза

Blog post image

И изменим пункт "Требуемая версия .Net Framework" на ".Net Framework 4"

Blog post image

далее открываем Program.cs и подключаем нужные библиотеки перед class Program{ }

  1. using HtmlAgilityPack;
  2. using System;
  3. using WatiN.Core;

перед static Main указываем что это однопоточное приложение

  1. [STAThread]

В итоге у вас должно получится следующее

  1. using System.Text;
  2.  
  3.  
  4. namespace ConsoleApplication1
  5. {
  6. using HtmlAgilityPack;
  7. using System;
  8. using WatiN.Core;
  9.  
  10. class Program
  11. {
  12. [STAThread]
  13. static void Main()
  14. {
  15. }
  16. }
  17. }
*namespace может отличатся

далее в Main(){} указываем кодировку

  1. Console.OutputEncoding = Encoding.UTF8;

и пишем структуру нашего граббера html

  1. using (var browser = new IE("http://www.yvision.kz"))
  2. {
  3. Settings.WaitForCompleteTimeOut = 999999999; /*увеличиваем тайм-аут на всякий случай*/
  4. var doc = new HtmlDocument(); /* инсталляция объекта парсера HTML Agility Pack*/
  5. doc.LoadHtml(browser.Body.OuterHtml); /*помещаем в парсер полученный html с страницы yvison.kz*/
  6. }
  7. Console.Write("Done!"); /*текст после завершения скрипта*/
  8. Console.ReadKey(); /*ожидание нажатия клавиши*/

таким образом мы имеем следующий код:

  1. скрипт открывает браузер IE
  2. переходит по адресу http://www.yvision.kz
  3. забирает  HTML разметку
  4. отдает парсеру

далее нам нужно распарсить информацию с html и например отобразим их в консоле, приступим.

Например получим 4 последних сообщения с главной страницы:

Blog post image

Смотрим структуру HTML, и видим что эти блоки лежат в div с классом .mainContent.main_page

каждым отдельный блок имеет класс .half-l

Blog post image

отсюда следует  что нам нужно из полученного HTML страницы, взять контент который находится в диве с классом .mainContent.main_page

и выбрать из него все дивы с классом .half-l Приступим.

  1. using System.Text;
  2.  
  3.  
  4. namespace ConsoleApplication1
  5. {
  6. using HtmlAgilityPack;
  7. using System;
  8. using WatiN.Core;
  9.  
  10. class Program
  11. {
  12. [STAThread]
  13. static void Main()
  14. {
  15. Console.OutputEncoding = Encoding.UTF8;
  16.  
  17. using (var browser = new FireFox("http://www.yvision.kz"))
  18. {
  19. Settings.WaitForCompleteTimeOut = 999999999;
  20. var doc = new HtmlDocument();
  21. doc.LoadHtml(browser.Body.OuterHtml);
  22. var dataBlock = doc.DocumentNode.SelectSingleNode("//div[@class=\"mainContent main_page\"]"); /*получаем в переменную все блоки из дива .mainContent.mainpage*/
  23.  
  24. foreach (var item in dataBlock.SelectNodes("//div[@class=\"half-l\"]")) /*в цикле проходим по каждому диву с классом .half-l*/
  25. {
  26. Console.Write( item.InnerHtml + "\n"); /*показываем в консоли содержимое дива*/
  27. }
  28. }
  29. Console.Write("Done!");
  30. Console.ReadKey();
  31. }
  32. }
  33. }

Теперь можете запустить приложение и проверить - F5 в Visual Studio

должно выглядеть примерно так

Blog post image

блоки мы вывели, но нужно отсеять не нужную информацию, давайте из каждого блока возьмем только ссылку на статью и адрес картинки

видим что путь до ссылки  "div.text > h3 > a" и путь до картинки у нас div.info> div.photo> div.hold> a > img

Blog post image

значит код выборки будет следующий

  1. Console.Write("Link item: " + item.SelectSingleNode("//div[@class=\"info\"]/div[@class=\"photo\"]/div[@class=\"hold\"]/a").Attributes["href"].Value + "\n"); /*выбираем ссылку*/
  2. Console.Write("Images patch: " + item.SelectSingleNode("//div[@class=\"info\"]/div[@class=\"photo\"]/div[@class=\"hold\"]/a/img").Attributes["src"].Value + "\n"); /*выбираем адрес картинки*/

Весь листинг выглядит так

  1. using System.Text;
  2.  
  3.  
  4. namespace ConsoleApplication1
  5. {
  6. using HtmlAgilityPack;
  7. using System;
  8. using WatiN.Core;
  9.  
  10. class Program
  11. {
  12. [STAThread]
  13. static void Main()
  14. {
  15. Console.OutputEncoding = Encoding.UTF8;
  16.  
  17. using (var browser = new FireFox("http://www.yvision.kz"))
  18. {
  19. Settings.WaitForCompleteTimeOut = 999999999;
  20. var doc = new HtmlDocument();
  21. doc.LoadHtml(browser.Body.OuterHtml);
  22. var dataBlock = doc.DocumentNode.SelectSingleNode("//div[@class=\"mainContent main_page\"]");
  23. int cntItem = 0; /*добавим счетчик, мы ведь будем выводить только 4 записи*/
  24. foreach (var item in dataBlock.SelectNodes("//div[@class=\"half-l\"]"))
  25. {
  26. cntItem++; /*увеличиваем счетчик на один*/
  27. Console.Write("Link item: " + item.SelectSingleNode("//div[@class=\"info\"]/div[@class=\"photo\"]/div[@class=\"hold\"]/a").Attributes["href"].Value + "\n");
  28. Console.Write("Images patch: " + item.SelectSingleNode("//div[@class=\"info\"]/div[@class=\"photo\"]/div[@class=\"hold\"]/a/img").Attributes["src"].Value + "\n");
  29. Console.Write("\n*****yvision.kz*******\n\n"); /*визуально разграничим результаты текстом*/
  30. if(cntItem == 4) {break;} /*если выбрали 4 записи то остановить цикл*/
  31. }
  32. }
  33. Console.Write("Done!");
  34. Console.ReadKey();
  35. }
  36. }
  37. }

Запустим программу и увидим

Blog post image

Работает!  Далее с этой информацией можете делать что душе угодно, например: положить в базу данных чтоб отображать на сайте.

Скачать работающие исходники

P.S если парсить много контента за один раз то в браузере лучше отключить отображение картинок, тогда парсинг займет меньше времени.

Успехов!

5