Имам проблеми с работа с Unicode символи от текст, извлечен от различни уеб страници (на различни сайтове). Използвам BeautifulSoup.
Проблемът е, че грешката невинаги може да се възпроизведе; понякога работи с някои страници, а понякога се проваля, като изхвърля UnicodeEncodeError
. Опитах почти всичко, за което се сетих, но все още не съм намерил нищо, което да работи постоянно, без да хвърля някаква грешка, свързана с Unicode.
Една от частите на кода, която създава проблеми, е показана по-долу:
agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
Тук е представена стековата следа, която се получава за НЯКОИ низове, когато се изпълнява горният фрагмент:
Traceback (most recent call last):
File "foobar.py", line 792, in <module>
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 20: ordinal not in range(128)
Подозирам, че това се дължи на факта, че някои страници (или по-точно страници от някои от сайтовете) могат да бъдат кодирани, докато други могат да бъдат некодирани. Всички сайтове са базирани в Обединеното кралство и предоставят данни, предназначени за потребление в Обединеното кралство - така че няма проблеми, свързани с интернализацията или работата с текст, написан на нещо различно от английски език.
Има ли някой идея как да реша този проблем, за да мога да го решавам ПОСТОЯННО?
Трябва да прочетете Python Unicode HOWTO. Тази грешка е първият пример.
В общи линии, спрете да използвате str
за преобразуване от Unicode в кодиран текст/байтове.
Вместо това използвайте правилно .encode()
, за да кодирате низ:
p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()
или да работите изцяло в уникод.
Това е класическа болна точка на питон за Unicode! Разгледайте следното:
a = u'bats\u00E0'
print a
=> batsà
Дотук всичко е наред, но ако извикаме str(a), нека видим какво ще стане:
str(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
О, дип, това няма да донесе нищо добро на никого! За да поправите грешката, кодирайте байтовете изрично с .encode и кажете на python какъв кодек да използва:
a.encode('utf-8')
=> 'bats\xc3\xa0'
print a.encode('utf-8')
=> batsà
Voil\u00E0!
Проблемът се състои в това, че когато извикате str(), python използва кодирането на символите по подразбиране, за да се опита да кодира байтовете, които сте му предоставили, които във вашия случай понякога представляват символи от Unicode. За да решите проблема, трябва да кажете на python как да се справи с низа, който сте му дали, като използвате .encode('whatever_unicode'). През повечето време би трябвало да се справите с използването на utf-8.
За отлично изложение на тази тема вижте лекцията на Ned Batchelder'на PyCon тук: http://nedbatchelder.com/text/unipain.html
Всъщност установих, че в повечето случаи е много по-просто просто да премахна тези символи:
s = mystring.decode('ascii', 'ignore')