BeautifulSoup вложенные теги - PullRequest
6 голосов
/ 04 января 2011

Я пытаюсь проанализировать XML с Beautifulsoup, но попал в кирпичную стену при попытке использовать атрибут " recursive " с 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>

Как видите, тег book повторяется внутри тега book, что вызывает ошибку, когда я пытаюсь что-то вроде:

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 ]

3 голосов
/ 05 января 2011

soup.findAll('catalog', recursive=False) вернет список, содержащий только ваш тег «catalog» верхнего уровня.Поскольку у него нет дочернего элемента title, item.title равно None.

Попробуйте вместо него soup.findAll("book") или soup.find("catalog").findChildren().

Редактировать: ОК, проблема была не в том, что я думал.Попробуйте это:

BSS.NESTABLE_TAGS["book"] = []
soup = BSS(open("catalog.xml"))
soup.catalog.findChildren(recursive=False)
2 голосов
/ 05 января 2011

Кажется, проблема заключается во вложенных тегах book. BautifulSoup имеет предопределенный набор тегов, которые могут быть вложены (BeautifulSoup.NESTABLE_TAGS), но он не знает, что book может быть вложенным, так что это чудеса.

Настройка синтаксического анализатора , объясняется, что происходит и как вы можете создать подкласс 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
0 голосов
/ 05 января 2011

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']
>>>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...