Как парсить данные с HTML-страниц на Python


Руководитель проектов Дмитрий Мирошниченко рассказывает, как быстро спарсить объявления конкурентов в «Яндекс.Директе» с помощью языка программирования Python.

В прошлой статье я показывал, как можно спарсить заголовки и текст объявлений из Яндекс.Директа с помощью Google Docs. Сегодня покажу как можно собрать ещё и название компании, почту, телефон и адрес сайта у каждого объявления. Все эти данные будет собирать скрипт на python и складывать в CSV файлик.

Я не профессиональный программист. Мой код далёк от кристальной чистоты. У меня часто нет проверок на исключения и использую не самые передовые решения. Я пишу как умею, но программирование помогает решать повседневные задачи быстро и с наименьшими затратами.

Тем не менее я стараюсь придерживаться стиля написания кода PEP8. Это даёт гарантию того, что в моем коде сможет разобраться кто-то ещё. Это полезно, когда что-то не работает и позволяет спросить совет у старших товарищей про программированию.

Кстати, ни в одном из популярных сервисов мониторинга контекстных объявлений вы не найдёте ни номеров телефонов, ни адресов сайтов, ни тем более электронной почты компаний, которые рекламируются в директе. Так что можно сказать, у вас будет эксклюзив.

Где и что парсить?

В прошлый раз мы смотрели объявления по ссылкам вида

https://direct.yandex.ru/search?&rid=213&text=запрос&page=номер_страницы

Заголовок и текст объявления вы уже знаете как находить. Отсюда же можно взять и сайт компании. Остальная информация есть в карточке объявления. Нужно найти признаки этих ссылок:

  • Сайт компании находится внутри тега span с классом domain.
  • Ссылка на карточку имеет класс vcard.

DZCG29tUwkdRZqW0thQwJAOGPPpVwWsV-uxA8aC_
Ссылка на карточку имеет класс vcard

класс домена.jpg
Сайт компании находится внутри тега span с классом domain

На карточке объявления также ищем признаки нужных элементов. Нас будут интересовать:

  • Название компании. Находится в заголовке с тегом h1.
  • Телефон находится внутри элементов с классами contact-item call-button-container large-text.
  • Почта имеет класс email.

карточка объявления.png
Карточка объявления, где есть интересующие нас данные: название компании, телефон и электронная почта

Соберу всё в кучу:

1. Пройдитесь по всем ссылкам вида https://direct.yandex.ru/search?&rid=213&text=запрос&page=номер_страницы.
2. С этих страниц запишите в файл заголовок и текст объявления, а также домен сайта.
3. Найдите ссылку на карточку объявления, если она есть.
4. Соберите название компании, почту и номер телефона с карточки и запишите в файл.

Чем парсить?

Что использовать для парсинга html страниц? Вот тут есть множество вариантов.

Для сильных духом можно использовать регулярные выражения. Но если вы знаете как их можно использовать, вам не нужно читать эту статью.

Можно использовать библиотеку lxml. Она работает очень быстро, но есть много ограничений. Яндекс сразу понимает, что на страницу зашёл робот. Чтобы этого избежать нужно эмулировать браузер обычного человека.

Прикинуться человеком со всякими юзерагентами и куками может фреймворк Grab. Я выбрал именно его, потому что уже немного знаю как с ним работать. Правда советую подумать разбираться в нём или нет, так как у него странная документация. Я там нашёл далеко не всё, что мне было нужно.

Описание программы

Текст программы можно взять с GitHub. Я расставил основные комментарии по тексту. В целом должно быть всё понятно.

Функция get_pages получает количество всех страниц с объявлениями. Работает очень просто. Получаем массив страниц и берём последнюю цифру.

список страниц.jpg
Массив страниц с объявлениями

Яндекс.Директ показывает подряд не больше 8 цифр. Иногда бывает так, что их больше. Тогда Яндекс ставить в конце многоточие и сразу узнать сколько всего страниц нельзя.

список страниц больше 8.jpg
Страниц с объявлениями больше 8

список страниц 10.jpg
Всего 10 страниц

Приходится открывать предпоследнюю страницу, переходить туда и снова смотреть последнюю цифру.

Итоговый результат записываем в файл firms.csv

csv.png
Все данные в уже готовом CSV файле

Нюансы

  • Если делать много запросов через небольшие интервалы, Яндекс будет показывать капчу. Чтобы её распознавать автоматически можно использовать сервис antigate. На GitHub есть библиотека для python. Ну, или можно делать запросы не так часто. Я пошёл по второму пути: поставил таймаут 5 секунд в параметрах grab.

g.setup (encoding='utf-8', connect_timeout=3, timeout=5)

  • У одной компании может быть несколько объявлений. У меня была задача собрать все различные компании: мне не не нужно было брать все объявления. Поэтому я использовал номер телефона как уникальное поле. Если объявление с таким номером уже было, я его исключал.
  • Библиотека tqdm показывает прогресс выполнения любого цикла. Нужно просто обернуть его и в консоли будет виден прогресс. Использовал просто для наглядности.

Screenshot at дек. 26 14-15-44.png
Прогресс парсинга объявлений по каждому запросу

Как со всем этим работать

Расскажу как всё это запустить на примере Windows 10. В Linux и macOS всё делается аналогично.

  • Установите Python 3. Я использую ветку 3.5. Скачать можно с официального сайта. Ветку 3.6 пока не советую, её зарелизили всего несколько дней назад.
  • Установите Grab. Лучше через pip. Это менеджер пакетов для python. Идёт с ним в комплекте.

pip install grab

  • Установите tqdm. Так же ставится через pip.

pip install tqdm

  • Установите git. Скачать можно с официального сайта.
  • Скачайте исходники себе на компьютер.

git clone https://github.com/gumbert/ydirect

  • Поменяйте запросы на ваши в тексте программы. Для написания и редактирования кода я использую Sublime.
  • Запустите скрипт.

python ydirect.py

Если всё сделали правильно, через некоторое время у вас будет файлик firms.csv со всеми данными.

Учитесь программировать и пусть компьютер работает за вас.

Мнение автора и редакции может не совпадать. Хотите написать колонку для «Нетологии»? Читайте наши условия публикации.

Полный текст статьи читайте на Нетология