【发布时间】:2020-11-28 12:56:35
【问题描述】:
案例:
我正在尝试读取一个 XML 文件,使用 BeautifulSoup 从其中提取少量数据,将数据添加到字典中,关闭文件,然后进入下一个文件。提取所需数据后,应关闭文件并从内存中释放。
问题:
程序最终会因内存错误而停止,并且任务管理器清楚地显示每个文件之后的内存消耗量都在增加,这让我相信我的文件没有正确关闭或从内存中释放。在我的环境中,这将在读取大约 200 个文件后发生。
我尝试过但没有成功的事情:
-
用 gc.collect() 收集垃圾(似乎没什么区别)
-
用soup.decompose()分解文件(好像没什么区别)
-
各种不同大小的文件
-
SoupStrainer(有/没有它几乎没有区别)
我找到了 2 个“解决方案”:
-
强制脚本在一段时间后自行重启(不是最佳的)
-
64 位版本和更多物理内存(不是最佳)
文件信息:
- 大小从 100kb 到 5mb 不等
- 每个文件 10.000 到 70.000 行。
- 标准 .xml 格式
EXML 结构示例/来自文件的 sn-p。 (最多可以有 70.000 行):
<!-- language: xml -->
<Partner>
<Language>en-US</Language>
<PartnerRole>stackoverflow1</PartnerRole>
<IsSalesAreaDependent>True</IsSalesAreaDependent>
<ContactPerson>
<ContactPerson>
<Language>en-US</Language>
</ContactPerson>
</ContactPerson>
<InheritFromSoldTo>True</InheritFromSoldTo>
<SalesAreaData>
<SalesAreaData>
<Language>en-US</Language>
<Valid>False</Valid>
<SalesOrganization>stackoverflow2</SalesOrganization>
<DistributionChannel>stackoverflow3</DistributionChannel>
<SalesDivision>stackoverflow4</SalesDivision>
<CustomerGroup />
<Currency>stackoverflow5</Currency>
<PriceGroup />
<PriceList>stackoverflow6</PriceList>
<ShippingConditions />
<Plant />
<PaymentTerms />
</SalesAreaData>
</SalesAreaData>
<CustomerHierarchy />
</Partner>
代码:
for fname in glob.glob(path+"/Quotes/**/*.quote"): #Further define path
with open(fname, encoding="utf8") as open_file:
gc.collect()
counter += 1
contents = open_file.read()
soup = BeautifulSoup(contents, 'lxml')
try:
results = ("("+str(counter)+") " + " Ref: " + soup.quickref.string + " Last modified: " + soup.modifieddate.string)
bsize = os.path.getsize(fname)
totalsize += bsize
tempdata = (soup.modifieddate.string, soup.quickref.string, soup.ownerusername.string, soup.companyname.string, soup.totalnetvalue.string, fname)
dictHolder[counter] = tempdata
except AttributeError:
results = "("+ str(counter) + ")" + "Invalid data / corrupted file, please check: " + fname
corruptCounter += 1
soup.decompose()
gc.collect()
print (results)
10/08/2020:问题已通过切换到 xml.etree.elementtree 模块“解决”,并不能真正算作答案或解决方案,但如果将来有人遇到同样的问题并阅读这个,试试上面的模块。
【问题讨论】:
-
with open块不应该在 for 循环中吗? -
很好看。它在实际代码中,但我似乎无法弄清楚如何在 stackoverflow 上缩进它。如果有人熟悉 StackOverflow 格式,请缩进该部分,谢谢。
-
不知道为什么需要BeautifulSoup,但可以直接使用底层引擎
lxml,它可以在没有open的情况下解析文件。此外,.readis memory-intensive 并且可能不会在for循环内释放回来。请发布 XML 示例,以便我们可以看到树。 -
我用 XML 结构的示例更新了 OP。可能值得注意的是,每个循环不仅消耗更多内存,而且每个循环的速度也越来越慢(尽管实际文件的大小或复杂性没有增加)我不一定“需要” beatifulsoup,但我发现它很容易与我在 Python 中相对初学者的技能相关的工作。
-
10/08 更新:通过将模块切换到“xml.etree.ElementTree”,问题已“解决”,否则代码相同或相似。切换到不同的模块并不能真正算作一个答案,所以我会留下这个,以防有人发现它有用或想通了。总处理时间从 ~2 小时缩短到 ~5 分钟。
标签: python xml memory beautifulsoup