использование Beautifulsoup 4 для XML вызывает странное поведение (проблемы с памятью?) - PullRequest
1 голос
/ 23 марта 2012

Я получаю странное поведение с этим

>>> from bs4 import BeautifulSoup

>>> smallfile = 'small.xml'      #approx 600bytes
>>> largerfile = 'larger.xml'    #approx 2300 bytes
>>> len(BeautifulSoup(open(smallfile, 'r'), ['lxml', 'xml']))
1
>>> len(BeautifulSoup(open(largerfile, 'r'), ['lxml', 'xml']))
0

Содержимое small.xml:

<?xml version="1.0" encoding="us-ascii"?>
<Catalog>
<CMoverMissile id="HunterSeekerMissile">
<MotionPhases index="1">
<Driver value="Guidance"/>
<Acceleration value="3200"/>
<MaxSpeed value="2.9531"/>
<Clearance value="0.5"/>
<ClearanceLookahead value="3"/>
<Outro value="-4.5,-4.25"/>
<YawPitchRoll value="MAX"/>
</MotionPhases>
<MotionPhases index="2">
<Driver value="Guidance"/>
<Acceleration value="4"/>
<MaxSpeed value="2.9531"/>
<Clearance value="0.5"/>
<ClearanceLookahead value="3"/>
<Outro value="-2.25,-2"/>
<YawPitchRoll value="MAX"/>
</MotionPhases>
</CMoverMissile>
</Catalog>

Файл большего размера - это просто файл меньшего размера, но дополненный пробелами и символами новой строки (между ними).последние два тега на случай, если это актуально).IE структура и содержимое xml должны быть идентичны для обоих случаев.

В редких случаях обработка файла largefile фактически даст частичный результат, когда была проанализирована только небольшая часть xml.Кажется, я не могу точно воссоздать обстоятельства.

Поскольку BeautifulSoup использует lxml, я проверил, может ли lxml обрабатывать файлы независимо.Похоже, lxml может анализировать оба файла.

>>> from lxml import etree
>>> tree = etree.parse(smallfile)
>>> len(etree.tostring(tree))
547
>>> tree = etree.parse(largerfile)
>>> len(etree.tostring(tree))
2294

Я использую

  • нетбук с оперативной памятью 1 ГБ
  • Windows 7
  • lxml 2.3 (возникли проблемы с установкой, надеюсь, не из-за неумелой установки)
  • beautiful soup 4.0.1
  • python 3.2 (у меня также установлен python 2.7x, ноиспользовал 3.2 для этого кода)

Что может помешать правильной обработке файла большего размера?Мое текущее подозрение - какая-то странная проблема с памятью, поскольку размер файла, похоже, имеет значение, возможно, в связи с некоторой ошибкой в ​​том, как BeautifulSoup 4 взаимодействует с lxml.

Редактировать: для лучшей иллюстрации ...

>>> smallsoup = BeautifulSoup(smallfile), ['lxml', 'xml'])
>>> smallsoup
<?xml version="1.0" encoding="utf-8"?>
<Catalog>
<CMoverMissile id="HunterSeekerMissile">
<MotionPhases index="1">
<Driver value="Guidance"/>
<Acceleration value="3200"/>
<MaxSpeed value="2.9531"/>
<Clearance value="0.5"/>
<ClearanceLookahead value="3"/>
<Outro value="-4.5,-4.25"/>
<YawPitchRoll value="MAX"/>
</MotionPhases>
<MotionPhases index="2">
<Driver value="Guidance"/>
<Acceleration value="4"/>
<MaxSpeed value="2.9531"/>
<Clearance value="0.5"/>
<ClearanceLookahead value="3"/>
<Outro value="-2.25,-2"/>
<YawPitchRoll value="MAX"/>
</MotionPhases>
</CMoverMissile>
</Catalog>
>>> largersoup = BeautifulSoup(largerfile, ['lxml', 'xml'])
>>> largersoup
<?xml version="1.0" encoding="utf-8"?>

>>>

>>> repr(open(largefile, 'r').read())
'\'<?xml version="1.0" encoding="us-ascii"?>\\n<Catalog>\\n<CMoverMissile id="HunterSeekerMissile">\\n<MotionPhases index="1">\\n<Driver value="Guidance"/>\\n<Acceleration value="3200"/>\\n<MaxSpeed value="2.9531"/>\\n<Clearance value="0.5"/>\\n<ClearanceLookahead value="3"/>\\n<Outro value="-4.5,-4.25"/>\\n<YawPitchRoll value="MAX"/>\\n</MotionPhases>\\n<MotionPhases index="2">\\n<Driver value="Guidance"/>\\n<Acceleration value="4"/>\\n<MaxSpeed value="2.9531"/>\\n<Clearance value="0.5"/>\\n<ClearanceLookahead value="3"/>\\n<Outro value="-2.25,-2"/>\\n<YawPitchRoll value="MAX"/>\\n</MotionPhases>\\n</CMoverMissile>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        </Catalog>\''

примечание: между пробелом и \ ''

есть много пробелов (которые, вероятно, не будут отображаться в браузере)

Ответы [ 3 ]

2 голосов
/ 23 марта 2012

len(soup) возвращает len(soup.contents), т. Е. Число ближайших детей (в данном случае один ребенок <Catalog>).

BeautifulSoup не удалось разобрать largerfile, поэтому len(soup) == 0

1 голос
/ 24 марта 2012

Оказывается, проблема лежит где-то с BS4 / LXML. Автор BS4 (BeautifulSoup), признает проблему (https://groups.google.com/group/beautifulsoup/browse_thread/thread/24a82209aca4c083):

"Очевидно, что BS4 + lxml не будет анализировать XML-документ, который длиннее около 550 байт. Я проверил это только с небольшими документами. BS4 код обработчика даже не вызывается, что затрудняет отладку, но это не гарантия, что проблема на стороне lxml. "

Небольшая настройка примера полезного кода Дж. Ф. Себастьяна дает размер, при котором код не выполняется:

>>> from bs4 import BeautifulSoup
>>> from itertools import count
>>> for n in count():
    s = "<a>" + " " * n + "</a>"
    nchildren = len(BeautifulSoup(s, 'xml'))
    if nchildren != 1: # broken
       print(len(s)) 
       break

1092

Код обрабатывает xml, как и ожидалось, для числа символов, меньшего или равного 1091. XML строки длиной больше или равной 1092 обычно не выполняется.

UPDATE: BeautifulSoup 4.0.2 был выпущен с обходным путем:

"Эта новая версия работает с ошибкой в ​​lxml XMLParser.feed (), который мешал BS анализировать XML-документы больше, чем около 512-1024 символов. «

0 голосов
/ 23 марта 2012

после того, как я проверил, что кажется, что запуск len на объекте Beautifulsoup не возвращает длину в байтах, но какое-то другое свойство (глубина узла или что-то еще ... не совсем уверен)

...