2014-07-10 83 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