Давайте дружить в Телеграме: рассказываем про новые фичи, общаемся в комментах, прислушиваемся к вашим идеям Подписаться

Очистка веб-страниц в Python с Beautiful Soup

Роман Андреев
Роман Андреев
Технический писатель
24 апреля 2023 г.
544
8 минут чтения
Средний рейтинг статьи: 1

Beautiful Soup — одна из библиотек Python, которая позволяет извлекать данные из веб-документов. Библиотека предоставляет простой и интуитивно понятный интерфейс для парсинга и обработки веб-документов, что делает ее полезной как для веб-скрейпинга, так и для анализа данных. В статье рассмотрим ряд важных функций этой библиотеки, в том числе научимся применять поисковые фильтры, использовать встроенные функции и модифицировать дерево DOM. Но сначала немного важной терминологии.

Что такое дерево DOM

DOM или Document Object Model — это иерархическая структура, которая представляет содержимое документа HTML в виде особых объектов — узлов. Дерево DOM состоит из узлов. Каждый узел имеет свой тип: например, элементы могут быть тегами <div>, <p>, <a> и т.д., а текстовые узлы содержат текстовую информацию, которая отображается на странице.

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

Устанавливаем Beautiful Soup

Для установки Beautiful Soup в Python 3, необходимо открыть командную строку или терминал на компьютере и ввести там следующую инструкцию:

pip install beautifulsoup4

Чтобы открыть командную строку в Windows, нажмите на кнопку «Пуск» и введите cmd в строку поиска, после чего нажмите Enter. На MacOS и Linux откройте терминал из меню приложений или нажмите сочетание клавиш Ctrl + Alt + T. После этого введите инструкцию pip install beautifulsoup4 и нажмите Enter. Это должно запустить процесс установки.

В Windows бывает так, что при попытке выполнить команду pip install beautifulsoup4 появляется сообщение об ошибке: "pip" не является внутренней или внешней командой…. В этом случае вероятно, что путь к исполняемому файлу pip не прописан в переменной PATH. Чтобы исправить это, выполните следующие шаги:

  1. Откройте Панель управления.
  2. Выберите «Система и безопасность» или «Система», в зависимости от вашей версии Windows.
  3. Нажмите на «Дополнительные параметры системы».
  4. Нажмите на «Переменные среды».
  5. Найдите переменную PATH и нажмите на «Изменить».
  6. Введите путь к папке Scripts, где находится исполняемый файл pip. Обычно это путь C:\PythonXX\Scripts, где XX — это версия Python, которую вы используете. Ввести путь можно в конце строки через точку с запятой, вот так:

Image1

ВАЖНО! Будьте осторожны и не изменяйте другие пути, которые содержатся в строке Значение переменной, только правильно (через точку с запятой и без пробелов) добавьте нужный путь в конце!

  1. Теперь нажмите на «ОК» во всех открытых окнах и закройте Панель управления.
  2. После этого снова выполните инструкцию pip install beautifulsoup4 в командной строке, она должна выполниться успешно, и вы увидите примерно следующее:

Image2

Библиотека установлена, можем приступать к работе.

Ищем элементы в DOM

find_all() — стандартный метод библиотеки, используемый для поиска элементов на веб-странице, удовлетворяющих определенным критериям. find_all() ищет всё соответствующее заданным параметрам, и возвращает это в виде списка объектов. Например, если мы хотим найти теги H2 в каком-либо документе HTML, сначала указываем путь к нему, выполнив следующую инструкцию:

from bs4 import BeautifulSoup
with open("C:/Files/my_wiki_example.html") as fp:
    soup = BeautifulSoup(fp, 'html.parser')

А теперь вводим инструкцию на поиск:

for heading in soup.find_all('h2'):
print(heading.text)

Если там содержатся такие заголовки, то мы получим их в выводе:

Chapter 1
Chapter 2
Chapter 3
Chapter 4

Если же Beautiful Soup ничего не найдет, он выведет пустую строку.

Также можно задать поиск при помощи регулярного выражения. Давайте попробуем вывести заголовки со страницы. В этом случае вводим следующую инструкцию:

import re
for heading in soup.find_all(re.compile('^h[1-6]')):
    print(heading.name + ' ' + heading.text.strip())

Получаем список всех заголовков документа:

h1 My First Wiki Doc
h2 Chapter 1
h2 Chapter 2
h2 Chapter 3
h2 Chapter 4

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

for heading in soup.find_all(['h1','h2','h3']):
    print(heading.name + ' ' + heading.text.strip())
h1 My First Wiki Doc
h2 Chapter 1
h2 Chapter 2
h2 Chapter 3
h2 Chapter 4

Если же нам нужно посчитать количество определенных элементов, в этом поможет следующая инструкция:

len(soup.find_all(True))

5

При возникновении трудностей с нахождением элементов в документе можно даже написать свою функцию. Несложный пример:

def big_lists(tag):
    return len(tag.contents) > 5 and tag.name == 'ul'
len(soup.find_all(big_lists))

1

В этом примере мы задали поиск немаркированных списков (тег ul) с количеством элементов > 5. Программа указала нам на наличие одного такого списка в нашем документе.

Фильтруем элементы

Чтобы отфильтровать нужные элементы через метод find_all(), можно задать поиск по определенным атрибутам. Давайте попробуем выполнить поиск по классам, а затем отфильтруем результаты:

import re
len(soup.find_all(class_='table'))
18

len(soup.find_all(class_='image'))
12

len(soup.find_all(class_='references'))
5

len(soup.find_all(class_='redirect'))
3

В данном случае мы выполнили поиск по таблицам (table), изображениям (image), ссылкам на источники (references), а также перенаправлениям на другие страницы (redirect). В данном случае получилось не так уж и много элементов определенного класса. Но допустим, нам нужно получить только 3 первых таблицы, в этом случае вводим:

soup.find_all(class_='table', limit=3)

И программа выведет нам примерно такой список:

<span class='table' id='Table1'>Table 1
<span class='table' id='Table2'>Table 2
<span class='table' id='Table3'>Table 3

Чтобы отфильтровать элементы, находящиеся в прямых «потомках», поможет инструкция:

len(soup.html.find_all('meta', recursive=False))

Значение False здесь используется для прекращения глобального поиска, фильтр устанавливается только на непосредственных дочерних объектах.

Также можно воспользоваться методом find(). Допустим, нам нужно получить заголовок H2. Вводим:

soup.find('h2')

Результат в нашем случае:

<h2>Chapter 1</h2>

Рассмотренные методы не являются единственно возможными для поиска и фильтрации объектов документа. Вот еще несколько полезных методов, которые пригодятся вам для парсинга веб-страниц:

  • Методы find_parent() и find_parents() используются для поиска родительских тегов HTML-документа. find_parent() ищет первый родительский элемент указанного тега, а find_parents() находит сразу все.
  • find_next_sibling() и find_next_siblings() используются для поиска тегов, имеющих тот же родительский элемент, находящийся ниже по документу.
  • Соответственно, find_previous_sibling() и find_previous_siblings() используются для поиска расположенного выше тега.
  • Похожим образом работают методы find_next() и find_all_next(), а также find_previous() и find_all_previous(), но они используются для поиска вообще любых тегов.

Еще одна возможность фильтрации результатов — использование селекторов CSS. Например, для выбора всех элементов с тегом p и находящихся внутри элемента с классом content мы вводим:

content_paragraphs = soup.select('div.content p')

Модифицируем DOM

Если бы Beautiful Soup позволял только искать, он не был бы столь полезен. Но с его помощью мы легко сможем и изменять содержимое веб-документов. Попробуем изменить текст заголовка H1:

title = soup.find('h1')
title.string = 'New Title'

Для проверки изменений вводим:

soup.find('h1')
<h1>New Title</h1>

В этом примере мы сначала нашли заголовок H1, а затем изменили его содержимое с через атрибут string.

А вот так можно добавить новый атрибут к первому параграфу:

paragraph = soup.find('p')
paragraph['data-id'] = '12345'

Нетрудно и удалить сам параграф, удаление производится при помощи метода extract():

paragraph = soup.find('p')
paragraph.extract()

В результате получим такой вывод:

<p data-id="12345">My first Wiki paragraph</p>

А чтобы проверить, что удаление состоялось, используем метод prettify() вместе с функцией print():

print(soup.prettify())

Так мы сможем убедиться, что параграф был удален.

Из других методов, используемых для модификации документа, отметим:

  • append() для добавления в конце элемента;
  • insert() для вставки чего-либо внутри элемента;
  • clear() для очистки всего содержимого элемента без удаления самого тега;
  • decompose() для полного удаления элемента и его содержимого из DOM;
  • extract() для удаления элемента и его содержимого, но без уничтожения элемента;
  • replace_with() для замены элемента другим.

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

Зарегистрируйтесь и начните пользоваться
сервисами Timeweb Cloud прямо сейчас

15 лет опыта
Сосредоточьтесь на своей работе: об остальном позаботимся мы
165 000 клиентов
Нам доверяют частные лица и компании, от небольших фирм до корпораций
Поддержка 24/7
100+ специалистов поддержки, готовых помочь в чате, тикете и по телефону