2014-07-10 53 views
0

我知道这个问题已经被问过,但从未有以下注意事项:转换修改JSON到CSV使用python

  • 我是一个完整的Python的n00b。还有一个JSON noob。
  • JSON文件/字符串与json2csv示例中显示的不一样。
  • CSV文件输出应该有标准列。

由于第一点,我不知道用于此的大多数术语和技术。所以请耐心等待。

点号2:这里的应该 JSON文件的一行:

"id":"123456","about":"YESH","can_post":true,"category":"Community","checkins":0,"description":"OLE!","has_added_app":false,"is_community_page":false,"is_published":true,"likes":48,"link":"www.fake.com","name":"Test Name","parking":{"lot":0,"street":0,"valet":0},"talking_about_count":0,"website":"www.fake.com/blog","were_here_count":0^ 

奇怪,我知道 - 它缺乏支撑和支架之类的东西。这就是为什么我确信发布的解决方案不起作用。

我不确定线末端的0 ^是什么,但我在每一行的末尾看到它。我假设0是“are_here_count”的值,而^是行终止符?编辑:显然,我可以忽略它。

值得注意的是,“停车”的价值似乎是另一个数组 - 我很好,只是显示它(减去双引号)。

点数3:以下是所需CSV文件输出的列。这是完整的列集--JSON文件并不总是全部包含它们。

ID STRING, 
ABOUT STRING, 
ATTIRE STRING, 
BAND_MEMBERS STRING, 
BEST_PAGE STRING, 
BIRTHDAY STRING, 
BOOKING_AGENT STRING, 
CAN_POST STRING, 
CATEGORY STRING, 
CATEGORY_LIST STRING, 
CHECKINS STRING, 
COMPANY_OVERVIEW STRING, 
COVER STRING, 
CONTEXT STRING, 
CURRENT_LOCATION STRING, 
DESCRIPTION STRING, 
DIRECTED_BY STRING, 
FOUNDED STRING, 
GENERAL_INFO STRING, 
GENERAL_MANAGER STRING, 
GLOBAL_BRAND_PARENT_PAGE STRING, 
HOMETOWN STRING, 
HOURS STRING, 
IS_PERMANENTLY_CLOSED STRING, 
IS_PUBLISHED STRING, 
IS_UNCLAIMED STRING, 
LIKES STRING, 
LINK STRING, 
LOCATION STRING, 
MISSION STRING, 
NAME STRING, 
PARKING STRING, 
PHONE STRING, 
PRESS_CONTACT STRING, 
PRICE_RANGE STRING, 
PRODUCTS STRING, 
RESTAURANT_SERVICES STRING, 
RESTAURANT_SPECIALTIES STRING, 
TALKING_ABOUT_COUNT STRING, 
USERNAME STRING, 
WEBSITE STRING, 
WERE_HERE_COUNT STRING 

这里是我到目前为止的代码:

import os 

num = '1' 
inPath = "./fb-data_input/" 
outPath = "./fb-data_output/" 
#Get list of Files, put them in filenameList array 
fileNameList = os.listdir(path) 
#Process per file in 
for item in fileNameList: 
    print("Processing: " + item) 
    fb_inputFile = open(inPath + item, "rb").read().split("\n") 
    fb_outputFile = open(outPath + "fbdata-IAB-output" + num, "wb") 
    num++ 
    jsonString = fb_inputFile.split("\",\"") 
    jsonField = jsonString[0] 
    jsonValue = jsonString[1] 
    jsonHash[?] = [?,?] 
    #Do Code stuff here 

直到for循环,它只是用来加载JSON文件名到一个数组,然后处理它一个接一个。

这里是我的代码的其余部分的逻辑:

  • 分割的东西JSON字符串。也许这个“,”使其他逗号不会分裂。
  • 将它存储到hashmap/2D数组(动态?)
  • 修剪掉JSON字段和第一个和/或最后一个双引号。
  • 将生成的输出添加到另一个散列映射,使用那些设置的列,将空值放入JSON文件不具有的列中。

然后我输出结果到CSV。

这听起来很符合我的想法,但我敢肯定,我错过了一些东西。当然,我很难把它放在代码中。

我可以帮忙吗?谢谢。

P.S.

其他信息:

  • 操作系统:Mac OSX
  • 目标平台操作系统:某种Ubuntu的
+0

JSON文件的行是否对应于单个数据记录? –

+0

“停车”:{“lot”:0,“street”:0,“valet”:0}如何映射到CSV的'PARKING'列? –

+0

行尾末尾的'^'字符表示什么? –

回答

1

这里是一个完整的解决方案,根据您的原始代码:

import os 
import json 
from csv import DictWriter 
import codecs 

def get_columns(): 
    columns = [] 
    with open("columns.txt") as f: 
     columns = [line.split()[0] for line in f if line.strip()] 
    return columns 

if __name__ == "__main__": 
    in_path = "./fb-data_input/" 
    out_path = "./fb-data_output/" 
    columns = get_columns() 
    bad_keys = ("has_added_app", "is_community_page") 
    for filename in os.listdir(in_path): 
     json_filename = os.path.join(in_path, filename) 
     csv_filename = os.path.join(out_path, "%s.csv" % (os.path.basename(filename))) 
     with open(json_filename) as f, open(csv_filename, "wb") as csv_file: 
      csv_file.write(codecs.BOM_UTF8) 
      csv = DictWriter(csv_file, columns) 
      csv.writeheader() 
      for line_number, line in enumerate(f, start=1): 
       try: 
        data = json.loads("{%s}" % (line.strip().strip('^'))) 
        # fix parking column 
        if "parking" in data: 
         data['parking'] = ", ".join("%s: %s" % (k, str(v)) for k, v in data['parking'].items()) 
        data = {k.upper(): unicode(v).encode('utf8') for k, v in data.items() if k not in bad_keys} 
       except Exception, e: 
        import traceback 
        traceback.print_exc() 
        data = {columns[0]: "Error on line %s of %s: %s" % (line_number, json_filename, e)} 
       csv.writerow(data) 

编辑:完整的Unicode支持以及扩展的错误信息。

+0

对于变量名称,camelCase和下划线的组合是什么? – Eli

+0

@Eli哈!没有注意到!骆驼套的是从OP复制的,下划线的是我。更好? :) –

+1

好得多。 Pep8 FTW! :) – Eli

1

所以,首先,你的字符串是有效的JSON,如果你只需要添加花括号周围。然后您可以使用Python的json库进行反序列化。将csv列设置为字典,每个列都指向任何你想要的默认值(None?“”?你是选择)。将json反序列化为字典后,只需循环每个键并根据需要填入csv_columns字典。然后,只需使用Python的CSV模块写出来:

import json 
import csv 
string = '"id":"123456","about":"YESH","can_post":true,"category":"Community","checkins":0,"description":"OLE!","has_added_app":false,"is_community_page":false,"is_published":true,"likes":48,"link":"www.fake.com","name":"Test Name","parking":{"lot":0,"street":0,"valet":0},"talking_about_count":0,"website":"www.fake.com/blog","were_here_count":0^' 
string = '{%s}' % string[:-1] 
json_dict = json.loads(string) 
#make 'parking' a string. I'm assuming that's your only hash. 
json_dict['parking'] = json.dumps(json_dict['parking']) 
csv_cols_list = ['a','b','c'] #put your actual csv columns here 
csv_cols = {col: '' for col in csv_cols_list} 
for k, v in json_dict.iterkeys(): 
    if k in csv_cols: 
     csv_cols[k] = v 
#now just write to csv using Python's csv library 

注:这是假设你的“JSON”将是有效的键/值对一般的答案。您的“停车”键是您需要以某种方式处理的特殊情况。我离开它,因为我不知道你想要什么。我还假设字符串末尾的'^'是一个错字。

[编辑]更改为帐户parking和'^'在最后。 [/编辑]

无论哪种方式,这里的一般想法是你想要的。

+0

自发布以来,我编辑了这个问题,很抱歉在早期缺乏细节。 “停车”键可以保持原样 - 一个字符串。 –

1

第一件事是你的输入不是JSON。它只是一个分隔字符串,列和值被引用。

这里是将工作的解决方案:

import csv 

columns = ['ID', 'ABOUT', ... ] 

with open('input_file.txt', 'r') as f, open('output_file.txt', 'w') as o: 
    reader = csv.reader(f, delimiter=',') 
    writer = csv.writer(o, delimiter=',') 
    writer.writerow(columns) 
    for row in reader: 
     data = {k.upper():v for k,v in row.split(':', 1)} 
     row = [data.get(v, '') for v in columns] 
     writer.writerow(row) 

在这个循环中,对于每一个我们从输入文件中读取行,创建一个字典。关键是'foo:bar'对中的第一个值,我们将其转换为大写。

接下来,对于每一列,我们尝试从这个字典中按列写出的顺序获取一个值。如果该列的值不存在,则返回空白''。这些值收集在列表中row。这可以确保无论缺少多少列,我们都会向输出写入相同数量的列。

+0

这会在他的“停车”键上打破。 – Eli

+0

不,它不会。该值是一个单独的字符串,并且在输出中只有一列用于“停放”。请记住输入不是有效的JSON,它只是一个字符串。 –

+0

你正在拆分“:”上的行。这将使你的钥匙与括号中的停车位,如“{”lot“:0'。这不是OP想要的。 – Eli