将xml文件从url解析为令人讨厌的votable,而无需下载

问题描述 投票:0回答:1

http://svo2.cab.inta-csic.es/theory/fps/中,您可以获得在天文观测中使用的许多滤波器的透射曲线。我想通过使用相应的xml文件(对于每个过滤器)打开url来获取这些数据,并将其解析为astropy的votable,有助于轻松读取表数据。

我设法通过打开将其转换为UTF-8文件的文件并将其另存为xml来做到这一点。然后打开本地文件就可以了,如下面的示例所示。

但是我不想保存文件并再次打开它。当我尝试执行以下操作时:votable = parse(xml_file),它将引发OSError:文件名太长,因为它将所有文件都当作字符串。

from urllib.request import urlopen

fltr = 'http://svo2.cab.inta-csic.es/theory/fps/fps.php?ID=2MASS/2MASS.H'
url = urlopen(fltr).read()
xml_file = url.decode('UTF-8')
with open('tmp.xml','w') as out:
    out.write(xml_file)

votable = parse('tmp.xml')
data = votable.get_first_table().to_table(use_names_over_ids=True)

print(votable)
print(data["Wavelength"])

在这种情况下的输出是:

<VOTABLE>... 1 tables ...</VOTABLE>
Wavelength
AA    
----------
12890.0
13150.0
...
18930.0
19140.0
Length = 58 rows
python-3.x xml-parsing astropy urlopen
1个回答
1
投票
seekable,这意味着可以通过随机访问来读取它。

HTTPResponse返回的urlopen对象确实是具有.read()方法的类似文件的对象,因此原则上可以直接传递给parse(),但这是我发现它的方式易于寻找:

fltr = 'http://svo2.cab.inta-csic.es/theory/fps/fps.php?ID=2MASS/2MASS.H' u = urlopen(fltr) >>> parse(u) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "astropy/io/votable/table.py", line 135, in parse _debug_python_based_parser=_debug_python_based_parser) as iterator: File "/usr/lib/python3.6/contextlib.py", line 81, in __enter__ return next(self.gen) File "astropy/utils/xml/iterparser.py", line 157, in get_xml_iterator with _convert_to_fd_or_read_function(source) as fd: File "/usr/lib/python3.6/contextlib.py", line 81, in __enter__ return next(self.gen) File "astropy/utils/xml/iterparser.py", line 63, in _convert_to_fd_or_read_function with data.get_readable_fileobj(fd, encoding='binary') as new_fd: File "/usr/lib/python3.6/contextlib.py", line 81, in __enter__ return next(self.gen) File "astropy/utils/data.py", line 210, in get_readable_fileobj fileobj.seek(0) io.UnsupportedOperation: seek

因此,您需要将数据包装在可搜索的类似文件的对象中。遵循@keflavich所写的内容,您可以使用io.BytesIOio.StringIO将无法使用,如下所述)。

事实证明,没有理由将UTF-8数据显式解码为unicode。我将保留该示例,但是我自己尝试之后,发现parse()适用于原始字节(我觉得有些奇怪,但是还可以)。因此,您可以将URL的全部内容读取到io.BytesIO中,它只是一个类似于内存文件的对象,支持随机访问:

>>> u = urlopen(fltr) >>> s = io.BytesIO(u.read()) >>> v = parse(s) WARNING: W42: None:2:0: W42: No XML namespace specified [astropy.io.votable.tree] >>> v.get_first_table().to_table(use_names_over_ids=True) <Table masked=True length=58> Wavelength Transmission AA float32 float32 ---------- ------------ 12890.0 0.0 13150.0 0.0 ... ... 18930.0 0.0 19140.0 0.0

通常,这是Python中处理某些数据的方式,就好像它是一个文件,而没有将实际文件写入文件系统的方式。

但是请注意,如果整个文件都无法容纳在内存中,则将无法使用。在这种情况下,您可能仍需要将其写出到磁盘。但是,如果只是为了进行一些临时处理而又不想像示例中那样乱扔磁盘tmp.xml,则可以始终使用tempfile模块来创建临时文件,这些临时文件一旦被删除便会自动删除不再使用。
© www.soinside.com 2019 - 2024. All rights reserved.