我正在尝试解析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]
与Geofabrick extracts完美配合。但是,当我尝试使用相同的脚本解析planet-latest.osm.bz2时,我得到错误:
xml.etree.XMLSyntaxError:属性num_change的规范授权值,第3684行,第60列
以下是我尝试过的事情:
然后我尝试首先使用简单的
解压缩planet.osm.gz2bzcat planet.osm.gz2 > planet.osm
直接在planet.osm上运行解析器。而且......它奏效了!我对此感到非常困惑,并且找不到任何可能发生这种情况的指针以及如何解决这个问题。我的猜测是解压缩和解析之间会发生一些事情,但我不确定。请帮我理解!
答案 0 :(得分: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]
另外,做了一些关于使用PBF格式的研究(正如评论中所建议的),我偶然发现了imposm.parser,这是一个python模块,它实现了OSM数据的通用解析器(pbf或xml格式)。你可能想看看这个!
答案 1 :(得分:2)
作为替代方案,您可以使用bzcat
命令的输出(也可以处理多流文件):
p = subprocess.Popen(["bzcat", "data.bz2"], stdout=subprocess.PIPE)
parser = et.iterparse(p.stdout, ...)
# at the end just check that p.returncode == 0 so there were no errors