【问题】
想要给BlogsToWordpress添加支持新版百度空间,然后通过:
去获得对应的帖子:
http://hi.baidu.com/hispace/item/c260a3d575252069fb5768ed
中的评论数据respCmtJson:
{"errorNo" : "0","errorMsg" : "success","data": [ {total_count : ‘129’,real_ret_count : ”,items : [{reply_id_enc : ‘3dc74bcd041d630ac710b2d6’,thread_id_enc : ‘8625437697c2ac29d6a89c75′,parent_id_enc : ’98ce38cba94a9a0cac092fe2’,reply_count : ‘0’,score : ‘0’,like_count : ‘0’,dislike_count : ‘0’,favor : ‘0’,is_top : ‘0’,cdatetime : ‘1342690951’,portrait : ’57bd31303330353530343434000b’,un : ‘1030550444’,area : ”,title : ”,reserved1 : ‘0’,content : ‘0’,replyee_portrait : ”,replyee_qurl : ”,replyee_name : ”,avatar : ‘http://hiphotos.baidu.com/space/scrop=40;q=100/sign=1f6d28a2b6003af349e49b3f4517f26c/7af40ad162d9f2d37e92ec44a9ec8a136227cc9e.jpg’,qurl : ‘\/go\/check?portrait=57bd66616b65000b’},{reply_id_enc : ‘fed96a6fca35820aa1cf0fd4’,thread_id_enc : ‘8625437697c2ac29d6a89c75′,parent_id_enc : ’98ce38cba94a9a0cac092fe2’,reply_count : ‘0’,score : ‘0’,like_count : ‘0’,dislike_count : ‘0’,favor : ‘0’,is_top : ‘0’,cdatetime : ‘1342690163’,portrait : ‘9d746c616c61383134400a’,un : ‘lala814’,area : ”,title : ”,reserved1 : ‘0’,content : ‘1234’,replyee_portrait : ”,replyee_qurl : ”,replyee_name : ”,avatar : ‘http://hiphotos.baidu.com/space/scrop=40;q=100/sign=a281b92f8c5494ee837c48465dc8d4ce/b7003af33a87e9506475cbfc10385343fbf2b43b.jpg’,qurl : ‘\/go\/check?portrait=9d7466616b65400a’},{reply_id_enc : ‘1ed3b252dde2fbaaacc857a8’,thread_id_enc : ‘8625437697c2ac29d6a89c75′,parent_id_enc : ’98ce38cba94a9a0cac092fe2’,reply_count : ‘0’,score : ‘0’,like_count : ‘0’,dislike_count : ‘0’,favor : ‘0’,is_top : ‘0’,cdatetime : ‘1342687361’,portrait : ‘369971716271627162717162cf17’,un : ‘追星赶花’,area : ”,title : ”,reserved1 : ‘0’,content : ‘直接给种子你懂得’,replyee_portrait : ”,replyee_qurl : ”,replyee_name : ”,avatar : ‘http://hiphotos.baidu.com/space/scrop=40;q=100/sign=26c32d9a0cd79123e4bed32bdd096db2/503d269759ee3d6db9b8fa5943166d224f4ade22.jpg’,qurl : ‘\/go\/check?portrait=369966616b65cf17’},{reply_id_enc : ‘9d3cdc855a7b0eddd0f8cd44’,thread_id_enc : ‘8625437697c2ac29d6a89c75′,parent_id_enc : ’98ce38cba94a9a0cac092fe2’,reply_count : ‘0’,score : ‘0’,like_count : ‘0’,dislike_count : ‘0’,favor : ‘0’,is_top : ‘0’,cdatetime : ‘1342687078’,portrait : ‘11316565646c6573734418’,un : ‘eedless’,area : ”,title : ”,reserved1 : ‘0’,content : ‘还有什么好看的电影么`’,replyee_portrait : ”,replyee_qurl : ”,replyee_name : ”,avatar : ‘http://hiphotos.baidu.com/space/scrop=40;q=100/sign=39e0d6482f2eb938e8333dada55fb105/8644ebf81a4c510fb4fe37b36059252dd42aa565.jpg’,qurl : ‘\/go\/check?portrait=113166616b654418’}]} ]} |
然后用json去解析:
cmtDict = json.loads(respCmtJson);
结果出错:
ValueError: Expecting property name: line 1 column 51 (char 51)
其中,此处不存在编码的问题,因为respCmtJson是UTF-8的。
【解决过程】
1.之前就遇到过类似json字符串解析成dict变量的问题。
后来是分别用eval,或ast.literal_eval,或json.loads而解决。
此处所以就又去试试eval和ast.literal_eval,结果都不行,都会出现解析错误:
(1)用
cmtDict = ast.literal_eval(respCmtJson);
出现:
ValueError: malformed string
(2)用
cmtDict = eval(respCmtJson);
出现:
NameError: name ‘total_count’ is not defined
所以都还是不行。
2.参考Python dict to JSON via json.loads:去试了试json.dumps,结果很明显,只是从utf-8的str转换为unicode的字符而已,然后用转换后的unicode字符再去json.loads,也还是同样出错。
3.由Issue5067想到,去把上述中单引号,换成双引号:
respCmtJson = respCmtJson.replace("'", "\"");
结果,让人失望,问题依旧。
4.专门去查了下那个错误位置51,发现是
"data": [ { ……} ]
中的第一个中括号之后,大括号之前,所以,看起来感觉是,json对于此处两个中括号之间,即列表变量中的值,不支持是dict类型的变量?
5.看到:Handling lazy JSON in Python – ‘Expecting property name’,才发现,原来上述猜测是错的。
问题根源在于,此处,对于json中的key和value来说,正常的话,是需要都用引号括起来的,而此处"data"之后的,第一个key是total_count,就没有用引号括起来,所以json才报错,不支持的。
类似地,后面的很多个key,比如real_ret_count,items,reply_id_enc等,全部都是没有引号括起来的,所以都会出错的。
然后就参考帖子的做法,去手动用正则表达式,把字符串处理为标准的json字符,就可以正确解析了。
如下是可以工作的代码:
respCmtJson = re.sub(r"(,?)(\w+?)\s+?:", r"\1'\2' :", respCmtJson); respCmtJson = respCmtJson.replace("'", "\""); logging.debug("after filter, respCmtJson=%s", respCmtJson); cmtDict = json.loads(respCmtJson); logging.debug("cmtDict=%s", cmtDict);
【总结】
解析json字符串位dict变量之前,的确要先确保json字符串是否符合标准。
此处就是由于json的key没有双引号,导致json解析错误的。
解决办法是,用正则表达式将非法的json字符串处理为合法的,符合json标准的字符串,然后在用json.loads,就可以正确解析了。
转载请注明:在路上 » 【已解决】Python中用json.loads去解析字符串出错:ValueError: Expecting property name: line 1 column 51 (char 51)
respCmtJson = re.sub(r”(,?)(\w+?)\s+?:”, r”\1′\2′ :”, respCmtJson);
把所有的,没有被引号括起来的key,加上单引号 即把: total_count : '129' ,real_ret_count : '' 等 变成 'total_count' : '129' ,'real_ret_count' : ''respCmtJson = respCmtJson.replace(“‘”, “\”");
把所有的单引号,变成双引号 =》 上面两行,所要解决的问题是: 消除了,json中错误的写法: (1)key没有被(双引号)括起来 (2)所用引号不是单引号 对应的背景是: (1)json中key,必须被双引号括起来 (2)json中要求必须都是双引号logging.debug(“after filter, respCmtJson=%s”, respCmtJson); cmtDict = json.loads(respCmtJson);
此时,处理后的json字符串,已经是合法的了 所以直接调用json.loads去转换为对应的(字典,列表等类型的)变量,即可。logging.debug(“cmtDict=%s”, cmtDict);
另外: 感兴趣的,可以去看我写的教程: JSON详解