BeautifulSoup не видит теги, вложенные в тег <h4>

Рейтинг: 5Ответов: 2Опубликовано: 21.03.2023

Проблема описана в заголовке. Больше и сказать нечего. 2 дня бился на рабочем сайте - ничего понять не мог. В конце-концов создал минимально воспроизводимый пример.

Имеем HTML файл:

<!DOCTYPE html>
<html>
    <head>
        <title>Что внутри тега h4 ?</title>
        <meta charset="utf-8">
    </head>

    <body>
        <h4>
            111
            <p>(1880-1938)</p>
            222
            <p>Возчик артели возчиков, герой Русско-Японской и Первой мировой войн,
            полный Георгиевский кавалер;
            Расстрелян в г. Томске в 1938 году.</p>
            333
        </h4>
    </body>
</html>

И крохотную программку на Python, которая ведёт себя очень странно:

#!/usr/bin/python3

from bs4 import BeautifulSoup

with open("index.html", "r") as f:
    contents = f.read()

    soup = BeautifulSoup(contents, 'lxml')

    print(f"HTML:")
    print(f"Тег Н4 полностью: {soup.h4}")
    print(f"Имя тега: {soup.h4.name}")
    print(f"Текст внутри тега: {soup.h4.text}")

Попробуйте запустить программку. В качестве содержимого тега <h4> она покажет строку 111. Т.е., содержимое тегов <p> не видно. Ладно, пусть так. Но и строки 222 и 333 тоже не видны! Мало того, если я вызову метод .finf_all('p4') то ничего не будет найдено!

Это что - ошибка в библиотеке? Или существует какой-то запрет на размещение любых тегов внутри тегов <h?>?

Ответы

▲ 2Принят

Действительно, с lxml не работает. Для него тег h4 закрыт до первого вложенного тега p:

html = """
...
</html>
"""
soup = BeautifulSoup(html, 'lxml')
print(soup.body)

Результат:

<body>
<h4>
            111
            </h4><p>(1880-1938)</p>
...

Попробуйте с html.parser - с ним работает и он еще поставляется с питоном:

from bs4 import BeautifulSoup

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Что внутри тега h4 ?</title>
        <meta charset="utf-8">
    </head>

    <body>
        <h4>
            111
            <p>(1880-1938)</p>
            222
            <p>Возчик артели возчиков, герой Русско-Японской и Первой мировой войн,
            полный Георгиевский кавалер;
            Расстрелян в г. Томске в 1938 году.</p>
            333
        </h4>
    </body>
</html>
"""
soup = BeautifulSoup(html, 'html.parser')
print(soup.body.h4.p)
# <p>(1880-1938)</p>

print(soup.find('h4').p)
# <p>(1880-1938)</p>

print(soup.select_one('h4 > p'))
# <p>(1880-1938)</p>
▲ 2

Этот код рабочий:

from bs4 import BeautifulSoup

html = '''
<!DOCTYPE html>
<html>
    <head>
        <title>Что внутри тега h4 ?</title>
        <meta charset="utf-8">
    </head>

    <body>
        <h4>
            111
            <p>(1880-1938)</p>
            222
            <p>Возчик артели возчиков, герой Русско-Японской и Первой мировой войн,
            полный Георгиевский кавалер;
            Расстрелян в г. Томске в 1938 году.</p>
            333
        </h4>
    </body>
</html>
'''
soup = BeautifulSoup(html, 'html.parser')
h4 = soup.find('h4')
for item in h4.findAll('p'):
    print(item)

Результат: введите сюда описание изображения