</>
Topic 1 of 5

Course materials are currently available in Russian only.

Теги и текст

Веб-страница — это текст на языке HTML: содержимое размечено тегами. <h1> — заголовок, <p> — абзац, <a> — ссылка, <li> — пункт списка. Теги вкладываются друг в друга и образуют дерево:

<html>
  <head><title>Магазин</title></head>
  <body>
    <h1>Товары</h1>
    <ul>
      <li>Чай <b>250</b></li>
      <li>Кофе <b>400</b></li>
    </ul>
  </body>
</html>

Достать из такой страницы нужные данные — цены, заголовки, ссылки — задача парсинга (разбора). Регулярными выражениями это делать неудобно и ненадёжно. Библиотека BeautifulSoup строит дерево тегов и даёт удобно по нему ходить.

Как начать

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, "html.parser")
  • первый аргумент — текст страницы (строка);
  • второй — какой разборщик использовать. "html.parser" встроен в Python и всегда доступен.

Обычно HTML получают по сети (библиотекой requests), но в задачах этого курса страница приходит во входных данных — целиком её читают так: sys.stdin.read().

BeautifulSoup терпим к ошибкам: незакрытые теги и лишние пробелы его не пугают. Имена тегов он приводит к нижнему регистру, так что <H2> найдётся как "h2".

Поиск тегов

soup.find("li")          # первый <li> или None, если его нет
soup.find_all("li")      # список всех <li>
soup.find_all(["h1", "h2"])   # теги нескольких видов
soup.title               # короткая запись для soup.find("title")

Искать можно не только во всём документе, но и внутри найденного тега — у него те же методы:

ul = soup.find("ul")
for li in ul.find_all("li"):
    price = li.find("b")    # <b> внутри этого <li>

Текст тега

li = soup.find("li")
print(li)                         # <li>Чай <b>250</b></li> — тег целиком
print(li.get_text())              # Чай 250 — весь текст, включая вложенные теги
print(li.find("b").get_text())    # 250
print(li.get_text().strip())     # без пробелов по краям
  • get_text() (или свойство .text) собирает текст тега и всех вложенных;
  • .strip() у полученной строки убирает пробелы и переводы строк по краям: li.get_text().strip();
  • параметр strip=True действует иначе: он обрезает каждый кусочек текста и склеивает их без пробелов — для <p>Привет, <b>мир</b></p> получится Привет,мир. Он удобен, когда в теге одно число или одно слово.

Есть ещё свойство .string — оно работает, только если внутри тега ровно один кусок текста без вложенных тегов, иначе возвращает None. Поэтому для текста надёжнее get_text().

Помните, что текст — это строка. Число из него получают через int(...) или float(...).

Итог

  • BeautifulSoup(html, "html.parser") — дерево тегов;
  • find(тег) — первый или None; find_all(тег) — список всех;
  • поиск работает и внутри найденного тега;
  • get_text().strip() — текст без разметки и пробелов по краям.