Как найти элементы по классу


386

У меня проблемы с анализом HTML-элементов с атрибутом "class" с помощью Beautifulsoup. Код выглядит так

soup = BeautifulSoup(sdata)
mydivs = soup.findAll('div')
for div in mydivs: 
    if (div["class"] == "stylelistrow"):
        print div

Я получаю сообщение об ошибке в той же строке «после» сценария заканчивается.

File "./beautifulcoding.py", line 130, in getlanguage
  if (div["class"] == "stylelistrow"):
File "/usr/local/lib/python2.6/dist-packages/BeautifulSoup.py", line 599, in __getitem__
   return self._getAttrMap()[key]
KeyError: 'class'

Как мне избавиться от этой ошибки?

Ответы:


646

Вы можете уточнить свой поиск, чтобы найти только те div с данным классом, используя BS3:

mydivs = soup.findAll("div", {"class": "stylelistrow"})

@ Клаус- что если я хочу использовать findAll вместо этого?

1
Спасибо за это. Это не только для @class, но и для чего угодно.
prageeth

41
Это работает только для точных совпадений. <.. class="stylelistrow">соответствует, но нет <.. class="stylelistrow button">.
Wernight

4
@pyCthon Смотрите ответ для @jmunsch, теперь BS поддерживает, class_который работает правильно.
Воскресенье,

25
Начиная с BeautifulSoup4, findAll теперь находится find_all
Neoecos

273

Из документации:

Начиная с Beautiful Soup 4.1.2, вы можете осуществлять поиск по классу CSS, используя ключевое слово аргумент class_ :

soup.find_all("a", class_="sister")

Который в этом случае будет:

soup.find_all("div", class_="stylelistrow")

Это также будет работать для:

soup.find_all("div", class_="stylelistrowone stylelistrowtwo")

5
Вы также можете использовать списки: soup.find_all("a", ["stylelistrowone", "stylelistrow"])безопаснее, если у вас мало классов.
Нуно Андре

4
Это должен быть принятый ответ, он более правильный и лаконичный, чем альтернативы.
goncalopp

1
Дополнение к @ ответ NunoAndré для BeautifulSoup 3: soup.findAll("a", {'class':['stylelistrowone', 'stylelistrow']}).
Брэд


18

Специфично для BeautifulSoup 3:

soup.findAll('div',
             {'class': lambda x: x 
                       and 'stylelistrow' in x.split()
             }
            )

Найдем все это:

<div class="stylelistrow">
<div class="stylelistrow button">
<div class="button stylelistrow">

Почему бы не re.search ('. * Stylelistrow. *', X)?
Рюрни

потому что тогда stylelistrow2 будет соответствовать. Лучший комментарий: "почему бы не использовать string.find () вместо re?"
FlipMcF

2
lambda x: 'stylelistrow' in x.split()просто и красиво
fferri

И я ненавижу регулярные выражения. Спасибо! (обновление ответа) | сохраняя 'x и' для проверки на None
FlipMcF

16

Прямой путь будет:

soup = BeautifulSoup(sdata)
for each_div in soup.findAll('div',{'class':'stylelist'}):
    print each_div

Убедитесь, что вы взяли корпус findAll , но не все


4
Это работает только для точных совпадений. <.. class="stylelistrow">соответствует, но нет <.. class="stylelistrow button">.
Wernight

11

Как найти элементы по классу

У меня возникают проблемы при разборе html-элементов с атрибутом "class" с помощью Beautifulsoup.

Вы можете легко найти по одному классу, но если вы хотите найти по пересечению двух классов, это немного сложнее,

Из документации (выделение добавлено):

Если вы хотите искать теги, которые соответствуют двум или более классам CSS, вы должны использовать селектор CSS:

css_soup.select("p.strikeout.body")
# [<p class="body strikeout"></p>]

Чтобы было ясно, это выбирает только те теги p, которые являются зачеркнутыми и классом тела.

Чтобы найти пересечение любого из набора классов (не пересечение, а объединение), вы можете дать список class_аргументу ключевого слова (по состоянию на 4.1.2):

soup = BeautifulSoup(sdata)
class_list = ["stylelistrow"] # can add any other classes to this list.
# will find any divs with any names in class_list:
mydivs = soup.find_all('div', class_=class_list) 

Также обратите внимание, что findAll был переименован из camelCase в более Pythonic find_all.


11

CSS селекторы

один класс первый матч

soup.select_one('.stylelistrow')

список матчей

soup.select('.stylelistrow')

составной класс (то есть И другой класс)

soup.select_one('.stylelistrow.otherclassname')
soup.select('.stylelistrow.otherclassname')

Пробелы в именах составных классов, например class = stylelistrow otherclassname, заменяются на «.». Вы можете продолжить добавлять классы.

список классов (ИЛИ - совпадать с тем, что есть)

soup.select_one('.stylelistrow, .otherclassname')
soup.select('.stylelistrow, .otherclassname')

BS4 4.7.1 +

Определенный класс, который innerTextсодержит строку

soup.select_one('.stylelistrow:contains("some string")')
soup.select('.stylelistrow:contains("some string")')

Определенный класс, который имеет определенный дочерний элемент, например, aтег

soup.select_one('.stylelistrow:has(a)')
soup.select('.stylelistrow:has(a)')

5

Начиная с BeautifulSoup 4+,

Если у вас есть одно имя класса, вы можете просто передать имя класса в качестве параметра, например:

mydivs = soup.find_all('div', 'class_name')

Или, если у вас более одного имени класса, просто передайте список имен классов как параметр, например:

mydivs = soup.find_all('div', ['class1', 'class2'])

3

Попробуйте сначала проверить, есть ли у div атрибут class, например:

soup = BeautifulSoup(sdata)
mydivs = soup.findAll('div')
for div in mydivs:
    if "class" in div:
        if (div["class"]=="stylelistrow"):
            print div

1
Это не работает Я думаю, что ваш подход был правильным, но 4-я строка не работает, как задумано.
Нео

1
Ах, я думал, что div работает как словарь, я не очень знаком с Beautiful Soup, так что это было только предположение.
Mew

3

Это работает для меня, чтобы получить доступ к атрибуту класса (на Beautifulsoup 4, вопреки тому, что говорится в документации). KeyError - это возвращаемый список, а не словарь.

for hit in soup.findAll(name='span'):
    print hit.contents[1]['class']


1

Это сработало для меня:

for div in mydivs:
    try:
        clazz = div["class"]
    except KeyError:
        clazz = ""
    if (clazz == "stylelistrow"):
        print div

1

В качестве альтернативы мы можем использовать lxml, он поддерживает xpath и очень быстро!

from lxml import html, etree 

attr = html.fromstring(html_text)#passing the raw html
handles = attr.xpath('//div[@class="stylelistrow"]')#xpath exresssion to find that specific class

for each in handles:
    print(etree.tostring(each))#printing the html as string

0

Это должно работать:

soup = BeautifulSoup(sdata)
mydivs = soup.findAll('div')
for div in mydivs: 
    if (div.find(class_ == "stylelistrow"):
        print div

0

Другие ответы не сработали для меня.

В других ответах findAllон используется на самом объекте супа, но мне нужен был способ найти по имени класса объекты внутри определенного элемента, извлеченного из объекта, который я получил после выполнения findAll.

Если вы пытаетесь выполнить поиск внутри вложенных элементов HTML, чтобы получить объекты по имени класса, попробуйте ниже -

# parse html
page_soup = soup(web_page.read(), "html.parser")

# filter out items matching class name
all_songs = page_soup.findAll("li", "song_item")

# traverse through all_songs
for song in all_songs:

    # get text out of span element matching class 'song_name'
    # doing a 'find' by class name within a specific song element taken out of 'all_songs' collection
    song.find("span", "song_name").text

Обратите внимание:

  1. Я не определяю явно, что поиск выполняется по атрибуту 'class' findAll("li", {"class": "song_item"}), поскольку это единственный атрибут, по которому я выполняю поиск, и он будет по умолчанию искать атрибут класса, если вы не сообщаете, какой именно атрибут вы хотите найти.

  2. Когда вы делаете findAllили find, результирующий объект имеет класс, bs4.element.ResultSetкоторый является подклассом list. Вы можете использовать все методы ResultSet, внутри любого количества вложенных элементов (если они имеют тип ResultSet), чтобы найти или найти все.

  3. Моя версия BS4 - 4.9.1, версия Python - 3.8.1


0

Следующее должно работать

soup.find('span', attrs={'class':'totalcount'})

замените «totalcount» на имя вашего класса, а «span» - на тег, который вы ищете. Кроме того, если ваш класс содержит несколько имен с пробелами, просто выберите одно и используйте.

PS Это находит первый элемент с заданными критериями. Если вы хотите найти все элементы, замените 'find' на 'find_all'.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.