最近在我的Python爬虫中总是会遇到json.loads()方法报错,把抓取到的原文摘出来一看,里面带有转义的 " 和 ',也就是 \"和\'。
一开始遇到这个问题就疯狂上网搜索,结果找不到能解决我问题的答案,所以就想着按照Json解析的算法做一个自己的Json解析算法。不过,这似乎十分麻烦,懒惰的我于是就做了个替换算法。针对 " 做定位,并且将 Json内的 " 替换成 \", 这样后面进行Json解析的时候就不会报错了.
4月12日更新:
遇到了一个比较特殊的Json,里面有换行符和制表符('\n'和'\t'),在python中用自带的json.loads()总是会报错,我自己写的方法也不好搞。不过因为业务特殊,这个Json不一定要在爬虫的时候就解析,而且在Java中用FastJson解析完全没有问题.(阿里爸爸牛逼),所以就干脆在python程序结束的时候调用一下Java程序就好啦.
什么,怎么调用?怎么运行jar包就怎么调呗,毕竟懒得引入python调用Java的框架了.TNT
import os
os.system("java -jar test.jar")
# 如果遇到java程序乱码,就再加上运行时的编码设置就好啦
# os.system("java -Dfile.encoding=utf-8 -jar test.jar")
封装json.loads方法,进行try及在except中加入对应的处理逻辑:
def json_loads(string):
"""
尝试将string转为json对象,如果转为json对象失败,则抛出异常,并且将错误的JSON记录在json.log中
:param string:
:return:
"""
try:
temp_json = json.loads(string)
except json.JSONDecodeError:
temp_json = None
if temp_json is None:
try:
# REPLACE_POINT是我自己定义的常量,用于标识\', 可以参照URLDecoder,我设置的是%10AA
string = str(string).replace("\\'", REPLACE_POINT)
temp_json = json.loads(string)
except json.JSONDecodeError:
# 锚点Json中经常会出现\t
string = string.replace("\t", "")
try:
temp_json = json.loads(string)
except json.JSONDecodeError:
# 万般无奈的情况下再用这个方法,该替换算法存在风险
string = solve_wrong(string)
try:
temp_json = json.loads(string)
except json.JSONDecodeError as json_exception:
print(string)
return temp_json
def solve_wrong(string, right=0):
"""
在解析Json失败时, 调用此方法将错误的字符串用转义,也就是将 '"' 替换成 '\"'
:param string: 解析错误的Json字符串
:param right: 字符串解析的初始偏移位置,网页上的Json数据长度基本都会大过10的吧...
:return: 转义之后的字符串
"""
if len(string) < 10:
# 长度比10还小的Json?逗我呢
print("Get out,this is bullshit.")
result = None
while right < len(string):
c = string[right]
if c == '"':
# 记录当前双引号位置
left = right
flag = False
# 从当前位置向后查询
right = left + 1
while (right + 2) < len(string):
if string[right] == '"':
# 找到与之配对的",判断是否是Json的正确结尾
nextc = string[right + 1]
if nextc == ']' or nextc == ',' or nextc == ':' or nextc == '[' or nextc == '}':
if nextc == ',':
# 可能是下一個Json對象、数组或数据的开始
next_nextc = string[right + 2]
if next_nextc != '{' and next_nextc != '"' and next_nextc != '[':
# 如果不是数据的开始部分,说明"就在本次字符串中
flag = True
right += 1
continue
# 说明是正确的结尾
if flag:
# 截取引号对中间的部分
temp = string[left + 1: right]
if result is None:
# 用result来存储string替换后的结果,如果直接更改string的话
# 会导致一连串的变化
result = string.replace(temp, temp.replace('"', '\\"'))
else:
result = result.replace(temp, temp.replace('"', '\\"'))
break
else:
# 找到导致Json解析错误的字符串了,现在只要移动到结尾再截取字符串就可以了
flag = True
right += 1
right += 1
return result
主要是依赖双指针,确定出来每一个 双引号(")对,当右指针发现"时候,判断它是不是正确的结尾,如果不是,就把flag设置为True,等到右指针指到真正的结尾时,截取引号对中间的部分,进行替换。
我就是靠硬生生盯着目标Json的形式,总结出来的结尾,顺便说一句,我用开发者模式看到的Json是有转义符号的,不过等我用程序抓来之后,python似乎就给当作转义字符识别了,很难受。。。