Вложенные теги BeautifulSoup
Я пытаюсь разобрать XML с Beautifulsoup, но попал в кирпичную стену при попытке использовать "рекурсивные" атрибут с findall ()
у меня довольно странный формат xml, показанный ниже:
<?xml version="1.0"?>
<catalog>
<book>
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
<book>true</book>
</book>
<book>
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
<book>false</book>
</book>
</catalog>
как вы можете видеть, тег книги повторяется внутри тега книги, что вызывает ошибку, когда я пытаюсь что-то вроде:
from BeautifulSoup import BeautifulStoneSoup as BSS
catalog = "catalog.xml"
def open_rss():
f = open(catalog, 'r')
return f.read()
def rss_parser():
rss_contents = open_rss()
soup = BSS(rss_contents)
items = soup.findAll('book', recursive=False)
for item in items:
print item.title.string
rss_parser()
как вы увидите, на мой суп.findAll я добавил recursive=false, что теоретически не сделало бы его рекурсивным через предмет найден, но переходим к следующему.
Это, похоже, не работает, так как я всегда получаю следующую ошибку:
File "catalog.py", line 17, in rss_parser
print item.title.string
AttributeError: 'NoneType' object has no attribute 'string'
Я уверен, что делаю что-то глупое здесь, и был бы признателен, если бы кто-нибудь мог помочь мне решить эту проблему.
изменение структуры HTML не является опцией, этот код должен хорошо работать, так как он потенциально будет анализировать большой XML-файл.
3 ответов
soup.findAll('catalog', recursive=False)
вернет список, содержащий только ваш тег "каталог" верхнего уровня. Поскольку у этого нет "титульного" ребенка,item.title
и None
.
попробовать soup.findAll("book")
или soup.find("catalog").findChildren()
вместо.
Edit: хорошо, Проблема была не в том, что я думал. Попробуйте это:
BSS.NESTABLE_TAGS["book"] = []
soup = BSS(open("catalog.xml"))
soup.catalog.findChildren(recursive=False)
похоже, проблема заключается в вложенном book
теги. BautifulSoup имеет предопределенный набор тегов, которые могут быть вложены (BeautifulSoup.NESTABLE_TAGS
), но он не знает, что book
может быть вложенным, поэтому он идет wonkers.
настройки парсера, объясняет, что происходит и как вы можете подкласс BeautifulStoneSoup
для настройки вложенных тегов. Вот как мы можем использовать его, чтобы исправить вашу проблему:
from BeautifulSoup import BeautifulStoneSoup
class BookSoup(BeautifulStoneSoup):
NESTABLE_TAGS = {
'book': ['book']
}
soup = BookSoup(xml) # xml string omitted to keep this short
for book in soup.find('catalog').findAll('book', recursive=False):
print book.title.string
если мы запустим это, мы получим следующий вывод:
XML Developer's Guide
Midnight Rain
Beautifulsoup медленный и мертвый, вместо этого используйте lxml:)
>>> from lxml import etree
>>> rss = open('/tmp/catalog.xml')
>>> items = etree.parse(rss).xpath('//book/title/text()')
>>> items
["XML Developer's Guide", 'Midnight Rain']
>>>