我遇到一个unicode编码错误,下面的代码是一个简单的网络抓取工具。
print 'JSON scraper initializing'
from bs4 import BeautifulSoup
import json
import requests
import geocoder
# Set page variable
page = 'https://www.bandsintown.com/?came_from=257&page='
urlBucket = []
for i in range (1,3):
uniqueUrl = page + str(i)
urlBucket.append(uniqueUrl)
# Build response container
responseBucket = []
for i in urlBucket:
uniqueResponse = requests.get(i)
responseBucket.append(uniqueResponse)
# Build soup container
soupBucket = []
for i in responseBucket:
individualSoup = BeautifulSoup(i.text, 'html.parser')
soupBucket.append(individualSoup)
# Build events container
allSanFranciscoEvents = []
for i in soupBucket:
script = i.find_all("script")[4]
eventsJSON = json.loads(script.text)
allSanFranciscoEvents.append(eventsJSON)
with open("allSanFranciscoEvents.json", "w") as writeJSON:
json.dump(allSanFranciscoEvents, writeJSON, ensure_ascii=False)
print ('end')
奇怪的是,有时,此代码有效,并且没有给出错误。它与代码的for i in range
行有关。例如,如果我将(2,4)
输入范围,则可以正常工作。如果我将其更改为1,3,
,则会显示:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 12: ordinal not in range(128)
谁能告诉我如何在我的代码中解决此问题?如果我打印allSanFranciscoEvents
,则表示它正在读取所有数据,因此,我认为问题出在JSON转储的最后一段代码中。非常感谢。
答案 0 :(得分:1)
最佳修复
使用Python 3! Python 2即将推出going EOL。如今,用旧版python编写的新代码的保质期非常短。
为了使您的代码在python 3中工作,我唯一需要更改的就是调用print()
函数而不是print
关键字。这样您的示例代码就可以正常工作了。
坚持使用Python 2
奇怪的是,有时,此代码有效,并且没有给出 错误。它与代码范围行中的for i有关。对于 例如,如果我在范围内输入(2,4),则效果很好。
这是因为您请求的页面具有不同的范围,并且并非每个页面都具有无法使用ascii编解码器转换为str
的字符。我必须转到响应的第5页,以获得与您相同的错误。就我而言,是艺术家姓名u'Mø'
引起了问题。因此,这里有一个重现该问题的1衬纸:
>>> str(u'Mø')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf8' in position 0: ordinal not in range(128)
您的错误明确指出了字符u'\xe9'
:
>>> str(u'\xe9')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128)
同一问题,只是字符不同。字符为Latin small letter e with acute。 Python尝试使用默认编码'ascii'将Unicode
字符串转换为str
,但是'ascii'不知道代码点是什么。
我相信问题会在最后的代码段中发生, JSON转储。
是的,是:
>>> with open('tmp.json', 'w') as f:
... json.dump(u'\xe9', f, ensure_ascii=False)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/usr/lib/python2.7/json/__init__.py", line 190, in dump
fp.write(chunk)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 1: ordinal not in range(128)
从回溯中,您可以看到它实际上是由于写入文件(fp.write(chunk)
)引起的。
file.write()
将string
写入文件,但是u'\xe9'
是unicode
对象。错误消息:'ascii' codec can't encode character...
告诉我们python正在尝试对该unicode
对象进行编码以将其转换为str
类型,以便可以将其写入文件。在unicode字符串上调用encoding使用"default string encoding",here被定义为'ascii'。
要解决此问题,请不要将其留给python使用默认编码:
>>> with open('tmp.json', 'w') as f:
... json.dump(u'\xe9'.encode('utf-8'), f, ensure_ascii=False)
...
# No error :)
在您的特定示例中,您可以通过更改以下内容来修复间歇性错误:
allSanFranciscoEvents.append(eventsJSON)
对此:
allSanFranciscoEvents.append(eventsJSON.encode('utf-8'))
那样,您将显式使用'utf-8'编解码器将Unicode
字符串转换为str
,以便python在以下情况下不会尝试应用默认编码'ascii'写入文件。
答案 1 :(得分:0)
eventsJSON
是不能使用eventsJSON.encode('utf-8')
的对象。对于Python 2.7以utf-8
或unicode写入文件,您可以使用codecs
或使用二进制或wb
标志写入文件。
with open("allSanFranciscoEvents.json", "wb") as writeJSON:
jsStr = json.dumps(allSanFranciscoEvents)
# the decode() needed because we need to convert it to binary
writeJSON.write(jsStr.decode('utf-8'))
print ('end')
# and read it normally
with open("allSanFranciscoEvents.json", "r") as readJson:
data = json.load(readJson)
print(data[0][0]["startDate"])
# 2019-02-04