在python中使用lxml iterparse解析一个大的.bz2文件(40 GB).未压缩文件未出现的错误

sci*_*ies 8 python xml lxml openstreetmap

我试图解析OpenStreetMap的planet.osm,以bz2格式压缩.因为它已经是41G,所以我不想完全解压缩文件.

所以我想出了如何使用bz2和lxml解析planet.osm文件的部分,使用以下代码

from lxml import etree as et
from bz2 import BZ2File

path = "where/my/fileis.osm.bz2"
with BZ2File(path) as xml_file:
    parser = et.iterparse(xml_file, events=('end',))
    for events, elem in parser:

        if elem.tag == "tag":
            continue
        if elem.tag == "node":
            (do something)


    ## Do some cleaning
    # Get rid of that element
    elem.clear()

    # Also eliminate now-empty references from the root node to node        
    while elem.getprevious() is not None:
        del elem.getparent()[0]
Run Code Online (Sandbox Code Playgroud)

Geofabrick提取物完美配合.但是,当我尝试使用相同的脚本解析planet-latestm.bz2时,我得到错误:

xml.etree.XMLSyntaxError:属性num_change的规范授权值,第3684行,第60列

以下是我尝试过的事情:

  • 检查planet-latest.osm.bz2 md5sum
  • 检查带有bz2的脚本停止的planet-latest.osm.没有明显的错误,该属性称为"num_changes",而不是错误中指示的"num_change"
  • 我也做了一些愚蠢的事,但错误让我困惑:我在模式'rb'中打开了planet -osm.bz2 [c = BZ2File('file.osm.bz2','rb')]然后传递了c. read()到iterparse(),它返回了一个错误说(很长的字符串)无法打开.奇怪的是,(非常长的字符串)在"规范授权值"错误引用的地方结束......

然后我尝试首先解压缩planet.osm.gz2

bzcat planet.osm.gz2 > planet.osm
Run Code Online (Sandbox Code Playgroud)

并直接在planet.osm上运行解析器.而且......它奏效了!我对此感到非常困惑,并且找不到任何可能发生这种情况的指针以及如何解决这个问题.我的猜测是解压缩和解析之间会发生一些事情,但我不确定.请帮我理解!

sci*_*ies 5

事实证明,问题在于压缩的planet.osm文件.

OSM Wiki所示,行星文件被压缩为多流文件,而bz2 python模块无法读取多流文件.但是,bz2文档指示可以读取此类文件的替代模块bz2file.我用过它,它完美无缺!

所以代码应该是:

from lxml import etree as et
from bz2file import BZ2File

path = "where/my/fileis.osm.bz2"
with BZ2File(path) as xml_file:
    parser = et.iterparse(xml_file, events=('end',))
    for events, elem in parser:

        if elem.tag == "tag":
            continue
        if elem.tag == "node":
            (do something)


    ## Do some cleaning
    # Get rid of that element
    elem.clear()

    # Also eliminate now-empty references from the root node to node        
    while elem.getprevious() is not None:
        del elem.getparent()[0]
Run Code Online (Sandbox Code Playgroud)

另外,做了一些关于使用PBF格式的研究(正如评论中所建议的),我偶然发现了imposm.parser,一个python模块,它实现了OSM数据的通用解析器(以pbf或xml格式).你可能想看看这个!