首页 > 解决方案 > Python 3 写入 json 文件时出现双反斜杠问题

问题描述

我使用urllib.requestand regexforhtml parse但是当我在json文件中写入时,文本中有双反斜杠。如何替换一个反斜杠?我查看了许多解决方案,但没有一个有效。

headers = {}
headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'
req = Request('https://www.manga-tr.com/manga-list.html', headers=headers)
response = urlopen(req).read()
a = re.findall(r'<b><a[^>]* href="([^"]*)"',str(response))
sub_req = Request('https://www.manga-tr.com/'+a[3], headers=headers)
sub_response = urlopen(sub_req).read()
manga = {}
manga['manga'] = []
manga_subject = re.findall(r'<h3>Tan.xc4.xb1t.xc4.xb1m<.h3>[^<]*.n.t([^<]*).t',str(sub_response))
manga['manga'].append({'msubject': manga_subject })
with io.open('allmanga.json', 'w', encoding='utf-8-sig') as outfile:
outfile.write(json.dumps(manga, indent=4))

这是我的 json 文件

{
    "manga": [
        {
            "msubject": [
                "  Minami Ria 16 ya\\xc5\\x9f\\xc4\\xb1ndad\\xc4\\xb1r. \\xc4\\xb0lk erkek arkada\\xc5\\x9f\\xc4\\xb1 sakatani jirou(16) ile yakla\\xc5\\x9f\\xc4\\xb1k 6 ayd\\xc4\\xb1r beraberdir. Herkes taraf\\xc4\\xb1ndan \\xc3\\xa7ifte kumru olarak g\\xc3\\xb6r\\xc3\\xbclmelerine ra\\xc4\\x9fmen ili\\xc5\\x9fkilerinde %1\\'lik bir eksiklik vard\\xc4\\xb1r. Bu eksikli\\xc4\\x9fi tamamlayabilecekler mi?"
        }
    ]
}

标签: pythonjsonregexrequest

解决方案


为什么会这样?

错误是 whenstr用于将bytes对象转换为str. 这不会以所需的方式进行转换。

a = re.findall(r'<b><a[^>]* href="([^"]*)"',str(response))
#                                           ^^^

例如,如果响应是单词“Tanıtım”,那么它会在 UTF-8 中表示为b'Tan\xc4\xb1t\xc4\xb1m'. 如果你然后使用str它,你会得到:

In [1]: response = b'Tan\xc4\xb1t\xc4\xb1m'

In [2]: str(response)
Out[2]: "b'Tan\\xc4\\xb1t\\xc4\\xb1m'"

如果将其转换为 JSON,您将看到双反斜杠(实际上只是普通的反斜杠,编码为 JSON)。

In [3]: import json

In [4]: print(json.dumps(str(response)))
"b'Tan\\xc4\\xb1t\\xc4\\xb1m'"

bytes将对象转换回 a的正确方法str是使用decode具有适当编码的方法:

In [5]: response.decode('UTF-8')
Out[5]: 'Tanıtım'

请注意,不幸的是,响应不是有效的 UTF-8。网站运营商似乎在提供损坏的数据。

快速解决

替换每次调用str(response)withresponse.decode('UTF-8', 'replace')并更新正则表达式以匹配。

a = re.findall(
    # "r" prefix to string is unnecessary
    '<b><a[^>]* href="([^"]*)"',
    response.decode('UTF-8', 'replace'))
sub_req = Request('https://www.manga-tr.com/'+a[3], 
                  headers=headers)
sub_response = urlopen(sub_req).read()
manga = {}
manga['manga'] = []
manga_subject = re.findall(
    # "r" prefix to string is unnecessary
    '<h3>Tanıtım</h3>([^<]*)',
    sub_response.decode('UTF-8', 'replace'))
manga['manga'].append({'msubject': manga_subject })
# io.open is the same as open
with open('allmanga.json', 'w', encoding='utf-8-sig') as fp:
    # json.dumps is unnecessary
    json.dump(manga, fp, indent=4)

更好的修复

使用“请求”

Requests库比使用urlopen. 您必须安装它(使用 pip、apt、dnf 等,无论您使用什么),它不随 Python 提供。它看起来像这样:

response = requests.get(
    'https://www.manga-tr.com/manga-list.html')

然后response.text包含解码后的字符串,不需要自己解码。更轻松!

使用 BeautifulSoup

Beautiful Soup库可以搜索 HTML 文档,比正则表达式更可靠,更易于使用。它也需要安装。例如,您可以像这样使用它来查找漫画页面中的所有摘要:

soup = BeautifulSoup(response.text, 'html.parser')
subject = soup.find('h3', text='Tanıtım').next_sibling.string

概括

这是一个Gist,其中包含一个更完整的刮板外观示例。

请记住,抓取网站可能有点困难,因为您可能会抓取 100 个页面,然后突然发现您的抓取器有问题,或者您访问网站的力度太大,或者某些内容崩溃并失败,您需要重来。因此,良好的抓取通常涉及速率限制、保存进度和缓存响应,以及(理想情况下)解析 robots.txt。

Requests + BeautifulSoup至少能让你入门。再次,请参阅要点


推荐阅读