</>
Topic 2 of 5

Course materials are currently available in Russian only.

Атрибуты и ссылки

У тегов бывают атрибуты — дополнительные сведения внутри открывающего тега: адрес ссылки, путь к картинке, класс оформления.

<a href="/catalog" class="menu-link" target="_blank">Каталог</a>
<img src="cat.jpg" alt="Рыжий кот" width="300">

Здесь у ссылки атрибуты href, class и target, у картинки — src, alt и width.

Чтение атрибутов

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, "html.parser")
a = soup.find("a")
print(a["href"])            # /catalog
print(a.get("target"))      # _blank
print(a.get("rel"))         # None — такого атрибута нет
print(a.get("rel", "нет"))  # нет — значение по умолчанию
print(a.attrs)              # словарь всех атрибутов
print(a.has_attr("href"))   # True
  • tag["имя"] — как у словаря; если атрибута нет — ошибка KeyError;
  • tag.get("имя") — безопасный вариант: вернёт None или указанное значение по умолчанию;
  • значения атрибутов — строки (числа нужно переводить самим: int(img["width"]));
  • атрибут class (и некоторые другие, где может быть несколько значений через пробел) возвращается списком: ['menu-link'].

Атрибут без значения (<input disabled>) или с пустым (alt="") возвращается пустой строкой. Пустая строка в условии if считается ложью — это удобно для проверок.

Поиск по атрибутам

В find и find_all можно указать нужные атрибуты:

soup.find_all("a", href=True)              # только ссылки, у которых есть href
soup.find_all("img", alt="")               # картинки с пустым alt
soup.find("input", attrs={"name": "q"})    # по произвольному атрибуту
soup.find_all("div", class_="card")        # по классу — с подчёркиванием!
soup.find(id="main")                       # по id, тег любой

class — зарезервированное слово Python, поэтому параметр называется class_. Поиск по классу находит теги, у которых среди классов есть указанный: <div class="card big"> тоже подходит.

Полные адреса: urljoin

В href часто записан относительный адрес — относительно текущей страницы. Чтобы получить полный, используют urljoin из стандартной библиотеки:

from urllib.parse import urljoin

page = "https://shop.ru/catalog/tea.html"
print(urljoin(page, "green.html"))    # https://shop.ru/catalog/green.html
print(urljoin(page, "../about"))      # https://shop.ru/about
print(urljoin(page, "/cart"))         # https://shop.ru/cart
print(urljoin(page, "https://x.ru"))  # https://x.ru — уже полный
  • green.html — в той же папке, что и текущая страница;
  • ../ — на папку выше;
  • /cart — от корня сайта;
  • полный адрес остаётся как есть.

Склеивать адреса вручную через + — частая ошибка: правил много, и urljoin знает их все.

Итог

  • tag["имя"] и tag.get("имя", по_умолчанию) — значение атрибута;
  • class — список классов;
  • find_all("a", href=True), class_="...", id="...", attrs={...} — поиск по атрибутам;
  • urljoin(страница, href) — полный адрес ссылки.