Скрапинг сайта с помощью Python: гайд для новичков
Пишем простой скрапер на Python для сайта с объявлениями о недвижимости. Получаем готовый очищенный готовый к экспорту датасет.
76К открытий84К показов
В этой статье мы разберемся, как создать HTML скрапер на Python, который получает неофициальный доступ к коду сайта и позволяет извлечь необходимые данные.
Отличие от вызовов API
Альтернативный метод получения данных сайта — вызовы API. Взаимодействие с API — это официально предоставляемый владельцем сайта способ получения данных прямо из БД или обычных файлов. Обычно для этого требуется разрешение владельца сайта и специальный токен. Однако апи доступен не всегда, поэтому скрапинг так привлекателен, однако его законность вызывает вопросы.
Юридические соображения
Скрапинг может нарушать копирайт или правила использования сайта, особенно когда он используется для получения прибыли, конкурентного преимущества или причинения ущерба (например из-за слишком частых запросов). Однако скрапинг публично доступен и используется для личного использования, академических целей или безвредного некоммерческого использования.
Если данные являются платными, требуют регистрации, имеют явную защиту от скрапинга, содержат конфиденциальные данные или личные данные пользователей, то нужно избегать любого из видов скрапинга.
Установка Beautiful Soup в Python
Beautiful Soup — это Python библиотека для скрапинга данных сайтов через HTML код.
Установите последнюю версию библиотеки.
Чтобы делать запросы, установите requests (библиотеку для отправки HTTP запросов):
Импортируйте библиотеки в файле Python или Jupiter notebook:
И несколько стандартных библиотек, которые потребуются для скрапинга на Python:
Введение
Представьте, что мы хотим произвести скрапинг платформы, содержащей общедоступные объявления о недвижимости. Мы хотим получить цену недвижимости, ее адрес, расстояние, название станции и ближайший до нее тип транспорта для того, чтобы узнать, как цены на недвижимость распределяются в зависимости от доступности общественного транспорта в конкретном городе.
Предположим, что запрос приведет к странице результатов, которая выглядит следующим образом:
Как только мы узнаем, в каких элементах сайта хранятся необходимые данные, нам нужно придумать логику скрапинга, которая позволит нам получить всю нужную информацию из каждого объявления.
Нам предстоит ответить на следующие вопросы:
- Как получить одну точку данных для одного свойства (например данные из тега price в первом объявлении)?
- Как получить все точки данных для одного свойства со всей страницы (например все теги price с одной страницы)?
- Как получить все точки данных для одного свойства всех страниц с результатами (например все теги price со всех страниц с результатами)?
- Как устранить несоответствие, когда данные могут быть разных типов (например, есть некоторые объявления, в которых в поле цены указана цена по запросу. В конечном итоге у нас будет столбец, состоящий из числовых и строковых значений, что в нашем случае не позволяет провести анализ)?
- Как лучше извлечь сложную информацию (Например, предположим, что каждое объявление содержит информацию об общественном транспорте, например “0,5 мили до станции метро XY”)?
Логика получения одной точки данных
Все примеры кода для скрапинга на Python можно найти в Jupiter Notebook файле на GitHub автора.
Запрос кода сайта
Во-первых, мы используем поисковый запрос, который мы сделали в браузере в скрипте Python:
Переменная soup содержит полный HTML-код страницы с результатами поиска.
Поиск тегов-свойств
Для этого нам потребуется браузер. Некоторые популярные браузеры предлагают удобный способ получения информации о конкретном элементе напрямую. В Google Chrome вы можете выбрать любой элемент сайта и, нажав правой кнопкой, выбрать пункт “Исследовать элемент” . Справа откроется код сайта с выделенным элементом.
HTML классы и атрибут id
HTML-классы и id в основном используются для ссылки на класс в таблице стилей CSS, чтобы данные могли отображаться согласованным образом.
В приведенном выше примере, класс, используемый для получения информации о ценах из одного объявления, также применяется для получения цен из других объявлений (что соответствует основной цели класса).
Обратите внимание, что HTML-класс также может ссылаться на ценники за пределами раздела объявлений (например, специальные предложения, которые не связаны с поисковым запросом, но все равно отображаются на странице результатов). Однако для целей этой статьи мы фокусируемся только на ценах в объявлениях о недвижимости.
Вот почему мы сначала ориентируемся на объявление и ищем HTML-класс только в исходном коде для конкретного объявления:
Использование .text в конце метода find() позволяет нам возвращать только обычный текст, как показано в браузере. Без .text он вернет весь исходный код строки HTML, на которую ссылается класс:
Важное примечание: нам всегда нужно указывать элемент, в данном случае это p.
Логика получения всех точек данных с одной страницы
Чтобы получить ценники для всех объявлений, мы применяем метод find.all() вместо find():
Переменная ads теперь содержит HTML-код для каждого объявления на первой странице результатов в виде списка списков. Этот формат хранения очень полезен, так как он позволяет получить доступ к исходному коду для конкретных объявлений по индексу.
Чтобы получить все ценники, мы используем словарь для сбора данных:
Важное примечание: использование идентификатора позволяет находить объявления в словаре:
Получение точек данных со всех страниц
Обычно результаты поиска либо разбиваются на страницы, либо бесконечно прокручиваются вниз.
Вариант 1. Веб-сайт с пагинацией
URL-адреса, полученные в результате поискового запроса, обычно содержат информацию о текущем номере страницы.
Важное примечание: номер страницы в URL-адресе обычно становится видимым со второй страницы. Использование базового URL-адреса с дополнительным фрагментом &pn=1 для вызова первой страницы по-прежнему будет работать (в большинстве случаев).
Применение одного цикла for-loop поверх другого позволяет нам перебирать страницы результатов:
Определение последней страницы результатов
Вы можете задаться вопросом, как определить последнюю страницу результатов? В большинстве случаев после достижения последней страницы, любой запрос с большим числом, чем фактическое число последней страницы, приведет нас обратно на первую страницу. Следовательно, использование очень большого числа для ожидания завершения сценария не работает. Через некоторое время он начнет собирать повторяющиеся значения.
Чтобы решить эту проблему, мы будем проверять, есть ли на странице кнопка с такой ссылкой:
Вариант 2. Сайт с бесконечным скроллом
В таком случае HTML скрапер не сработает. Альтернативные методы мы обсудим в конце статьи.
Устранение несогласованности данных
Если нам нужно избавиться от ненужных данных в самом начале скрапинга на Python, мы можем использовать обходной метод:
Функция для определения аномалий
И применить его при сборе данных:
Форматирование данных на лету
Мы могли заметить, что цена хранится в строке вместе с запятыми с символом валюты. Мы можем исправить это ещё на этапе скрапинга:
Используем эту функцию:
Получение вложенных данных
Информация об общественном транспорте имеет вложенную структуру. Нам потребуются данные о расстоянии, названии станции и типе транспорта.
Отбор информации по правилам
Каждый кусочек данных представлен в виде: число миль, название станции. Используем слово “миль” в качестве разделителя.
Первоначально переменная transport хранит два списка в списке, поскольку есть две строки информации об общественном транспорте (например, “0,3 мили Слоун-сквер”, “0,5 мили Южный Кенсингтон”). Мы перебираем эти списки, используя len транспорта в качестве значений индекса, и разделяем каждую строку на две переменные: расстояние и станцию.
Поиск дополнительных HTML атрибутов для визуальной информации
В коде страницы мы можем найти атрибут testid, который указывает на тип общественного транспорта. Он не отображается в браузере, но отвечает за изображение, которое отображается на странице. Для получения этих данных нам нужно использовать класс css-StyledIcon:
Преобразование в датафрейм и экспорт в CSV
Когда скрапинг выполнен, все извлеченные данные доступны в словаре словарей.
Давайте сначала рассмотрим только одно объявление, чтобы лучше продемонстрировать заключительные шаги трансформации.
Преобразуем словарь в список списков, чтобы избавиться от вложенности
Создаём датафрейм
Мы можем экспортировать датафрейм в CSV:
Преобразование всех объявлений в датафрейм:
Мы это сделали! Теперь наш скрапер готов к тестированию.
Ограничения HTML скрапинга и его альтернативы
Этот пример показывает, насколько простым может быть скрапинг HTML на Python в стандартном случае. Для этого не нужно исследовать документацию. Это требует, скорее, творческого мышления, чем опыта веб-разработки.
Однако HTML скраперы имеют недостатки:
- Можно получить доступ только к информации в HTML-коде, которая загружается непосредственно при вызове URL-адреса. Веб-сайты, которые требуют JavaScript и Ajax для загрузки контента, не будут работать.
- HTML-классы или идентификаторы могут изменяться в связи с обновлениями веб-сайта.
- Может быть легко обнаружен, если запросы кажутся аномальными для веб-сайта (например, очень большое количество запросов в течение короткого промежутка времени).
Альтернативы:
- Shell скрипты — загружают всю страницу, с помощью регулярных выражений могут обрабатывать html.
- Screen scraper — изображают реального пользователя, используют браузер (Selenium, PhantomJS).
- ПО для скрапинга — рассчитаны на стандартные случаи, не требуют написания кода (webscraper.io).
- Веб сервисы скраперы — не требуют написания кода, хорошо справляются со скрапингом, платные (zyte.com).
Здесь вы найдёте список инструментов и библиотек для скрапинга.
76К открытий84К показов