【问题标题】:Convert CSV to mongoimport-friendly JSON using Python使用 Python 将 CSV 转换为 mongoimport 友好的 JSON
【发布时间】:2012-11-08 19:35:40
【问题描述】:

我有一个 300 mb 的 CSV,其中包含来自 Geonames.org 的 300 万行城市信息。我正在尝试将此 CSV 转换为 JSON 以使用 mongoimport 导入 MongoDB。我想要 JSON 的原因是它允许我将“loc”字段指定为数组而不是与地理空间索引一起使用的字符串。 CSV 以 UTF-8 编码。

我的 CSV 的 sn-p 如下所示:

"geonameid","name","asciiname","alternatenames","loc","feature_class","feature_code","country_code","cc2","admin1_code","admin2_code","admin3_code","admin4_code"
3,"Zamīn Sūkhteh","Zamin Sukhteh","Zamin Sukhteh,Zamīn Sūkhteh","[48.91667,32.48333]","P","PPL","IR",,"15",,,
5,"Yekāhī","Yekahi","Yekahi,Yekāhī","[48.9,32.5]","P","PPL","IR",,"15",,,
7,"Tarvīḩ ‘Adāī","Tarvih `Adai","Tarvih `Adai,Tarvīḩ ‘Adāī","[48.2,32.1]","P","PPL","IR",,"15",,,

与 mongoimport 一起使用的所需 JSON 输出(字符集除外)如下:

{"geonameid":3,"name":"Zamin Sukhteh","asciiname":"Zamin Sukhteh","alternatenames":"Zamin Sukhteh,Zamin Sukhteh","loc":[48.91667,32.48333] ,"feature_class":"P","feature_code":"PPL","country_code":"IR","cc2":null,"admin1_code":15,"admin2_code":null,"admin3_code":null,"admin4_code":null}
{"geonameid":5,"name":"Yekahi","asciiname":"Yekahi","alternatenames":"Yekahi,Yekahi","loc":[48.9,32.5] ,"feature_class":"P","feature_code":"PPL","country_code":"IR","cc2":null,"admin1_code":15,"admin2_code":null,"admin3_code":null,"admin4_code":null}
{"geonameid":7,"name":"Tarvi? ‘Adai","asciiname":"Tarvih `Adai","alternatenames":"Tarvih `Adai,Tarvi? ‘Adai","loc":[48.2,32.1] ,"feature_class":"P","feature_code":"PPL","country_code":"IR","cc2":null,"admin1_code":15,"admin2_code":null,"admin3_code":null,"admin4_code":null}

我已经尝试了所有可用的在线 CSV-JSON 转换器,但由于文件大小,它们无法正常工作。我得到的最接近的是Mr Data Converter(如上图所示),它会在删除文档之间的开始和结束括号以及逗号后导入到 MongoDb。不幸的是,该工具不适用于 300 mb 的文件。

上面的 JSON 设置为 UTF-8 编码,但仍有字符集问题,很可能是由于转换错误?

过去三天我在学习 Python,尝试使用 Python CSVKIT,尝试了 stackoverflow 上的所有 CSV-JSON 脚本,将 CSV 导入 MongoDB 并将“loc”字符串更改为数组(不幸的是,这保留了引号)甚至尝试一次手动复制和粘贴 30,000 条记录。大量的逆向工程、反复试验等等。

有没有人知道如何实现上面的 JSON,同时像上面的 CSV 一样保持正确的编码?我完全处于静止状态。

【问题讨论】:

  • 我的问题是关于格式而不是错误消息。我没有收到任何错误,但也没有收到所需的输出。
  • 这个问题不是重复的:上面提到的另一个问题中没有编码问题和特殊的输出格式要求。

标签: python json csv geospatial mongoimport


【解决方案1】:

Python 标准库(加上用于十进制编码支持的 simplejson)拥有你所需要的一切:

import csv, simplejson, decimal, codecs

data = open("in.csv")
reader = csv.DictReader(data, delimiter=",", quotechar='"')

with codecs.open("out.json", "w", encoding="utf-8") as out:
   for r in reader:
      for k, v in r.items():
         # make sure nulls are generated
         if not v:
            r[k] = None
         # parse and generate decimal arrays
         elif k == "loc":
            r[k] = [decimal.Decimal(n) for n in v.strip("[]").split(",")]
         # generate a number
         elif k == "geonameid":
            r[k] = int(v)
      out.write(simplejson.dumps(r, ensure_ascii=False, use_decimal=True)+"\n")

其中“in.csv”包含您的大 csv 文件。上面的代码被测试为在 Python 2.6 和 2.7 上工作,具有大约 100MB 的 csv 文件,生成正确编码的 UTF-8 文件。根据要求,不带括号、数组引用或逗号分隔符。

还值得注意的是,要使编码正常工作(在这种情况下),需要同时传递 ensure_ascii 和 use_decimal 参数。

最后,作为based on simplejson,python stdlib json 包迟早也会获得十进制编码支持。所以最终只需要stdlib。

【讨论】:

  • Petri,谢谢,它成功了!你是最棒的!是否可以以与 CSV 相同的方式对输出进行排序并将 geonameid 字段保留为数字而不是使其成为字符串?该脚本在 geonameid 字段中添加了引号。
  • 更新了示例,因此 geonameid 也被编码为数字。顺序在这里真的很重要,还是您只是为了完美而追求完美? :) 您可以切换到使用常规 csv.reader,首先阅读标题行:headers=reader.next(),然后使用它为每一行生成有序字典,即。 r=OrderedDict(zip(headers, row))。试试看,我相信你能成功。
  • 我注意到备用名称字段在查询时工作非常缓慢,因为整个字段被视为单个字符串。如果每个替代名称都放在引号内并将该字段制成数组,则搜索会快得多。该字段如下所示:alternatenames:["Zamin Sukhteh", "Zamīn Sūkhteh"] 是否可以更新解决方案以使用 Python 实现这一点?我认为任何将 geonames 数据库转换为 MongoDB 的人都可能会发现这更好,因为目前无法对该字段进行查询。
【解决方案2】:

也许您可以尝试将 csv 直接导入 mongodb 使用

mongoimport -d <dB> -c <collection> --type csv --file location.csv --headerline

【讨论】:

  • 这种方法在我的一个服务器上为我节省了大量内存 v. 运行一个首先读取 .csv 文件的 python 脚本。
  • 我很高兴听到这个消息 :-)
猜你喜欢
  • 2018-01-04
  • 2019-02-23
  • 2021-09-01
  • 2021-12-03
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多