Beautiful Soup — одна из библиотек Python, которая позволяет извлекать данные из веб-документов. Библиотека предоставляет простой и интуитивно понятный интерфейс для парсинга и обработки веб-документов, что делает ее полезной как для веб-скрейпинга, так и для анализа данных. В статье рассмотрим ряд важных функций этой библиотеки, в том числе научимся применять поисковые фильтры, использовать встроенные функции и модифицировать дерево DOM. Но сначала немного важной терминологии.
DOM или Document Object Model — это иерархическая структура, которая представляет содержимое документа HTML в виде особых объектов — узлов. Дерево DOM состоит из узлов. Каждый узел имеет свой тип: например, элементы могут быть тегами <div>
, <p>
, <a>
и т.д., а текстовые узлы содержат текстовую информацию, которая отображается на странице.
Дерево DOM обеспечивает доступ к содержимому документа, позволяя разработчикам манипулировать элементами, атрибутами и содержимым страницы с помощью языков программирования. Например, с помощью DOM можно изменять содержимое элементов, добавлять новые элементы или удалять существующие.
Для установки 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
. Чтобы исправить это, выполните следующие шаги:
PATH
и нажмите на «Изменить».Scripts
, где находится исполняемый файл pip
. Обычно это путь C:\PythonXX\Scripts
, где XX
— это версия Python, которую вы используете. Ввести путь можно в конце строки через точку с запятой, вот так:ВАЖНО! Будьте осторожны и не изменяйте другие пути, которые содержатся в строке
Значение переменной
, только правильно (через точку с запятой и без пробелов) добавьте нужный путь в конце!
pip install beautifulsoup4
в командной строке, она должна выполниться успешно, и вы увидите примерно следующее:Библиотека установлена, можем приступать к работе.
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')
Если бы 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 и без проблем изменять их содержимое.