2015-04-01 23 views
7

我想解析OpenStreetMap的planet.osm,以bz2格式压缩。因为它已经是41G,我不想完全解压文件。用python中的lxml iterparse解析一个大的.bz2文件(40 GB)。没有出现未压缩文件的错误

所以我想通了如何解析使用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完美的作品。然而,当我尝试分析行星latest.osm.bz2具有相同的脚本我得到的错误:

xml.etree.XMLSyntaxError: Specification mandate value for attribute num_change, line 3684, column 60

这里是我试过的东西:

  • 检查行星最新的。 osm.bz2 md5sum
  • 检查行星latest.osm脚本与bz2停止。没有明显的错误,并且该属性被称为“num_changes”,而不是“num_change”,如错误
  • 所示。另外我做了一些愚蠢的事情,但是这个错误使我感到困惑:我打开了planet- latest.osm.bz2 mode'rb'[c = BZ2File('file.osm.bz2','rb')],然后将c.read()传递给iterparse(),它返回了一个错误,表示(非常长的字符串)无法打开。奇怪的事情,(很长的字符串)结束身在何方“规范授权值”的错误指的是......

然后我试图解压缩第一planet.osm.gz2全光照简单

bzcat planet.osm.gz2 > planet.osm 

然后直接在planet.osm上运行解析器。而且...它的工作!我对此感到非常困惑,并且找不到任何可能发生的原因以及如何解决这个问题。我的猜测是解压缩和解析之间会发生什么,但我不确定。请帮我理解!

+0

不能告诉是肯定的,当然的,但'BZ2File(file.osm.bz2 ,'rb')'看起来不正确,因为根据文档,第一个参数被假定为_filename_(即字符串)。 – martineau 2015-04-01 21:58:41

+0

感谢您指出这一点!但在原始代码中是正确的,我只是编辑了我的问题以避免混淆。 – scities 2015-04-01 22:27:45

+1

在bz2模块中可能存在一个错误(我怀疑它经常被维护人员在40GB输入上测试)。尝试编写一个使用bz2模块来解压缩数据并将其写入新文件的Python脚本,并验证输出是否与'bzcat'输出匹配。 – 2015-04-01 22:28:47

回答

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,实现了OSM通用解析器一个Python模块数据(以pbf或xml格式)。你可能想看看这个!

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