место в рейтинге
  • 153252
  • 554
  • 56
Нравится блог?
Подписывайтесь!

Простой граббинг, сложных сайтов. 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 создаем новое консольное приложение

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

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

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

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

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

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

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

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

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

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

далее открываем 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 последних сообщения с главной страницы:

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

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

отсюда следует  что нам нужно из полученного 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

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

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

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

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

  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. }

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

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

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

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

Успехов!

2 апреля 2012, 18:10
21596

Загрузка...
Loading...

Комментарии

ibrain
0
0
спс за рабочий "завод" по копипасту)
web
0
0
не совсем понял :)
Adik
1
0
было бы интересно увидеть как это реализовывается на php
web
0
0
К сожалению не специализируюсь на php уже ооооочень давно. Но знаю что на php тоже все просто :)
lEx0kz
1
0
curl и simplehtmldom.sourceforge.net вам в помощь. могу как нить написать базовый парсер если интересует :D
web
1
0
curl классная вещь. Работал с ним. Советую.
Adik
0
0
угу, чтож ждем)
pecl_http + DOMDocument + XQuery + RegExp
Спасибо что еще есть те кто то делиться а не тащит в нору
web
0
0
Всегда пожалуйста.
Спасибо! Андр, это ты?
web
0
0
Если это адресовано мне - то я не Андр :)
Это XQuery в SelectNodes/SelectSingleNode пихается?
web
0
0
Можно и так его назвать, либо еще называется XPath
так тут где то у вас ошибка судя по последнему скриншоту, у вас все ссылки и адреса картинок повторяются!
Спасибо ьольшое, с Вашего урока начну изучат Agility pack.
Hes
0
0
HtmlAgilityPack должен работать с Linq - а там проще делать проекции в списки объектов, без танцев с бубнами, не пробовали? Будет время - в своем блоге что нибудь такое нарисую :)

Оставьте свой комментарий

Спасибо за открытие блога в Yvision.kz! Чтобы убедиться в отсутствии спама, все комментарии новых пользователей проходят премодерацию. Соблюдение правил нашей блог-платформы ускорит ваш переход в категорию надежных пользователей, не нуждающихся в премодерации. Обязательно прочтите наши правила по указанной ссылке: Правила

Также можно нажать Ctrl+Enter

Популярные посты

Маргулан Сейсембаев: Об идеальных учителях, финской модели обучения и дисциплине

Маргулан Сейсембаев: Об идеальных учителях, финской модели обучения и дисциплине

Крупнейшая частная школа осознала, что внедрять финскую модель в чистом виде в Казахстане, не имеет смысла. Нельзя давать детям свободу без "идеальных" учителей.
Zhumanova
вчера / 8:18
  • 4819
  • 7
О проститутках, ЗППП и других сексуальных страстях

О проститутках, ЗППП и других сексуальных страстях

У меня обширный сексуальный опыт, и я этим не хвастаюсь. Будь у меня возможность, променял бы это всё на одного партнёра. Но так как с личной жизнью не заладилось, а секс я очень люблю, то приходилось изворачиваться.
bez_prav
18 окт. 2017 / 18:01
Я помню тот день, когда мне позвонили друзья и сообщили: «Она выходит замуж». Часть 2

Я помню тот день, когда мне позвонили друзья и сообщили: «Она выходит замуж». Часть 2

Я знал дату свадьбы. За неделю до свадьбы в соцсети "Вконтакте" на все мои последние фото, был проставлен лайк с её профиля. Сердце забилось сильнее. В душе загорелась наивная, крошечная надежда.
Dominator-kz
17 окт. 2017 / 15:41
Льготное кредитование для молодежи Алматы. Не хоромы, но для начала неплохо

Льготное кредитование для молодежи Алматы. Не хоромы, но для начала неплохо

Если вам нет 35 лет и у вас нет своего жилья, то есть интересная гос.программа. Нишевая программа - молодые семьи Алматы до 35 лет, семья - это как минимум 2 супруга без детей.
DanaJarlygapova
19 окт. 2017 / 16:21
Мой парень – «тиран». Почему я вступила в такие отношения?

Мой парень – «тиран». Почему я вступила в такие отношения?

История из моей жизни. Я вспоминаю эти отношения и сама не могу понять - как так произошло? А дело в том, что вы и сами не заметите. Это наступает плавно и динамично.
Altynai_JA
18 окт. 2017 / 14:17
Доверяют ли граждане Казахстана полицейским? Социальный опрос

Доверяют ли граждане Казахстана полицейским? Социальный опрос

Борьба с оборотнями в погонах идёт не один год, но без особого эффекта. Это даёт повод подробнее поговорить о нашей полиции и её проблемах. Как относятся к полицейским казахстанцы?
voiceQZ
20 окт. 2017 / 18:42
  • 2611
  • 41
Как и где найти дешевые авиабилеты?

Как и где найти дешевые авиабилеты?

Дешевые авиабилеты и не только. Какими сайтами воспользоваться лучше всего? Байки о том, что чем раньше вы покупаете билет, тем дешевле, не всегда верны и точны.
dianaobyrne
вчера / 9:25
  • 2062
  • 15
Сказ об офисных планктонах. А какой работник ты?

Сказ об офисных планктонах. А какой работник ты?

Я проработала во многих компаниях и повстречала очень много разных интересных людей. Исходя из моих наблюдений, могу описать несколько категорий работников. Может, речь пойдет о ком-то из вас…
Altynai_JA
18 окт. 2017 / 17:51
  • 2022
  • 20
«Автобусная неделя». Выдержит ли аким Шымкента давку в общественном транспорте?

«Автобусная неделя». Выдержит ли аким Шымкента давку в общественном транспорте?

Аким Шымкента Габидулла Абдрахимов нашёл решение накопившихся проблем городского транспорта. Все ключевые работники акимата некоторое время будут сами ездить на автобусах.
openqazaqstan
18 окт. 2017 / 10:53
  • 1954
  • 36