我观察到一种在使用BeautifulSoup4时发现奇怪的行为。 我有以下XML(文件名:fake_product.xml):
<product acronym="ACRO1">
<formats>
<format id="format1">
</format>
<format id="format2">
</format>
<format id="format3">
</format>
<format id="format4">
</format>
<format id="format5">
</format>
<format id="format6">
</format>
</formats>
</product>
此TestCase
失败:
import unittest
from bs4 import BeautifulSoup
class Test(unittest.TestCase):
def setUp(self):
with open('fake_product.xml') as f:
self.soup = BeautifulSoup(f, 'xml')
def test_product_removal(self):
output = len(self.soup.find_all('format'))
expected = 6
self.assertEqual(output, expected)
format_to_delete = self.soup.find(id='format2')
format_to_delete.extract()
#self.soup = BeautifulSoup(self.soup.prettify(), 'xml')
output = len(self.soup.find_all('format'))
expected -= 1
self.assertEqual(output, expected)
原因是find_all()
无法找到所有格式。如果我这样做print self.soup.prettify()
一切看起来都很好。
如果我取消注释TestCase中的注释行并在extract()
之后创建一个新的BeautifulSoup对象,find_all()
似乎再次正常工作并且TestCase成功。
有人可以向我解释这种行为吗?
答案 0 :(得分:3)
这是4.4.0中引入的错误,请参阅BeautifulSoup 4 project bug tracker:
在某些情况下,似乎调用
extract()
无法正确调整前一个元素的next_sibling
属性。这将提取的元素留在后代生成器中。稍后调用find(...)
或find_all(...)
时,搜索会终止于提取的元素,从而导致错过结果。
This bug也是相关的,包含一个潜在的修复方法:
第265,267,274,277行需要
!=
更改为is not
第290行需要
==
更改为is
我可以确认它修复了您的具体测试。
如果您对编辑BeautifulSoup源代码感到不舒服,那么解决方法就是像您一样重建树,或者降级到4.3.2直到修复程序出来为止。