Как изменить HTML с помощью BeautifulSoup: Полное руководство

Что такое BeautifulSoup и зачем он нужен для изменения HTML?

BeautifulSoup — это мощная Python-библиотека, предназначенная для парсинга HTML и XML документов. Она преобразует сложные HTML-структуры в Python-объекты, с которыми легко взаимодействовать. В контексте изменения HTML, BeautifulSoup позволяет:

  • Находить нужные элементы на странице.
  • Изменять их атрибуты.
  • Манипулировать содержимым этих элементов (текст, другие теги).
  • Добавлять новые элементы.
  • Удалять ненужные элементы.

В отличие от регулярных выражений, BeautifulSoup предоставляет более надежный и интуитивно понятный способ работы с HTML, особенно когда структура документа сложная или непредсказуемая. Например, представим, что вам нужно автоматически обновить цены на товары на вашем сайте контекстной рекламы, получая данные из внешнего источника. BeautifulSoup поможет вам найти соответствующие элементы <span> или <div>, содержащие цены, и заменить их новыми значениями.

Установка и настройка BeautifulSoup

Установка BeautifulSoup выполняется очень просто с помощью pip:

pip install beautifulsoup4

Также потребуется установить парсер. Рекомендуется использовать lxml, как наиболее быстрый и функциональный:

pip install lxml

Если lxml не подходит, можно использовать встроенный html.parser, но он менее производительный.

Импорт BeautifulSoup и разбор HTML

Чтобы начать использовать BeautifulSoup, необходимо импортировать библиотеку и создать объект BeautifulSoup, передав HTML-код и выбранный парсер:

from bs4 import BeautifulSoup

html_code: str = """<html><head><title>Пример страницы</title></head><body><h1>Заголовок</h1><p id='first_paragraph'>Это первый параграф.</p></body></html>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

print(soup.prettify())

soup.prettify() делает HTML более читаемым.

Поиск и выбор элементов HTML с помощью BeautifulSoup

Поиск элементов по тегу, атрибутам и тексту

BeautifulSoup предоставляет несколько методов для поиска элементов:

  • find(): Находит первый элемент, соответствующий заданным критериям.
  • find_all(): Находит все элементы, соответствующие заданным критериям.

Примеры:

from bs4 import BeautifulSoup

html_code: str = """<html><body><h1>Заголовок</h1><p id='first_paragraph'>Это первый параграф.</p><p class='important'>Важный параграф.</p></body></html>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

# Поиск первого тега h1
h1_tag = soup.find('h1')
print(h1_tag.text) # Вывод: Заголовок

# Поиск всех тегов p
p_tags = soup.find_all('p')
for p in p_tags:
    print(p.text)
# Вывод:
# Это первый параграф.
# Важный параграф.

# Поиск элемента по атрибуту
paragraph_with_id = soup.find('p', id='first_paragraph')
print(paragraph_with_id.text)
# Вывод: Это первый параграф.

# Поиск по тексту
important_paragraph = soup.find('p', class_='important', string='Важный параграф.')
if important_paragraph:
    print(important_paragraph.text)
# Вывод: Важный параграф.

Использование CSS-селекторов для поиска элементов

Метод select() позволяет использовать CSS-селекторы для поиска элементов, что делает код более лаконичным и выразительным.

from bs4 import BeautifulSoup

html_code: str = """<html><body><div id='content'><p class='highlight'>Параграф 1</p><p>Параграф 2</p></div></body></html>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

# Поиск элемента с классом 'highlight' внутри элемента с id 'content'
highlighted_paragraph = soup.select('#content > .highlight')
if highlighted_paragraph:
    print(highlighted_paragraph[0].text)
# Вывод: Параграф 1

Навигация по дереву HTML: parent, children, siblings

BeautifulSoup позволяет перемещаться по дереву HTML, используя свойства parent, children и siblings.

from bs4 import BeautifulSoup

html_code: str = """<html><body><div id='container'><p>Параграф 1</p><p id='second'>Параграф 2</p></div></body></html>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

# Получение родительского элемента
second_paragraph = soup.find('p', id='second')
if second_paragraph:
    parent_div = second_paragraph.parent
    print(parent_div.name) # Вывод: div

# Получение дочерних элементов
container_div = soup.find('div', id='container')
if container_div:
    for child in container_div.children:
        if child.name == 'p':
            print(child.text)
# Вывод:
# Параграф 1
# Параграф 2

# Получение следующего соседнего элемента
first_paragraph = soup.find('p')
if first_paragraph:
    next_sibling = first_paragraph.find_next_sibling()
    if next_sibling:
        print(next_sibling.text) # Вывод: Параграф 2

Изменение атрибутов HTML-элементов

Получение значений атрибутов

Для получения значения атрибута используется синтаксис словаря:

from bs4 import BeautifulSoup

html_code: str = """<a href='https://example.com' title='Ссылка'>Текст ссылки</a>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

link = soup.find('a')
if link:
    href_value = link['href']
    title_value = link['title']
    print(f"href: {href_value}, title: {title_value}")
# Вывод: href: https://example.com, title: Ссылка

Изменение существующих атрибутов

from bs4 import BeautifulSoup

html_code: str = """<a href='https://example.com' title='Ссылка'>Текст ссылки</a>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

link = soup.find('a')
if link:
    link['href'] = 'https://new-example.com'
    print(link)
# Вывод: <a href="https://new-example.com" title="Ссылка">Текст ссылки</a>

Добавление новых атрибутов

from bs4 import BeautifulSoup

html_code: str = """<a>Текст ссылки</a>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

link = soup.find('a')
if link:
    link['href'] = 'https://example.com'
    link['class'] = 'external-link'
    print(link)
# Вывод: <a class="external-link" href="https://example.com">Текст ссылки</a>

Удаление атрибутов

from bs4 import BeautifulSoup

html_code: str = """<a href='https://example.com' title='Ссылка'>Текст ссылки</a>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

link = soup.find('a')
if link:
    del link['title']
    print(link)
# Вывод: <a href="https://example.com">Текст ссылки</a>

Изменение содержимого HTML-элементов

Замена текста внутри элемента

from bs4 import BeautifulSoup

html_code: str = """<h1>Старый заголовок</h1>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

h1_tag = soup.find('h1')
if h1_tag:
    h1_tag.string = 'Новый заголовок'
    print(h1_tag)
# Вывод: <h1>Новый заголовок</h1>

Добавление новых элементов внутрь существующих

from bs4 import BeautifulSoup

html_code: str = """<div id='content'></div>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

content_div = soup.find('div', id='content')
if content_div:
    new_paragraph = soup.new_tag('p')
    new_paragraph.string = 'Новый параграф'
    content_div.append(new_paragraph)
    print(content_div)
# Вывод: <div id="content"><p>Новый параграф</p></div>

Удаление элементов

from bs4 import BeautifulSoup

html_code: str = """<div id='content'><p>Параграф</p></div>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

paragraph = soup.find('p')
if paragraph:
    paragraph.decompose()
    content_div = soup.find('div', id='content')
    print(content_div)
# Вывод: <div id="content"></div>

Замена элемента другим элементом

from bs4 import BeautifulSoup

html_code: str = """<p id='old'>Старый параграф</p>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

old_paragraph = soup.find('p', id='old')
if old_paragraph:
    new_paragraph = soup.new_tag('p')
    new_paragraph.string = 'Новый параграф'
    old_paragraph.replace_with(new_paragraph)
    print(soup.body)
# Вывод: <body><p>Новый параграф</p></body>

Сохранение измененного HTML

Преобразование BeautifulSoup объекта обратно в строку HTML

from bs4 import BeautifulSoup

html_code: str = """<h1>Заголовок</h1>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

html_string: str = str(soup)
print(html_string)
# Вывод: <html><body><h1>Заголовок</h1></body></html>

Форматирование HTML для удобочитаемости

Для форматирования HTML используется метод prettify():

from bs4 import BeautifulSoup

html_code: str = """<h1>Заголовок</h1>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

pretty_html: str = soup.prettify()
print(pretty_html)
# Вывод:
# <html>
#  <body>
#   <h1>
#    Заголовок
#   </h1>
#  </body>
# </html>

Запись измененного HTML в файл

from bs4 import BeautifulSoup

html_code: str = """<h1>Заголовок</h1>"""

soup: BeautifulSoup = BeautifulSoup(html_code, 'lxml')

with open('output.html', 'w', encoding='utf-8') as f:
    f.write(soup.prettify())

Теперь измененный HTML будет сохранен в файле output.html.


Добавить комментарий