BeautifulSoup Webscraper中的UnicodeEncodeError

时间:2019-02-03 01:44:46

标签: python unicode beautifulsoup encode

我遇到一个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转储的最后一段代码中。非常感谢。

2 个答案:

答案 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