Hiển thị thông báo lỗi tốt hơn so với không có đối tượng JSON Không thể giải mã được


128

Mã Python để tải dữ liệu từ một số tệp JSON phức tạp dài:

with open(filename, "r") as f:
  data = json.loads(f.read())

(lưu ý: phiên bản mã tốt nhất phải là:

with open(filename, "r") as f:
  data = json.load(f)

nhưng cả hai biểu hiện hành vi tương tự)

Đối với nhiều loại lỗi JSON (thiếu dấu phân cách, dấu gạch chéo ngược không chính xác trong chuỗi, v.v.), điều này sẽ in một thông báo hữu ích tốt đẹp chứa dòng và số cột nơi tìm thấy lỗi JSON.

Tuy nhiên, đối với các loại lỗi JSON khác (bao gồm cả "sử dụng dấu phẩy trên mục cuối cùng trong danh sách" cổ điển, nhưng cũng có những thứ khác như viết hoa đúng / sai), đầu ra của Python chỉ là:

Traceback (most recent call last):
  File "myfile.py", line 8, in myfunction
    config = json.loads(f.read())
  File "c:\python27\lib\json\__init__.py", line 326, in loads
    return _default_decoder.decode(s)
  File "c:\python27\lib\json\decoder.py", line 360, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "c:\python27\lib\json\decoder.py", line 378, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

Đối với loại ValueError đó, làm thế nào để bạn nhận được Python để cho bạn biết lỗi trong tệp JSON ở đâu?


Bạn có thể đổ một đoạn trích của tập tin của bạn?
Ketouem

Tôi hiện không cố gắng tìm lỗi trong một tệp cụ thể; Tôi đang cố gắng sửa đổi chương trình của mình để nó sẽ làm nổi bật lỗi trong bất kỳ tệp nào trong tương lai mà nó đọc.
OJW

2
Không liên quan trực tiếp, nhưng bạn chỉ có thể làm json.load(f)thay vìjson.loads(f.read())
Martin Samson

@OJW hành vi này của python là gì?
jxramos

Python 3.8.1 hiện cung cấp vị trí lỗi "Giá trị mong đợi: dòng 1 cột 21 (char 20)"
OJW

Câu trả lời:


173

Tôi đã thấy rằng simplejsonmô-đun cung cấp nhiều lỗi mô tả hơn trong nhiều trường hợp jsonmô-đun tích hợp là mơ hồ. Chẳng hạn, đối với trường hợp có dấu phẩy sau mục cuối cùng trong danh sách:

json.loads('[1,2,]')
....
ValueError: No JSON object could be decoded

mà không phải là rất mô tả. Hoạt động tương tự với simplejson:

simplejson.loads('[1,2,]')
...
simplejson.decoder.JSONDecodeError: Expecting object: line 1 column 5 (char 5)

Tốt hơn nhiều! Tương tự như vậy đối với các lỗi phổ biến khác như viết hoa True.


18
Các phiên bản tương lai của Python sẽ bao gồm những cải tiến đó; đó là cùng một dự án bên dưới.
Martijn Pieters


1
@ user2016290 Chỉnh sửa trực tiếp các tập tin lõi / gói là một ý tưởng tồi. Python rất dễ để vá khỉ, vì vậy tốt hơn là làm điều đó trong mã.
Hoàn trả

2
@jxramos: OP đã sử dụng Python 2.7, hiển nhiên từ truy nguyên. Thử nghiệm nhanh trên ideone.com (Python 3.7.3) cho thấy jsonthư viện stdlib đã được cập nhật và đưa ra định dạng thông báo lỗi mới. Tôi không có thời gian để theo dõi các bản phát hành chính xác ngay bây giờ.
Martijn Pieters

1
@jxramos tìm thấy nó, Python 3.5 cập nhật các trường hợp ngoại lệ: bugs.python.org/issue19361 (thông qua docs.python.org/3/whatsnew/3.5.html#improved-modules ).
Martijn Pieters

15

Bạn sẽ không thể lấy python để cho bạn biết JSON không chính xác ở đâu. Bạn sẽ cần phải sử dụng một kẻ nói dối trực tuyến ở đâu đó như thế này

Điều này sẽ cho bạn thấy lỗi trong JSON mà bạn đang cố giải mã.


2
Có công cụ ngoại tuyến nào có thể làm điều này cho các tệp JSON bí mật không?
OJW

@OJW không phải tôi biết nhưng điều đó sẽ giải quyết vấn đề bạn đang gặp phải hoặc ít nhất là để bạn sửa chữa cái json bị hỏng của bạn.
myusuf3

12
Tệp JSON của tôi vẫn ổn - Tôi đang cố gắng để chương trình của mình in các thông báo lỗi hữu ích cho mọi người. Nói với họ "thoát khỏi dấu phẩy ở dòng 13 cột 32" là tốt. Nói với họ "có lỗi ở đâu đó trong tệp của bạn, vui lòng tải nó lên internet nơi mọi người sẽ giúp bạn" thật tệ.
OJW

7

Bạn có thể thử thư viện rson được tìm thấy ở đây: http://code.google.com.vn/p/rson/ . Tôi cũng lên PYPI: https://pypi.python.org/pypi/rson/0.9 để bạn có thể sử dụng easy_install hoặc pip để lấy nó.

cho ví dụ được đưa ra bởi tom:

>>> rson.loads('[1,2,]')
...
rson.base.tokenizer.RSONDecodeError: Unexpected trailing comma: line 1, column 6, text ']'

RSON được thiết kế để trở thành siêu bộ của JSON, vì vậy nó có thể phân tích các tệp JSON. Nó cũng có một cú pháp thay thế đó là nhiều đẹp hơn cho con người nhìn vào và chỉnh sửa. Tôi sử dụng nó một chút cho các tập tin đầu vào.

Đối với việc viết hoa các giá trị boolean: có vẻ như rson đọc các booleans viết hoa không chính xác dưới dạng chuỗi.

>>> rson.loads('[true,False]')
[True, u'False']

4

Tôi đã có một vấn đề tương tự và đó là do đơn. Tiêu chuẩn JSON ( http://json.org ) chỉ nói về việc sử dụng dấu ngoặc kép để jsonthư viện python chỉ hỗ trợ dấu ngoặc kép.


3

Đối với phiên bản cụ thể của tôi về vấn đề này, tôi đã tiếp tục và tìm kiếm khai báo hàm load_json_file(path)trong packaging.pytệp, sau đó nhập một printdòng vào đó:

def load_json_file(path):
    data = open(path, 'r').read()
    print data
    try:
        return Bunch(json.loads(data))
    except ValueError, e:
        raise MalformedJsonFileError('%s when reading "%s"' % (str(e),
                                                               path))

Bằng cách đó, nó sẽ in nội dung của tệp json trước khi vào thử bắt và theo cách đó - ngay cả với kiến ​​thức Python chưa có của tôi - tôi đã có thể nhanh chóng tìm ra lý do tại sao cấu hình của tôi không thể đọc tệp json.
(Đó là vì tôi đã thiết lập trình soạn thảo văn bản của mình để viết một UTF-8 BOM Sự ngu ngốc)

Chỉ đề cập đến điều này bởi vì, trong khi có thể không phải là một câu trả lời tốt cho vấn đề cụ thể của OP, đây là một phương pháp khá nhanh chóng trong việc xác định nguồn gốc của một lỗi rất ngột ngạt. Và tôi cá rằng nhiều người sẽ vấp phải bài báo này, những người đang tìm kiếm một giải pháp dài dòng hơn cho a MalformedJsonFileError: No JSON object could be decoded when reading …. Vì vậy, điều đó có thể giúp họ.


Bạn nên sử dụng trình quản lý bối cảnh cho tệp I / O ( with open(fn) as f), nó xử lý việc đóng tệp trong một ngoại lệ đối với bạn. vi.wikibooks.org/wiki/Python_Programming/ từ
Rebs

1
+1. Nếu bạn có thể đưa ra một ví dụ về việc bắt chước hành vi tiêu chuẩn đó, thì nó sẽ khá gọn gàng
Craig Brett

Xin lỗi, tôi chưa bao giờ chạm vào bất kỳ mã Python nào sau khi vấn đề đó được tìm ra. Có lẽ ai đó có thể giúp đỡ?
WoodrowShigeru

3

Đối với tôi, tập tin json của tôi rất lớn, khi sử dụng phổ biến jsontrong python nó sẽ gặp lỗi trên.

Sau khi cài đặt simplejsonbằng sudo pip install simplejson.

Và sau đó tôi đã giải quyết nó.

import json
import simplejson


def test_parse_json():
    f_path = '/home/hello/_data.json'
    with open(f_path) as f:
        # j_data = json.load(f)      # ValueError: No JSON object could be decoded
        j_data = simplejson.load(f)  # right
    lst_img = j_data['images']['image']
    print lst_img[0]


if __name__ == '__main__':
    test_parse_json()

1

Tôi đã có một vấn đề tương tự đây là mã của tôi:

    json_file=json.dumps(pyJson)
    file = open("list.json",'w')
    file.write(json_file)  

    json_file = open("list.json","r")
    json_decoded = json.load(json_file)
    print json_decoded

vấn đề là tôi đã quên file.close() tôi đã làm nó và khắc phục vấn đề.


Làm việc cho tôi cũng vậy, không biết tại sao trước đây không có vấn đề này.
pceccon

Bạn nên sử dụng trình quản lý bối cảnh cho tệp I / O ( with open(fn) as f), nó xử lý việc đóng tệp trong một ngoại lệ đối với bạn. vi.wikibooks.org/wiki/Python_Programming/ từ
Rebs

0

Câu trả lời được chấp nhận là cách dễ nhất để khắc phục vấn đề. Nhưng trong trường hợp bạn không được phép cài đặt Simplejson do chính sách của công ty, tôi đề xuất giải pháp bên dưới để khắc phục vấn đề cụ thể là "sử dụng dấu phẩy trên mục cuối cùng trong danh sách" :

  1. Tạo một lớp con "JSONLintCheck" để kế thừa từ lớp "JSONDecoder" và ghi đè phương thức init của lớp "JSONDecoder" như bên dưới:

    def __init__(self, encoding=None, object_hook=None, parse_float=None,parse_int=None, parse_constant=None, strict=True,object_pairs_hook=None)        
            super(JSONLintCheck,self).__init__(encoding=None, object_hook=None,      parse_float=None,parse_int=None, parse_constant=None, strict=True,object_pairs_hook=None)
            self.scan_once = make_scanner(self)
  1. make_scanner là một hàm mới được sử dụng để ghi đè phương thức 'scan_once' của lớp trên. Và đây là mã cho nó
  1 #!/usr/bin/env python
  2 from json import JSONDecoder
  3 from json import decoder
  4 import re
  5
  6 NUMBER_RE = re.compile(
  7     r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
  8     (re.VERBOSE | re.MULTILINE | re.DOTALL))
  9
 10 def py_make_scanner(context):
 11     parse_object = context.parse_object
 12     parse_array = context.parse_array
 13     parse_string = context.parse_string
 14     match_number = NUMBER_RE.match
 15     encoding = context.encoding
 16     strict = context.strict
 17     parse_float = context.parse_float
 18     parse_int = context.parse_int
 19     parse_constant = context.parse_constant
 20     object_hook = context.object_hook
 21     object_pairs_hook = context.object_pairs_hook
 22
 23     def _scan_once(string, idx):
 24         try:
 25             nextchar = string[idx]
 26         except IndexError:
 27             raise ValueError(decoder.errmsg("Could not get the next character",string,idx))
 28             #raise StopIteration
 29
 30         if nextchar == '"':
 31             return parse_string(string, idx + 1, encoding, strict)
 32         elif nextchar == '{':
 33             return parse_object((string, idx + 1), encoding, strict,
 34                 _scan_once, object_hook, object_pairs_hook)
 35         elif nextchar == '[':
 36             return parse_array((string, idx + 1), _scan_once)
 37         elif nextchar == 'n' and string[idx:idx + 4] == 'null':
 38             return None, idx + 4
 39         elif nextchar == 't' and string[idx:idx + 4] == 'true':
 40             return True, idx + 4
 41         elif nextchar == 'f' and string[idx:idx + 5] == 'false':
 42             return False, idx + 5
 43
 44         m = match_number(string, idx)
 45         if m is not None:
 46             integer, frac, exp = m.groups()
 47             if frac or exp:
 48                 res = parse_float(integer + (frac or '') + (exp or ''))
 49             else:
 50                 res = parse_int(integer)
 51             return res, m.end()
 52         elif nextchar == 'N' and string[idx:idx + 3] == 'NaN':
 53             return parse_constant('NaN'), idx + 3
 54         elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity':
 55             return parse_constant('Infinity'), idx + 8
 56         elif nextchar == '-' and string[idx:idx + 9] == '-Infinity':
 57             return parse_constant('-Infinity'), idx + 9
 58         else:
 59             #raise StopIteration   # Here is where needs modification
 60             raise ValueError(decoder.errmsg("Expecting propert name enclosed in double quotes",string,idx))
 61     return _scan_once
 62
 63 make_scanner = py_make_scanner
  1. Tốt hơn là đặt hàm 'make_scanner' cùng với lớp con mới vào cùng một tệp.

0

Chỉ cần nhấn vào cùng một vấn đề và trong trường hợp của tôi, vấn đề có liên quan đến BOM(dấu thứ tự byte) ở đầu tệp.

json.tool sẽ từ chối xử lý ngay cả tệp trống (chỉ là dấu ngoặc nhọn) cho đến khi tôi xóa dấu UTF BOM.

Những gì tôi đã làm là:

  • mở tập tin json của tôi với vim,
  • loại bỏ dấu thứ tự byte ( set nobomb)
  • lưu tập tin

Điều này đã giải quyết vấn đề với json.tool. Hi vọng điêu nay co ich!


-1

Khi tập tin của bạn được tạo ra. Thay vì tạo một tập tin với nội dung là trống rỗng. Thay thế bằng:

json.dump({}, file)

-3

Bạn có thể sử dụng cjson , tuyên bố nhanh hơn 250 lần so với triển khai python thuần, với điều kiện bạn có "một số tệp JSON phức tạp dài" và có thể bạn sẽ cần phải chạy nó nhiều lần (bộ giải mã thất bại và báo cáo lỗi đầu tiên chỉ gặp).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.