如何将原始 javascript 对象转换为字典?
- 2025-02-28 08:22:00
- admin 原创
- 65
问题描述:
当我对某个网站进行屏幕抓取时,我从<script>
标签中提取数据。
我得到的数据不是标准JSON
格式。我无法使用json.loads()
。
# from
js_obj = '{x:1, y:2, z:3}'
# to
py_obj = {'x':1, 'y':2, 'z':3}
目前我习惯regex
将原始数据转换为JSON
格式,
但遇到复杂的数据结构时就感觉很麻烦。
您有更好的解决方案吗?
解决方案 1:
demjson.decode()
import demjson
# from
js_obj = '{x:1, y:2, z:3}'
# to
py_obj = demjson.decode(js_obj)
chompjs.parse_js_object()
import chompjs
# from
js_obj = '{x:1, y:2, z:3}'
# to
py_obj = chompjs.parse_js_object(js_obj)
jsonnet.evaluate_snippet()
import json, _jsonnet
# from
js_obj = '{x:1, y:2, z:3}'
# to
py_obj = json.loads(_jsonnet.evaluate_snippet('snippet', js_obj))
ast.literal_eval()
import ast
# from
js_obj = "{'x':1, 'y':2, 'z':3}"
# to
py_obj = ast.literal_eval(js_obj)
解决方案 2:
使用json5
import json5
js_obj = '{x:1, y:2, z:3}'
py_obj = json5.loads(js_obj)
print(py_obj)
# output
# {'x': 1, 'y': 2, 'z': 3}
解决方案 3:
今天下午我也遇到了同样的问题,最后找到了一个相当不错的解决方案。那就是JSON5。
JSON5的语法与原生JavaScript更加相似,因此它可以帮助您解析非标准的JSON对象。
您可能想要检查一下pyjson5。
解决方案 4:
node
如果系统上有可用资源,您可以要求它为您评估 javascript 表达式,并打印字符串化结果。然后可以将生成的 JSON 输入到json.loads
:
def evaluate_javascript(s):
"""Evaluate and stringify a javascript expression in node.js, and convert the
resulting JSON to a Python object"""
node = Popen(['node', '-'], stdin=PIPE, stdout=PIPE)
stdout, _ = node.communicate(f'console.log(JSON.stringify({s}))'.encode('utf8'))
return json.loads(stdout.decode('utf8'))
解决方案 5:
这可能不会在任何地方都有效,但作为开始,这里有一个简单的正则表达式,它应该将键转换为带引号的字符串,以便您可以传递到 json.loads。或者这就是您已经在做的事情?
In[70] : quote_keys_regex = r'([{s,])(w+)(:)'
In[71] : re.sub(quote_keys_regex, r'""', js_obj)
Out[71]: '{"x":1, "y":2, "z":3}'
In[72] : js_obj_2 = '{x:1, y:2, z:{k:3,j:2}}'
Int[73]: re.sub(quote_keys_regex, r'""', js_obj_2)
Out[73]: '{"x":1, "y":2, "z":{"k":3,"j":2}}'
解决方案 6:
不包括物体
json.loads()
json.loads()
不接受未定义,你必须更改为nulljson.loads()
仅接受双引号
+ `{"foo": 1, "bar": null}`
如果您确定您的 javascript 代码仅在键名上有双引号,请使用此功能。
import json
json_text = """{"foo": 1, "bar": undefined}"""
json_text = re.sub(r'("s*:s*)undefined(s*[,}])', '\\1null\\2', json_text)
py_obj = json.loads(json_text)
ast.literal_eval()
ast.literal_eval()
不接受未定义,你必须更改为Noneast.literal_eval()
不接受null,您必须更改为Noneast.literal_eval()
不接受true,你必须更改为Trueast.literal_eval()
不接受false,你必须更改为Falseast.literal_eval()
接受单引号和双引号
+ `{"foo": 1, "bar": None}`或者`{'foo': 1, 'bar': None}`
import ast
js_obj = """{'foo': 1, 'bar': undefined}"""
js_obj = re.sub(r'([\'\"]s*:s*)undefined(s*[,}])', '\\1None\\2', js_obj)
js_obj = re.sub(r'([\'\"]s*:s*)null(s*[,}])', '\\1None\\2', js_obj)
js_obj = re.sub(r'([\'\"]s*:s*)NaN(s*[,}])', '\\1None\\2', js_obj)
js_obj = re.sub(r'([\'\"]s*:s*)true(s*[,}])', '\\1True\\2', js_obj)
js_obj = re.sub(r'([\'\"]s*:s*)false(s*[,}])', '\\1False\\2', js_obj)
py_obj = ast.literal_eval(js_obj)
解决方案 7:
这里的一些答案已经过时了,所以这里是 json5、hjson 和 chompjs 之间的速度比较。(ast.literal_eval 和 json.loads 失败)。在 1 MB js 对象上评估函数以获得良好的样本。所有 3 次成功都产生了相同的字典。
# 100.00% - reference time
chompjs.parse_js_object(text)
# 666.65% - 7 times slower
hjson.loads(text)
# 60460.57% - 605 times slower
json5.loads(text)
# fail
ast.literal_eval(text)
json.loads(text)
# won't install on Python 3.11.9
demjson
jsonnet
扫码咨询,免费领取项目管理大礼包!