Facebook JSON编码严重

Jak*_*yka 23 python unicode mojibake python-3.x

我下载了我的Facebook信使数据(在你的Facebook帐户中,转到设置,然后转到你的Facebook信息,然后下载你的信息,然后创建一个文件,至少选中了消息框)来做一些很酷的统计数据

但是编码有一个小问题.我不确定,但看起来Facebook对这些数据使用了错误的编码.当我用文本编辑器打开它时,我看到这样的事情:Rados\u00c5\u0082aw.当我尝试用python(UTF-8)打开它时,我得到了RadosÅ\x82aw.但是我应该得到:Rados?aw.

我的python脚本:

text = open(os.path.join(subdir, file), encoding='utf-8')
conversations.append(json.load(text))
Run Code Online (Sandbox Code Playgroud)

我尝试了一些最常见的编码.示例数据是:

{
  "sender_name": "Rados\u00c5\u0082aw",
  "timestamp": 1524558089,
  "content": "No to trzeba ostatnie treningi zrobi\u00c4\u0087 xD",
  "type": "Generic"
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 26

我确实可以确认Facebook下载数据编码不正确; 一个Mojibake.原始数据是UTF-8编码的,但是被解码为Latin -1.我会确保提交错误报告.

在此期间,您可以通过两种方式修复损坏:

  1. 将数据解码为JSON,然后将任何字符串重新编码为Latin-1,再次解码为UTF-8:

    >>> import json
    >>> data = r'"Rados\u00c5\u0082aw"'
    >>> json.loads(data).encode('latin1').decode('utf8')
    'Rados?aw'
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将数据加载为二进制,用\u00hh最后两个十六进制数字表示的字节替换所有序列,解码为UTF-8,然后解码为JSON:

    import re
    from functools import partial
    
    fix_mojibake_escapes = partial(
         re.compile(rb'\\u00([\da-f]{2})').sub,
         lambda m: bytes.fromhex(m.group(1).decode()))
    
    with open(os.path.join(subdir, file), 'rb') as binary_data:
        repaired = fix_mojibake_escapes(binary_data.read())
    data = json.loads(repaired.decode('utf8'))
    
    Run Code Online (Sandbox Code Playgroud)

    从您的示例数据中产生:

    {'content': 'No to trzeba ostatnie treningi zrobi? xD',
     'sender_name': 'Rados?aw',
     'timestamp': 1524558089,
     'type': 'Generic'}
    
    Run Code Online (Sandbox Code Playgroud)


小智 15

这是使用 jq 和 iconv 的命令行解决方案。在 Linux 上测试。

cat message_1.json | jq . | iconv -f utf8 -t latin1 > m1.json

  • @jjmerelo您需要它将转义字符转换为其原始 b0rked 形式。 (2认同)

hot*_*tas 8

我想用下面的递归代码片段来扩展@Geekmoss的答案,我用来解码我的Facebook数据。

import json

def parse_obj(obj):
    if isinstance(obj, str):
        return obj.encode('latin_1').decode('utf-8')

    if isinstance(obj, list):
        return [parse_obj(o) for o in obj]

    if isinstance(obj, dict):
        return {key: parse_obj(item) for key, item in obj.items()}

    return obj

decoded_data = parse_obj(json.loads(file))
Run Code Online (Sandbox Code Playgroud)

我注意到这效果更好,因为您下载的 facebook 数据可能包含字典列表,在这种情况下,由于 lambda 恒等函数,这些字典将“按原样”返回。


Gee*_*oss 6

我解析对象的解决方案parse_hook在加载/加载函数使用回调

import json


def parse_obj(dct):
    for key in dct:
        dct[key] = dct[key].encode('latin_1').decode('utf-8')
        pass
    return dct


data = '{"msg": "Ahoj sv\u00c4\u009bte"}'

# String
json.loads(data)  
# Out: {'msg': 'Ahoj svÄ\x9bte'}
json.loads(data, object_hook=parse_obj)  
# Out: {'msg': 'Ahoj sv?te'}

# File
with open('/path/to/file.json') as f:
     json.load(f, object_hook=parse_obj)
     # Out: {'msg': 'Ahoj sv?te'}
     pass
Run Code Online (Sandbox Code Playgroud)

更新:

用字符串解析列表的解决方案不起作用。所以这里是更新的解决方案:

import json


def parse_obj(obj):
    for key in obj:
        if isinstance(obj[key], str):
            obj[key] = obj[key].encode('latin_1').decode('utf-8')
        elif isinstance(obj[key], list):
            obj[key] = list(map(lambda x: x if type(x) != str else x.encode('latin_1').decode('utf-8'), obj[key]))
        pass
    return obj
Run Code Online (Sandbox Code Playgroud)