Как получить заголовок страницы
Что проверяют
Прежде всего, уточните ли вы задачу: «заголовок страницы» может означать <title> из HTML или HTTP-заголовки ответа. Дальше смотрят на аккуратность работы с сетью: таймауты, коды ответа, кодировку. Уточняющий вопрос обычно такой: а если заголовок подставляет JavaScript?
Как отвечать
Сначала переспросите, что нужно. Если <title>, каркас такой:
resp = requests.get(url, timeout=10)
resp.raise_for_status()
soup = BeautifulSoup(resp.content, "html.parser")
title = soup.title.get_text(strip=True) if soup.title else Nonetimeout: уrequestsнет таймаута по умолчанию, без него запрос к зависшему серверу ждёт бесконечно;resp.contentвместоresp.text: если сервер не указалcharset,requestsдляtext/htmlсчитает текст ISO-8859-1, и кириллица превращается в кракозябры. Байты BeautifulSoup декодирует сам, заглянув в<meta charset>;get_text(strip=True):.stringвернётNone, если внутри тега окажется больше одного узла, аget_textзаодно срежет переносы и пробелы;- отсутствие тега:
soup.titleбываетNone, это нужно обработать.
Если нужны HTTP-заголовки, это resp.headers, словарь без учёта регистра: content-type и Content-Type дают одно и то же. Можно отправить requests.head, но часть серверов на HEAD отвечает 405 или отдаёт не то, что на GET.
Для SPA, где <title> выставляет JavaScript, статический парсинг вернёт заглушку. Тогда нужен браузер: в Playwright это page.title() после page.goto(url). Для массового обхода берут httpx или aiohttp с асинхронными запросами.
Где спотыкаются
Отвечают не на тот вопрос: пишут про response.headers, когда спрашивали <title>, или наоборот. Короткое уточнение в начале снимает проблему.
Парсят HTML регулярным выражением. Это ломается на атрибутах тега, переносах строк и сущностях вроде &, которые парсер раскодирует сам.
Возвращают строку с текстом ошибки вместо исключения. Вызывающий код получает то заголовки, то строку и падает уже в другом месте. Заодно тесты ходят в живой интернет, хотя ответ стоит подменять через responses для requests или respx для httpx.