{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python для сбора и анализа данных\n", "\n", "*Алла Тамбовцева, НИУ ВШЭ*\n", "\n", "## Управление браузером с помощью Selenium и BeautifulSoup" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Библиотека `selenium` – набор инструментов для интерактивной работы в браузере средствами Python. В широком смысле Selenium – это целый проект, который предлагает различные возможности для управления браузером с использованием популярных языков программирования (Python, Java, R и другие). \n", "\n", "Мы рассмотрим один из самых распространённых инструментов – *Selenium WebDriver*, модуль, который позволяет Python встраиваться в браузер и имитировать в нём работу пользователя: кликать на ссылки и кнопки, заполнять формы, выбирать опции в меню, скроллить страницы и прочее.\n", "\n", "Для начала установим библиотеку:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install selenium" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь скачаем драйвер для браузера в виде архива ([файлы](https://chromedriver.chromium.org/downloads) для Chrome, [файлы](https://github.com/mozilla/geckodriver/releases/) для Firefox). Этот драйвер нужен для того, чтобы Python получил доступ к браузеру и мог открыть в нём новое окно, управляемое автоматически. \n", "\n", "После скачивания архив необходимо распаковать и запомнить, где лежит файл с драйвером (`chromedriver.exe` на Windows, `chromedriver` на Mac). Сам файл с драйвером открывать/запускать не нужно\n", "\n", "Обратите внимание: версия драйвера должна совпадать с версией браузера!\n", "\n", "Импортируем из `selenium` модуль `webdriver` с сокращённым названием:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from selenium import webdriver as wd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если используете драйвер для Chrome, необходимо прописать путь к файлу с драйвером внутри функции `Chrome()`:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# пример для Mac\n", "\n", "br = wd.Chrome('/Users/allat/Downloads/chromedriver')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# пример для Windows\n", "\n", "br = wb.Chrome(r'C:\\\\Users\\\\allat\\\\Downloads\\\\chromedriver.exe')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если используете драйвер для Mozilla Firefox, можно ничего не прописывать, функция `Firefox()` сама поймет, где найти `geckodriver`:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если на Mac файл с драйвером упорно не хочет подсоединяться к Python, попробуйте выполнить действия в инструкции на странице курса (это займет некоторое время). \n", "\n", "После запуска строки кода выше в новом окне браузера открывается пустая страница. На эту страницу мы можем отправить ссылку на сайт и открыть его. Зайдём на сайт «Библио-глобуса»:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "br.get(\"http://www.biblio-globus.ru/\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Чтобы выполнить поиск в каталоге, нам нужно ввести запрос в поле поиска. Найдём это поле! Обратимся к исходному коду страницы и заметим, что поле для ввода запроса имеет атрибут `id` равный `search_string` (искать по id – самый надёжный способ, так как id всегда уникальный). Попросим `selenium` запомнить это поле:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# find_element_by_ – набор методов \n", "# для поиска по id, тэгам, классам и проч\n", "\n", "search = br.find_element_by_id(\"search_string\") " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А теперь введём в это поле слово *Python*, используя метод `.send_keys()`:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "search.send_keys(\"Python\") " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Отлично! В окне браузера должны были отразиться изменения. Осталось найти кнопку для поиска и кликнуть на неё. Опять вернёмся к изучению исходного кода страницы:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "button = br.find_element_by_id(\"search_submit\") # снова id\n", "button.click() " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python в браузере кликнул на кнопку, теперь там должен быть список книг по запросу *Python*. Для того, чтобы собрать информацию по книгам с первой страницы результатов, `selenium` не понадобится, достаточно задействовать знакомый `BeautifulSoup`. Однако для дальнейшей работы нам будет нужен исходный код страницы, которая открыта в браузере в данный момент. Извлечём его:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "html = br.page_source" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь импортируем `BeautifulSoup` и обработаем исходный код HTML:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "from bs4 import BeautifulSoup\n", "soup = BeautifulSoup(html) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Выгрузим основную информацию о книгах: название, ссылку, авторов, расположение в магазине и цену. Обратите внимание – информация по каждой книге находится в разделах с атрибутом `class` равным `details_1`. Найдём все такие блоки информации:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "books = soup.find_all(\"div\", {\"class\" : \"details_1\"})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь поработаем с одним из них. " ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "
\n", " | 0 | \n", "1 | \n", "2 | \n", "3 | \n", "4 | \n", "
---|---|---|---|---|---|
0 | \n", "Криволапов С.Я. | \n", "/search/catalog/details/10835402 | \n", "Математика на Python. (Бакалавриат). Учебник. | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "1639 | \n", "
1 | \n", "Криволапов С.Я. | \n", "/search/catalog/details/10835400 | \n", "Статистические вычисления на платформе Jupyter... | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "1499 | \n", "
2 | \n", "М. Лутц | \n", "/search/catalog/details/10597875 | \n", "Изучаем Python, том 1 | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "2849 | \n", "
3 | \n", "Кольцов Д.М. | \n", "/search/catalog/details/10829190 | \n", "Python. Полное руководство | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "909 | \n", "
4 | \n", "Н. Гифт, К. Берман, А. Деза, Г. Георгиу | \n", "/search/catalog/details/10814639 | \n", "Python и DevOps: Ключ к автоматизации Linux | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "2529 | \n", "
5 | \n", "Д. М. Кольцов , Е. В. Дубовик | \n", "/search/catalog/details/10776656 | \n", "Справочник PYTHON. Кратко, быстро, под рукой | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "499 | \n", "
6 | \n", "М. Яворски , Т. Зиаде | \n", "/search/catalog/details/10766703 | \n", "Python. Лучшие практики и инструменты | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "2759 | \n", "
7 | \n", "Б. Любанович | \n", "/search/catalog/details/10736311 | \n", "Простой Python. Современный стиль программиров... | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "2019 | \n", "
8 | \n", "М.Лутц | \n", "/search/catalog/details/10632642 | \n", "Изучаем Python, том 2, | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "2849 | \n", "
9 | \n", "Л.Грессер,В.Кенг | \n", "/search/catalog/details/10831874 | \n", "Глубокое обучение с подкреплением: теория и пр... | \n", "Расположение в торговом зале: Уровень 1, зал №... | \n", "2509 | \n", "