1

Amazon AWS Data Pipeline 提供一个 CSV 文件作为 MySQL 数据库的输出。在 CSV 中,有一个包含 JSON 的字段,我们尝试分别使用 Python 的内置 CSV 和 JSON 阅读器对其进行提取和解码。但是,由于 CSV 的生成方式,JSON 不以引号开头,并且 CSV 解析器仅返回该 CSV 字段的 JSON 中的第一个“{”。

我们认为 CSV 阅读器会看到第一个“{”,然后会看到一个换行符,它将其解释为 CSV 行的结尾。如果 JSON 包含在引号中,则脚本可以正常工作。请参阅以下代码:

with open(args.env_vars[0] + '/click_stream_source.csv', 'r') as csvFile:
    csvReader = csv.reader(csvFile, delimiter = ',')
    with open(args.env_vars[1] + '/clickstream_target.csv', 'wb') as csvTarget:
        csvWriter = csv.writer(csvTarget, delimiter = ',')
        for row in csvReader:
            json_data = json.loads(row[5])

示例 CSV 是:

    495019,,8239,E3728E7D480248AA2EB5D5BB5C467737,67.84.254.6,{
            ""requests"": [
          {
             ""queryString"": null,
             ""time"": ""2013-06-14T11:53:40Z"",
             ""userAgent"": ""Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"",
             ""requestURI"": ""/xxxxx/xxxx/xxxx.xxxxxxx"",
             ""class"": ""xxxxx"",
             ""params"": {
                ""action"": ""xxxxx"",
                ""controller"": ""xxxx""
             },
             ""isAjaxRequest"": false
          }]}

我们得到一个

ValueError:期望对象...

json.loads() 方法在哪里

4

4 回答 4

1

我认为这不能称为 CSV,因此 CSV 模块将无济于事。

您可以使用正则表达式转换[\r\n]\s+为空格。如果“JSON”是最后一个字段,您可以按列数进行拆分(将最后一列转换为有效 JSON 所需的转换留给读者作为作业)示例:

In [1]: l = """495019,,8239,E3728E7D480248AA2EB5D5BB5C467737,67.84.254.6,{
   ...:             ""requests"": [
   ...:           {
   ...:              ""queryString"": null,
   ...:              ""time"": ""2013-06-14T11:53:40Z"",
   ...:              ""userAgent"": ""Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"",
   ...:              ""requestURI"": ""/xxxxx/xxxx/xxxx.xxxxxxx"",
   ...:              ""class"": ""xxxxx"",
   ...:              ""params"": {
   ...:                 ""action"": ""xxxxx"",
   ...:                 ""controller"": ""xxxx""
   ...:              },
   ...:              ""isAjaxRequest"": false
   ...:           }]}"""

In [2]: import re

In [3]: l_ = re.sub(r'[\n\r]\s+', ' ', l)

In [4]: l_
Out[4]: '495019,,8239,E3728E7D480248AA2EB5D5BB5C467737,67.84.254.6,{ ""requests"": [ { ""queryString"": null, ""time"": ""2013-06-14T11:53:40Z"", ""userAgent"": ""Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"", ""requestURI"": ""/xxxxx/xxxx/xxxx.xxxxxxx"", ""class"": ""xxxxx"", ""params"": { ""action"": ""xxxxx"", ""controller"": ""xxxx"" }, ""isAjaxRequest"": false }]}'

In [5]: l_.split(',', 5)
Out[5]:
['495019',
 '',
 '8239',
 'E3728E7D480248AA2EB5D5BB5C467737',
 '67.84.254.6',
 '{ ""requests"": [ { ""queryString"": null, ""time"": ""2013-06-14T11:53:40Z"", ""userAgent"": ""Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"", ""requestURI"": ""/xxxxx/xxxx/xxxx.xxxxxxx"", ""class"": ""xxxxx"", ""params"": { ""action"": ""xxxxx"", ""controller"": ""xxxx"" }, ""isAjaxRequest"": false }]}']

查看“JSON”中的行拆分是否与记录末尾不同(例如,一个是\n,另一个是\r\n,这可以使您的工作更轻松。

这有点骇人听闻——正确的实现可能应该使用解析器(正式的 EBNF 语法应该在 10 行以下)。

于 2013-06-14T23:25:04.350 回答
1

我认为从技术上讲你不能调用这个 CSV,因为它违反了解析规则,但我并不是想学究气,我想说这是放弃内置解析工具并走老路的原因,做一个有限状态机。这是一个简单粗暴的示例,您可以根据自己的目的进行调整。

#!/usr/bin/env python
import re
import json

def fix_and_parse(gathered_lines):
    strJson = '{' + "\n".join(gathered_lines)
    strJson = strJson.replace('""', '"')
    return json.loads(strJson)

state = 0
with open('csvFile', 'r') as csvFile:
    gathered_lines = []
    for line in csvFile:
        if re.search('^\d', line):
            if gathered_lines:
                print json.dumps(fix_and_parse(gathered_lines), indent=4)
            state = 0
            gathered_lines = []
        else:
            state = 1
        if state == 1:
            gathered_lines.append(line)
print json.dumps(fix_and_parse(gathered_lines), indent=4)
于 2013-06-14T23:44:41.713 回答
1

这里有一些非常有趣的建议,但经过进一步考虑,我的团队决定我们将寻求更直接的解决方案。不幸的是,对于未来的读者来说,这有点特定于 MySQL/AWS CSV,但我们决定更正 SQL 查询本身中的问题:

SELECT RANDOM_FIELD, RANDOM_FIELD2, ..., REPLACE(JSON_FIELD,'\n','NEWLINE') FROM DATABASE ....

这修复了真正有问题的换行符,而不是 CSV。请注意,最初的目标是用 \\n 替换 \n,但 CSV 生成器再次删除了转义“\”。话虽如此,我真的很喜欢 Paulo Scardine 的解决方案,它在我们使用的少数测试用例中运行良好;如果 JSON 中的字符串实际上包含换行符,似乎可能存在问题(这是我们没有机会与数据库作者讨论的问题)。

于 2013-06-15T04:17:09.340 回答
0

您既没有有效的 csv 也没有有效的 json。

您可以使用正则表达式将 [\r\n]\s+ 变成空格

出于什么目的?

import json

data = '''495019,,8239,E3728E7D480248AA2EB5D5BB5C467737,67.84.254.6,{
            "requests": [
          {
             "queryString": null,
             "time": "2013-06-14T11:53:40Z",
             "userAgent": "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)",
             "requestURI": "/xxxxx/xxxx/xxxx.xxxxxxx",
             "class": "xxxxx",
             "params": {
                "action": "xxxxx",
                "controller": "xxxx"
             },
             "isAjaxRequest": false
          }]}'''

pieces = data.split(',', 5)
print pieces[5]

json_dict = json.loads( pieces[5] )
print json_dict['requests'][0]['time']

--output:--

{
            "requests": [
          {
             "queryString": null,
             "time": "2013-06-14T11:53:40Z",
             "userAgent": "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)",
             "requestURI": "/xxxxx/xxxx/xxxx.xxxxxxx",
             "class": "xxxxx",
             "params": {
                "action": "xxxxx",
                "controller": "xxxx"
             },
             "isAjaxRequest": false
          }]}

2013-06-14T11:53:40Z
于 2013-06-14T23:37:18.223 回答