Учебное пособие по парсингу сайтов на Python

Изучение
Предположим, вы хотите получить информацию с веб-сайта? Скажем, статья с сайта geeksforgeeks или новость, что вы будете делать? Первое, что может прийти вам в голову, — это скопировать и вставить информацию на ваш местный носитель. Но что, если вам нужен большой объем данных ежедневно и как можно быстрее. В таких ситуациях копирование и вставка не работают, и именно здесь вам понадобится веб-скрейпинг.
В этой статье мы обсудим, как выполнять парсинг веб-страниц с помощью библиотеки запросов и библиотеки beautifulsoup в Python.
Модуль запросов
Библиотека запросов используется для выполнения HTTP-запросов к определенному URL-адресу и возвращает ответ. Запросы Python предоставляют встроенные функции для управления как запросом, так и ответом.
Установка
Установка запросов зависит от типа операционной системы, основная команда в любом месте — открыть командный терминал и запустить,
Сделать запрос
Модуль запросов Python имеет несколько встроенных методов для выполнения HTTP-запросов к указанному URI с использованием запросов GET, POST, PUT, PATCH или HEAD. HTTP-запрос предназначен либо для получения данных из указанного URI, либо для отправки данных на сервер. Он работает как протокол запроса-ответа между клиентом и сервером. Здесь мы будем использовать запрос GET.
Метод GET используется для получения информации с заданного сервера с использованием заданного URI. Метод GET отправляет закодированную информацию о пользователе, добавленную к запросу страницы.
Пример: запросы Python, выполняющие запрос GET

Объект ответа
Когда кто-то делает запрос к URI, он возвращает ответ. Этот объект Response в терминах python возвращается с помощью request.method (), являющегося методом — get, post, put и т.д. Response — это мощный объект с множеством функций и атрибутов, которые помогают в нормализации данных или создании идеальных частей кода. Например, response.status_code возвращает код состояния из самих заголовков, и можно проверить, был ли запрос обработан успешно или нет.
Объекты ответа могут использоваться для обозначения множества функций, методов и функций.
Пример: Python запрашивает объект ответа
Библиотека BeautifulSoup
BeautifulSoup используется для извлечения информации из файлов HTML и XML. Он предоставляет дерево синтаксического анализа и функции для навигации, поиска или изменения этого дерева синтаксического анализа.
Установка
Чтобы установить Beautifulsoup в Windows, Linux или любой другой операционной системе, потребуется пакет pip. Чтобы узнать, как установить pip в вашей операционной системе, посмотрите — Установка PIP — Windows || Linux. Теперь запустите следующую команду в терминале.
Проверка веб-сайта
Прежде чем извлекать какую-либо информацию из HTML страницы, мы должны понять структуру страницы. Это нужно сделать для того, чтобы выделить нужные данные со всей страницы. Мы можем сделать это, щелкнув правой кнопкой мыши страницу, которую мы хотим очистить, и выбрав элемент проверки.

После нажатия кнопки проверки откроются инструменты разработчика браузера. Теперь почти все браузеры поставляются с установленными инструментами разработчика, и в этом руководстве мы будем использовать Chrome.

Инструменты разработчика позволяют увидеть объектную модель документа (DOM) сайта. Если вы не знаете о DOM, не беспокойтесь, просто рассмотрите отображаемый текст как HTML-структуру страницы.
Разбор HTML
После получения HTML-кода страницы давайте посмотрим, как проанализировать этот необработанный HTML-код и получить полезную информацию. Прежде всего, мы создадим объект BeautifulSoup, указав парсер, который мы хотим использовать.
Примечание. Библиотека BeautifulSoup построена на основе библиотек синтаксического анализа HTML, таких как html5lib, lxml, html.parser и т. Д. Таким образом, объект BeautifulSoup и указанная библиотека синтаксического анализатора могут быть созданы одновременно.
Пример: Python BeautifulSoup анализирует HTML

Эта информация для нас все еще не полезна, давайте посмотрим на другой пример, чтобы сделать из этого некоторую ясную картину. Попробуем извлечь заголовок страницы.
Поиск элементов
Теперь мы хотели бы извлечь некоторые полезные данные из содержимого HTML. Объект soup содержит все данные во вложенной структуре, которые могут быть извлечены программно. Веб-сайт, который мы хотим очистить, содержит много текста, поэтому теперь давайте очистим весь этот контент. Во-первых, давайте проверим веб-страницу, которую мы хотим очистить.

Поиск элементов по классу
На изображении выше мы видим, что все содержимое страницы находится под блоком div с классом entry-content. Мы будем использовать класс find. Этот класс найдет данный тег с данным атрибутом. В нашем случае он найдет весь div, имеющий class как entry-content. У нас есть весь контент с сайта, но вы можете видеть, что все изображения и ссылки также очищены. Итак, наша следующая задача — найти только контент из проанализированного выше HTML. При повторном просмотре HTML-кода нашего веб-сайта —

Мы видим, что содержимое страницы находится под тегом <p>. Теперь нам нужно найти все теги p, присутствующие в этом классе. Мы можем использовать класс find_all в BeautifulSoup.
Веб-парсинг на Python
Веб-парсинг на Python – это гораздо больше, чем просто извлечение контента с помощью селекторов CSS. Благодаря приемам и идеям из этой статьи вы сможете более надежно, быстро и эффективно собирать данные.
Начинаем
Сперва установите все необходимые библиотеки, запустив pip install.
Получить HTML-код из URL-адреса мы можем при помощи библиотеки requests . Затем контент передается в BeautifulSoup, после чего можно начать получать данные и делать запросы с помощью селекторов. В детали вдаваться мы не будем, лишь скажем, что селекторы CSS используются для получения отдельных элементов и содержимого страницы. Синтаксис при этом бывает разный, но это мы рассмотрим позже.
Чтобы не запрашивать HTML каждый раз, мы можем сохранить его в HTML-файле и уже оттуда загружать BeautifulSoup. Чисто для демонстрации давайте сделаем это вручную. Самый простой способ – это просмотреть исходный код страницы, скопировать и вставить его в файл. Важно посетить страницу без входа в систему, как это сделал бы поисковый робот.
Получение HTML-кода может показаться простой задачей, но это далеко не так. Вообще эта тема тянет на отдельную полноценную статью, так что здесь мы затронем ее лишь вскользь. Мы советуем использовать статический подход из примера ниже, поскольку многие сайты после нескольких запросов начнут перенаправлять вас на страницу входа. Некоторые покажут капчу, и в худшем случае ваш IP будет забанен.
После статической загрузки из файла мы сможем делать сколько угодно попыток запросов, не имея проблем проблем с сетью и не опасаясь блокировки.
Изучите сайт перед тем, как начать писать код
Прежде чем начать писать программу, нужно понять содержание и структуру страницы. Это можно сделать довольно просто при помощи браузера. Мы будем использовать DevTools Chrome, но в других браузерах есть аналогичные инструменты.
Например, мы можем открыть любую страницу продукта на Amazon. Беглый просмотр покажет нам название продукта, цену, доступность и многие другие поля. Перед копированием всех этих селекторов мы рекомендуем потратить пару минут на поиск скрытых входных данных, метаданных и сетевых запросов.
Пользуясь Chrome DevTools или аналогичными инструментами, проявляйте осторожность. Контент, который вы увидите, возможно, был изменен в результате работы JavaScript и сетевых запросов. Да, это утомительно, но иногда нужно исследовать исходный HTML, чтобы избежать запуска JavaScript.
Дисклеймер: мы не будем включать URL-запрос в фрагменты кода для каждого примера. Все они похожи на первый. И помните: сохраняйте HTML-файл локально, если собираетесь протестировать его несколько раз.
Скрытые инпуты
Скрытые инпуты позволяют разработчикам включать поля ввода, которые конечные пользователи не могут видеть или изменять. Многие формы используют их для включения внутренних идентификаторов или токенов безопасности.
В продуктах Amazon мы видим, что их довольно много. Некоторые из них будут доступны в других местах или форматах, но иногда они уникальны. В любом случае имена скрытых инпутов обычно более стабильны, чем имена классов.

Метаданные
Хотя некоторый контент отображается через пользовательский интерфейс, его может быть проще извлечь с помощью метаданных. Например, можно получить количество просмотров в числовом формате и дату публикации в формате ГГГГ-ММ-ДД для видео на YouTube. Да, эти данные можно увидеть на сайте, но их можно получить и с помощью всего пары строк кода. Несколько минут на написание кода точно окупятся.
XHR-запросы
Некоторые сайты загружают пустой шаблон и вставляют в него все данные через XHR-запросы. В таких случаях проверки исходного HTML будет недостаточно. Нам нужно исследовать сеть, в частности XHR-запросы.
Возьмем, к примеру, Auction. Заполните форму с любым городом и выполните поиск. Вы будете перенаправлены на страницу результатов, которая, пока выполняются запросы для введенного вами города, представляет собой страницу-каркас.
Это вынуждает нас использовать headless-браузер, который может выполнять JavaScript и перехватывать сетевые запросы. Иногда вы можете вызвать конечную точку XHR напрямую, но обычно для этого требуются файлы cookie или другие методы аутентификации. Или вас могут немедленно забанить, поскольку это не обычный путь пользователя. Будьте осторожны.

Мы наткнулись на золотую жилу! Взгляните еще раз на изображение.
Все возможные данные, уже очищенные и отформатированные, готовы к извлечению. А также геолокация, внутренние идентификаторы, цена в числовом виде без форматирования, год постройки и т. д.
Рецепты и хитрости для извлечения надежного контента
Уймите свой пыл ненадолго. Получить все с помощью селекторов CSS – это вариант, но есть еще множество других опций. Давайте рассмотрим больше инструментов и идей. Тогда вы сможете самостоятельно принимать решения, зная обо всех альтернативах.
Получение внутренних ссылок
Теперь мы начнем использовать BeautifulSoup для получения значимого контента. Эта библиотека позволяет нам получать контент по идентификаторам, классам, псевдоселекторам и т.д. Мы рассмотрим лишь небольшую часть ее возможностей.
В этом примере со страницы будут извлечены все внутренние ссылки. Упростим себе задачу и будем считать внутренними только ссылки, начинающиеся с косой черты. В более полном варианте следует проверить домен и поддомены.
Получив все эти ссылки, мы можем убрать дубликаты и поставить их в очередь для последующего парсинга. Поступая таким образом, мы могли бы создать поискового робота для всего сайта, а не только для одной страницы. Однако это уже совсем другая тема, ведь количество страниц для сканирования может увеличиваться, как снежный ком.

Английский для программистов
Наш телеграм канал с тестами по английскому языку для программистов. Английский это часть карьеры программиста. Поэтому полезно заняться им уже сейчас
Будьте осторожны, выполняя это автоматически. Вы можете получить сотни ссылок за несколько секунд, что приведет к слишком большому количеству запросов к одному и тому же сайту. При неосторожном обращении можно нарваться на капчу или бан.
Извлечение ссылок на социальные сети и электронную почту
Другой распространенной задачей парсинга является извлечение ссылок на соцсети и email-адресов. Точного определения для «ссылок на соцсети» нет, поэтому мы будем получать их, основываясь на домене. Что касается email-адресов, то здесь есть два варианта: ссылки «mailto» и проверка всего текста.
Для примера мы будем использовать тестовый сайт.
Для начала получим все ссылки, как в предыдущем примере. Затем переберем их, проверяя, есть ли среди них домены соцсетей или «mailto». Если да, добавим такие URL-адреса в список и выведем конечный список на экран.
Эту задачу можно решить и с помощью регулярных выражений. Конечно, если вы не дружите с regexp, это немного сложнее. Основная идея в том, что мы ищем совпадение текста с заданным паттерном.
В нашем случае паттерн — некоторое количество символов (в основном, букв и цифр), за которым идет знак @, а затем опять символы (домен), точка и еще от двух до четырех символов (домен верхнего уровня. Этому паттерну будет соответствовать, например, test@example.com.
Обратите внимание, что этот паттерн несовершенен: он не учитывает составные домены верхнего уровня, такие как co.uk.
Наше регулярное выражение можно запустить для всего контента (HTML) или только для текста. Мы используем HTML, хотя при этом полученные email-адреса будут дублироваться (они есть и в тексте, и в href).
Автоматический парсинг таблиц
HTML-таблицы все еще широко применяются на сайтах. Мы можем воспользоваться этим, поскольку они обычно структурированы и хорошо отформатированы.
Используя в качестве примера список самых продаваемых альбомов из Википедии, мы извлечем все значения в датафрейм pandas. Это простой пример, но со всеми данными нужно обращаться так, как если бы они были получены из набора данных.
Мы начинаем с поиска таблицы и перебора всех строк tr . Для каждой из них мы ищем ячейки td или th . Дальше удаляем заметки и сворачиваемое содержимое из таблиц (необязательный шаг). Затем добавляем вырезанный текст ячейки в строку и строку — в окончательный вывод.
Другой способ – использовать pandas и напрямую импортировать HTML, как показано ниже. При таком подходе все будет сделано за нас: первая строка будет соответствовать заголовкам, а остальные будут вставлены как контент с правильным типом. read_html() возвращает массив, поэтому мы берем первый элемент, а затем удаляем столбец, у которого нет содержимого.
Попав в датафрейм, мы можем выполнить любую операцию. Например — упорядочить по продажам, поскольку pandas преобразовала некоторые столбцы в числа. Или вывести сумму продаж. Здесь это не очень полезно, но идея понятна.
Извлечение информации не из HTML, а из метаданных
Как было замечено ранее, есть способы получить важные данные, не полагаясь на визуальный контент. Давайте рассмотрим пример с «Ведьмаком» от Netflix. Мы попробуем получить список актеров. Легко, правда?
Что, если бы мы сказали вам, что актеров и актрис четырнадцать? Вы попытаетесь получить все имена? Не прокручивайте дальше, если хотите попробовать самостоятельно.
Помните: актеров больше, чем кажется на первый взгляд. Вы знаете троих – поищите их в исходном HTML. Честно говоря, внизу есть еще одно место, где показан весь состав, но постарайтесь его избегать.
Netflix включает фрагмент Schema.org со списком актеров и актрис и многими другими данными. Как и в примере с YouTube, иногда удобнее использовать этот подход. Например, даты обычно отображаются в «машинном» формате, который более удобен при парсинге.

Разберем следующий пример, используя Instagram-профиль Билли Айлиш. После посещения нескольких страниц вы будете перенаправлены на страницу входа. Будьте осторожны при парсинге Instagram и используйте для тестирования локальный HTML-код.
Обычным подходом будет поиск класса, в нашем случае — Y8-fY . Мы не рекомендуем использовать эти классы, поскольку они, вероятно, изменятся. Судя по виду, они созданы автоматически. Многие современные веб-сайты используют подобный CSS, который генерируется при каждом изменении. Для нас это означает, что мы не можем полагаться на эти классы.
План Б: header ul > li , верно? Это сработает. Но для этого нам нужен рендеринг JavaScript, поскольку он отсутствует при первой загрузке. А как было сказано ранее, этого следует избегать.
Взгляните на исходный HTML. Заголовок и описание включают подписчиков, подписки и количество постов. Это может быть проблемой, поскольку они имеют строковый формат, но мы можем с этим справиться. Если мы хотим только эти данные, нам не понадобится headless-браузер. Отлично!
Скрытая информация о продукте в онлайн-магазине
Комбинируя некоторые из уже рассмотренных методов, мы хотим извлечь невидимую информацию о продукте. Наш первый пример — это eCommerce-магазин Shopify – Spigen.
Мы сможем извлечь требуемые данные наверняка: не из имени продукта и не из «хлебных крошек», поскольку мы не можем быть уверены в их надежности.

В данном случае они используют itemprop и включают Product и Offer со schema.org. Вероятно, мы могли бы определить, есть ли товар на складе, просмотрев форму или кнопку «Add to cart». Но в этом нет необходимости, мы можем доверять itemprop = «availability» . Что касается бренда, то мы можем использовать тот же сниппет кода, что и для YouTube, но с изменением имени свойства на «brand».
Другой пример со Shopify: nomz. Мы хотим извлечь количество оценок и среднее значение, доступные в HTML. Однако средняя оценка скрыта от просмотра с помощью CSS.
Здесь есть тег, поставленный исключительно для скринридеров, рядом с которым расположены средняя оценка и счетчик. Последние включают текст, что не является проблемой. Но мы можем добиться большего.
Это несложно, если вы изучите исходный код. Схема продукта будет первым, что вы увидите. Применяя то, чему вы научились на примере с Netflix, получите первый блок «ld + json», проанализируйте JSON, и весь контент будет доступен!
И последнее. Мы воспользуемся атрибутами данных, которые также распространены в eCommerce. Просматривая страницу с бейсбольными битами онлайн-магазина Marucci Sports, мы видим, что у каждого продукта есть несколько полезных точек данных. Цена в числовом формате, идентификатор, название продукта и категория. У нас есть все данные, которые нам могут понадобиться.
Отлично! Мы получили все данные с этой страницы. Теперь нужно проделать это со второй, а затем с третьей. Действуя постепенно, мы с большей вероятностью не нарвемся на бан.
Не забудьте преобразовать эти данные и сохранить их в CSV-файлах или в базе данных. Вложенные поля непросто экспортировать ни в один из этих форматов.
Итоги
Сегодня мы поговорили о веб-парсинге на Python. Нам бы хотелось, чтобы вы усвоили три урока:
Туториал по библиотеке BeautifulSoup4
Парсеры — это программы, которые скачивают из интернета странички и разбирают их на составляющие: заголовок, картинка, текст… С помощью него можно выкачать с сайта гигабайты полезной информации. Библиотека BeautifulSoup4 как раз предназначена для парсинга.
В этой статье вы узнаете как распарсить сайт Франка Сонненберга. Цель: по ссылке на пост вытащить его название, текст и картинку.
Франк Сонненберг — известный американский писатель и коуч. За свои книги он попал в “Топ 100 Американских мыслителей”, а его блог принадлежит списку “Лучшие блоги о лидерстве 21 века”.
Прежде чем начинать…
Для прохождения этого туториала вам понадобятся 3 библиотеки:
Получить страничку поста
Будем парсить пост “Are You Grateful?”. Чтобы распарсить HTML-страничку с постом, сначала нужно её скачать. Это можно сделать с помощью requests , вот статья об этой библиотеке.
Здесь мы просто сделали запрос по ссылке и получили в ответ огромный HTML. Начинаться он будет примерно так:
Парсинг поста
У вас есть HTML страничка, но как достать оттуда заголовок поста, картинку и текст? Наконец, на сцену выходит BeautifulSoup. Сейчас вы получили HTML из response.text , но это просто строка с HTML кодом. Для работы с библиотекой BeautifulSoup нужно сделать из этой строки HTML-суп:
В Python-коде суп — это новый объект с кучей возможностей. Например, теперь можно вывести HTML красиво, с отступами, с помощью метода soup.prettify() :
Супом он называется исторически, вот статья об этом термине. Если вкратце, то на самом деле верстальщики иногда косячат и, например, забывают закрывать теги или оставляют какие-нибудь неисправности. Такой код на HTML стали называть tag soup . Браузеры умеют самостоятельно исправлять какие-то огрехи и делать из такого “супа” нормальный, рабочий HTML. Но если вы скачиваете страничку через requests , то браузер тут ни при чём, и вы получите такой HTML, какой написали верстальщики сайта, со всеми его ошибками.
Для этого и нужна библиотека lxml , она подправит мелкие недочёты, и с ней BeautifulSoup справится даже с очень плохой вёрсткой. В этой строчке вы как раз говорите библиотеке BeautifulSoup использовать lxml :
Заголовок поста
Заголовок поста можно легко найти методом супа .find() . Для начала нужно узнать в какой тег этот заголовок обёрнут. В этом помогут инструменты разработчика:
Итак, тег h1 . Вот что вернёт метод .find() :
Это тоже суп, но уже не со всей HTML-страницей, а только с этим тегом и тегами внутри него. Заголовка поста тут нет: пост называется Are You Grateful? , а такого текста в этом теге нет. Похоже, что это не тот тег <h1> , который вы искали. Их на странице несколько и BeautifulSoup4 выдал первый, который нашёл. Это тег <h1> , который находится в самом верху страницы:
Как же найти заголовок поста, а не страницы? Можно уточнить запрос: заголовок поста лежит в теге <header> , а тот — в <main> :
Давайте попробуем такой запрос:
Тег нашли, а как достать его текст? Всё очень просто:
Победа, вы добрались до заголовка поста!
Картинка поста
Картинку можно найти так же: это единственный тег <img> внутри тега <main> . Но давайте попробуем другой подход, найдём её по классу. У картинки есть классы:
У картинки есть 3 класса, они перечислены через пробел:
Класс attachment-post-image переводится как “Картинка поста”, а значит наверняка он есть только у картинок поста. Вот как найти тег img , у которого есть такой класс:
Тот же .find() , только указали параметр class_ . Нижнее подчёркивание разработчики библиотеки добавили для того, чтобы не было пересечения со словом class из Python, которое используется для создания классов.
Осталось достать адрес картинки, он лежит в аргументе src :
Домашнее задание
Осталось спарсить текст поста. Сделать это можно одним из способов выше: по классу или тегам, с помощью метода find .
Попробуйте бесплатные уроки по Python
Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.
