BeautifulSoup и поиск по классу

Возможный дубликат:
Beautiful Soup не может найти класс CSS, если у объекта есть и другие классы

Я использую BeautifulSoup для поиска tables в HTML. Проблема, с которой я сейчас сталкиваюсь, заключается в использовании пробелов в атрибуте class. Если мой HTML читает <html><table class="wikitable sortable">blah</table></html>, я не могу извлечь его из следующего (где я должен был бы найти tables как с wikipedia, так и wikipedia sortable для class):

BeautifulSoup(html).findAll(attrs={'class':re.compile("wikitable( sortable)?")})

Это найдет таблицу, если мой HTML только <html><table class="wikitable">blah</table></html>. Аналогично, я попытался использовать "wikitable sortable" в своем регулярном выражении, и это тоже не будет соответствовать. Любые идеи?

Ответы

Ответ 1

Совпадение шаблона также завершится неудачно, если wikitable появится после другого класса CSS, как в class="something wikitable other", поэтому, если вы хотите, чтобы все таблицы, атрибут класса которых содержит класс wikitable, вам нужен шаблон, который принимает больше возможностей:

html = '''<html><table class="sortable wikitable other">blah</table>
<table class="wikitable sortable">blah</table>
<table class="wikitable"><blah></table></html>'''

tree = BeautifulSoup(html)
for node in tree.findAll(attrs={'class': re.compile(r".*\bwikitable\b.*")}):
    print node

Результат:

<table class="sortable wikitable other">blah</table>
<table class="wikitable sortable">blah</table>
<table class="wikitable"><blah></blah></table>

Только для записи я не использую BeautifulSoup и предпочитаю использовать lxml, как упомянули другие.

Ответ 2

Одна из вещей, которая делает lxml лучше, чем BeautifulSoup, - это поддержка правильного выбора класса CSS (или даже поддерживает полные селектора css, если вы хотите их использовать)

import lxml.html

html = """<html>
<body>
<div class="bread butter"></div>
<div class="bread"></div>
</body>
</html>"""

tree = lxml.html.fromstring(html)

elements = tree.find_class("bread")

for element in elements:
    print lxml.html.tostring(element)

дает:

<div class="bread butter"></div>
<div class="bread"></div>