Ответ 1
В BeautifulSoup 4 атрибут class
(и несколько других атрибутов, таких как accesskey
и атрибут headers
на элементах ячейки таблицы) рассматривается как набор; вы сопоставляетесь с отдельными элементами, указанными в атрибуте. Это следует за стандартом HTML.
Таким образом, вы не можете ограничить поиск только одним классом.
Вам нужно будет использовать пользовательскую функцию здесь, чтобы вместо этого сопоставить класс:
result = soup.find_all(lambda tag: tag.name == 'div' and
tag.get('class') == ['product'])
Я использовал lambda
для создания анонимной функции; каждый тег сопоставляется по имени (должен быть 'div'
), а атрибут класса должен быть точно равен списку ['product']
; например имеют только одно значение.
Демо:
>>> from bs4 import BeautifulSoup
>>> text = """
... <body>
... <div class="product">Product 1</div>
... <div class="product">Product 2</div>
... <div class="product special">Product 3</div>
... <div class="product special">Product 4</div>
... </body>"""
>>> soup = BeautifulSoup(text)
>>> soup.find_all(lambda tag: tag.name == 'div' and tag.get('class') == ['product'])
[<div class="product">Product 1</div>, <div class="product">Product 2</div>]
Для полноты, вот все такие атрибуты набора из исходного кода BeautifulSoup:
# The HTML standard defines these attributes as containing a
# space-separated list of values, not a single value. That is,
# class="foo bar" means that the 'class' attribute has two values,
# 'foo' and 'bar', not the single value 'foo bar'. When we
# encounter one of these attributes, we will parse its value into
# a list of values if possible. Upon output, the list will be
# converted back into a string.
cdata_list_attributes = {
"*" : ['class', 'accesskey', 'dropzone'],
"a" : ['rel', 'rev'],
"link" : ['rel', 'rev'],
"td" : ["headers"],
"th" : ["headers"],
"td" : ["headers"],
"form" : ["accept-charset"],
"object" : ["archive"],
# These are HTML5 specific, as are *.accesskey and *.dropzone above.
"area" : ["rel"],
"icon" : ["sizes"],
"iframe" : ["sandbox"],
"output" : ["for"],
}