Современная Веб-Автоматизация при Помощи Python и Selenium

В данной статье вы изучите продвинутую технику веб-автоматизации в Python. Мы используем Selenium с браузером без графического интерфейса, экспортируем отобранные данные в CSV файлы и завернем ваш отобранный код в класс Python.

Содержание

  1. Мотивация: отслеживаем музыкальные привычки
  2. Установка и Настройка Selenium
  3. Пробный запуск браузера в режиме Headless
  4. Веб-парсинг в Python
  5. Расширяем потенциал
  6. Исследуем каталог
  7. Создание класса
  8. Собираем структурированные данные
  9. Что дальше и чему мы научились?

1. Мотивация: отслеживаем музыкальные привычки

Предположим, что вы время от времени слушаете музыку на bandcamp.com или soundcloud и вам хочется вспомнить название песни, которую вы услышали несколько месяцев назад.

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Конечно, вы можете покопаться в истории вашего браузера и проверить каждую песню, но это весьма болезненная затея… Все, что вы помните, это то, что вы услышали песню несколько месяцев назад и она в жанре электроника.

«Было бы классно», думаете вы «Если бы у меня запись моей истории прослушиваний. Я мог бы просто взглянуть на электронную музыку, которую я слушал пару месяцев назад и найти эту песню!»

Сегодня мы создадим простой класс Python под названием BandLeader, который подключается к bandcamp.com, стримит музыку из раздела «Найденное» на главной странице, и отслеживает вашу историю прослушиваний.

История прослушиваний будет сохранена на диске в CSV файле. Далее, вы можете в любой момент просматривать CSV файл в вашей любимой программе для работы с таблицами, или даже в Python.

Если у вас есть опыт в веб-парсинга в Python, то вы знакомы с созданием HTTP запросами и использованием API Python для навигации в DOM. Сегодня мы затронем все эти пункты, за одним исключением.

Сегодня вы используете браузер в режиме без графического интерфейса (режим «командной строки») для выполнения запросов HTTP.

Консольный браузер – это обычный веб браузер, который работает без видимого пользовательского интерфейса. Как вы могли догадаться, он может делать больше, чем выполнять запросы: проводить рендер HTML (правда, вы этого не будете видеть), хранить информацию о сессии, даже проводить асинхронные сетевые связи на коде JavaScript.

Если вы хотите автоматизировать современную сеть, консольные браузеры – неотъемлемая часть.

Бесплатный бонус: Скачайте основу проекта Python+Selenium с полным исходным кодом, который вы можете использовать как основу для вашего веб-парсинга в Python и автоматических приложениях.

2. Установка и Настройка Selenium

Первый шаг, перед тем как написать первую строчку кода – это установка Selenium с поддержкой WebDriver для вашего любимого браузера. Далее в статье мы будем работать с Firefox Selenium, но Chrome также будет отлично.

По выше указанным ссылкам имеется полное описание процесса установки драйверов для Selenium.

Далее, нужно установить Selenium при помощи pip, или как вам удобнее. Если вы создали виртуальное пространство для этого проекта, просто введите:

[Если у вас будут вопросы в ходе изучения данной статьи, полный код можно найти на GitHub.]

Время для пробного запуска.

3. Пробный запуск браузера

Чтобы убедиться, что все работает, попробуйте выполнить простой поиск в интернете через DuckDuckGo. Используйте свой предпочитаемый интерпретатор Python и введите:

Таким образом, вы только что создали Firefox в режиме консольного приложения (без головы т.е. без графического интерфейса), направленный на https://duckduckgo.com. Вы создали экземпляр «Options» и применили его для активации мода headless в конструкторе Firefox. Это похоже на введение команды firefox – headless в командной строке.

4. Веб-парсинг в Python

Современная Веб-Автоматизация при Помощи Python и Selenium

Теперь, когда страница загружена, вы можете запросить DOM при помощи методов, определенных в вашем созданном объекте браузера.

Но откуда мы знаем, что запрашивать? Лучший способ – это открыть ваш веб браузер и использовать его инструменты разработки для исследования содержимого страницы. Сейчас вы можете получить форму поиска для отправки запроса, чтобы выполнить запрос. Проверив главную страницу DuckDuckGo, вы увидите, что элемент поисковой формы<input> имеет атрибут ID «search_form_input_homepage«. Вот, что вам нужно:

Вы найдете поисковую форму, используя метод send_keys для заполнения, затем метод submit для выполнения поиска для «Real Python». Вы можете проверить результат:

Результат:

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

5. Расширяем потенциал

Вы удостоверились в том, что можете управлять браузером в режиме headless (без головы т.е. без графического интерфейса), используя Python, теперь перейдем к практике.

  1. Вам нужно включать музыку;
  2. Вам нужно искать и просматривать музыку;
  3. Вам нужна информация о проигрываемой музыке.

Для начала, отправимся на https://bandcamp.com и покопаемся в инструментах разработки вашего браузера. Вы увидите большую и яркую кнопку воспроизведения внизу экрана с HTML атрибутом class, который содержит значение «playbutton«. Проверим, как это работает:

Современная Веб-Автоматизация при Помощи Python и Selenium

Вы должны слышать музыку! Запустите трек и оставьте его, вернитесь обратно в веб браузер. Рядом с кнопкой воспроизведения находится окно поиска. Еще раз, нужно проверить эту секцию. Вы найдете, что каждый видимый и доступный трек имеет значение класса «discover-item«, а каждый объект кликабельный. В Python, проверка выполняется следующим образом:

Следующий трек должен воспроизвестись. Это первый шаг в исследовании bandcamp при помощи Python! Вы уделите несколько минут, переключая разные треки в пространстве Python, но скромная библиотека из 8 песен может быстро надоесть.

6. Изучаем каталог

Вернувшись в свой браузер, вы увидите кнопку для изучения всех треков, связанных с окном поиска bandcamp. Сейчас все должно выглядеть знакомым: каждая кнопка имеет значение класса»item-page«. Последняя кнопка — “далее” показывает следующие восемь композиций в каталоге. Нужно выполнить следующее:

Отлично! Теперь, может вам захочется просмотреть новые треки, и вы подумаете «Я просто перепишу переменные моих треков, так же, как я делал это минуту назад». Но здесь мы с вами столкнемся с хитростями.

Во первых, bandcamp разработали свой сайт так, чтобы пользователям было удобно им пользоваться, а не для скриптов Python для доступа к программному обеспечению. Вызывая next_button.click(), реальный веб браузер отвечает, выполняя какой-нибудь код JavaScript. Если вы попробуете сделать это в своем браузере, то увидите, что некоторое время уходит на эффект анимации каталога песен при прокрутке. Если вы попробуете переписать переменные композиций перед окончанием анимации, то можете получить не все треки, или получить те, которые вам не нужны.

Решение? Вы можете просто заснуть на секунду, или, если вы проделываете работу в оболочке Python, вы, вероятно, даже не заметите этого – в конце концов, на набор данных также уходит время.

Еще один небольшой момент, который можно обнаружить только путем проб и ошибок. Попробуйте запустить такой же код еще раз:

Вы обнаружите кое-что странное. len(tracks) не равен 8, даже если пачка состоит из восьми треков. Углубившись, вы обнаружите, что ваш список состоит из треков, которые были показаны ранее. Чтобы получить треки, которые будут видны в браузере, нужно сделать небольшую фильтрацию результатов.

Попробовав несколько вариантов, вы решите оставить трек, только если его координата х на странице попадают в определенные рамки содержимого элемента. Контейнер каталога имеет значение класса «discover-results«. Выполним следующее:

7. Создание класса

Если вас утомляет переписывать одни и те же команды снова и снова в пространстве Python, вам нужно выгрузить часть из них в модуль. Простейший класс для вашей работы с bandcamp должен выполнять следующие задачи:

  1. Инициализация headless браузера и выполнить направление на bandcamp;
  2. Хранение списка доступных треков;
  3. Поддержка поиска треков;
  4. Воспроизведение, пауза, переключение треков;

Четыре в одном. Вот простой код:

Весьма удобно. Вы можете импортировать этот код в ваше пространство Python и запустить bandcamp! Но постойте, разве мы не затеяли это все потому, что нам нужно собирать информацию о вашей истории прослушиваний?

8. Собираем структурированные данные

Наша последняя с вами задача, это отслеживать прослушанные вами треки. Как нам это сделать? Что буквально означает слушать что-либо? Если вы пролистываете каталог, переключая треки спустя пару секунд, это считается за прослушивание песни? Скорее всего, нет. Нам нужно включить фактор длительности прослушивания в сбор данных.

Сейчас нам нужно:

  1. Собрать структурированную информацию о воспроизводимых композициях;
  2. Хранить базу данных треков;
  3. Сохранить и восстановить эту базу данных на диск и из диска.

Используем namedtuple для сортировки отслеживаемой вами информации. Кортежи с названиями хороши для показа связки атрибутов без привязки к ним. Это немного похоже на запись базы данных.

Чтобы собрать эту информацию, добавьте метод в класс BandLeader. Проверка при помощи инструментов разработки браузера откроет необходимые элементы HTML и атрибуты для выбора всей необходимой информации. Кстати, вам понадобится только информация о недавно прослушанных треках, если в это время музыка воспроизводилась. К счастью, страница плеера добавляет класс «playing» к кнопке воспроизведения, когда музыка играет, и убирает его, когда воспроизведение прекращается. Держа в голове данные нюансы, нужно прописать несколько методов:

Для точного измерения, можно также модифицировать метод play для продолжения отслеживания играющего в данный момент трека:

Далее, нам нужно создать какую-либо базу данных. Хотя она может плохо масштабироваться при больших объемах, в простом списке все должно пройти хорошо.

Добавляем строку:

В методе инициализации класса BandCamp __init__ . Так как нам нужно дать возможность тому, чтобы прошло определенное время перед входом в объект TrackRec в базе данных, мы используем инструменты threading нашего Python, для запуска отдельных процессов, которые поддерживают базу данных в фоновом режиме.

Мы привяжем метод _maintain() к экземплярам BandLeader, которые запустят раздельный поток. Новый метод будет периодически проверять значение self._current_track_record и добавлять его в базу данных, если это новый трек.

Мы запустим поток, когда класс станет подтвержденным, путем добавления кода в __init__.

Если вы никогда не работали с мультипоточным программированием в Python, вы должны с этим ознакомиться! Для нашей нынешней цели, вы можете представить потоки как цикл, который возвращает фоновый режим основного процесса Python (тот, с которым вы напрямую взаимодействуете). Каждые двадцать секунд цикл выполняет небольшую проверку, чтобы увидеть, нужно ли обновить базу данных. Если нужно, он добавляет новую запись. Вполне себе круто.

Самым последним будет сохранение базы данных и восстановление из сохраненных состояний. Используя модуль csv, вы гарантированно будете хранить свою базу данных в очень портативном формате, кроме этого, базу данных можно будет использовать, даже если вы покинете ваш чудесный класс BandLeader ;)

Метод __init__ снова нужно изменить, на этот раз, для принятия пути файла, в котором вы хотите сохранить базу данных. Вам может понадобиться загрузить эту базу данных, если она доступна, и периодически её сохранять, когда она будет обновлена. Обновления выглядят следующим образом:

Ву а ля! Вы можете слушать музыку и хранить запись прослушанных треков. Великолепно.

Кое-что интересное показанном выше коде: использование namedtuple действительно начинает окупаться. При конвертации из формата CSV , вы получаете возможность упорядочивать строки в файле CSV для заполнения строк в объектах TrackRec. Также вы можете создать заглавную строку файла CSV, ссылаясь на атрибут TrackRec._fields. Это одна из причин, по которой использование кортежа имеет смысл во время работы со столбчатыми данными.

Что дальше и чему мы научились?

С этого момента вы умеете делать намного больше! Вот несколько идей, навскидку, которые можно реализовать при помощи суперсилы связки Python + Selenium:

  • Вы можете расширить класс BandLeader для навигации по страницам альбомов и воспроизводить найденные в них треки;
  • Вы можете создать плейлист на основании своих любимых и наиболее часто прослушиваемых композиций;
  • Возможно, вы захотите добавить функцию автоматического воспроизведения;
  • Может быть, вам захочется запросить песни по дате, названию или артисту и составить таким образом плейлист.

Здесь вы можете скачать основы проектов «Python + Selenium» со всеми исходными кодами, которые вы можете использовать как фундамент для веб-парсинга и автоматизации приложений.

Вы узнали, что Python может делать то же самое, что и веб-браузер, и даже больше. Вы можете легко прописывать скрипты для контроля экземпляров виртуального браузера, работающего в облаке, создавать ботов, которые могут взаимодействовать с реальными пользователями, или просто заполняют формы! Развивайтесь и автоматизируйте!