Έχω προβλήματα με χαρακτήρες unicode από κείμενο που λαμβάνεται από διαφορετικές ιστοσελίδες (σε διαφορετικές τοποθεσίες). Χρησιμοποιώ το BeautifulSoup.
Το πρόβλημα είναι ότι το σφάλμα δεν είναι πάντα αναπαραγώγιμο: μερικές φορές λειτουργεί με ορισμένες σελίδες και μερικές φορές, barfs ρίχνοντας ένα 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 σε κωδικοποιημένο κείμενο / bytes.
Αντ' αυτού, χρησιμοποιήστε σωστά την .encode()
για την κωδικοποίηση της συμβολοσειράς:
p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()
ή δουλέψτε εξ ολοκλήρου σε unicode.
Αυτό είναι ένα κλασικό σημείο πόνου της python 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)
Ωχ βουτιά, αυτό'δεν θα κάνει καλό σε κανέναν! Για να διορθώσετε το σφάλμα, κωδικοποιήστε τα bytes ρητά με .encode και πείτε στην python τι codec να χρησιμοποιήσει:
a.encode('utf-8')
=> 'bats\xc3\xa0'
print a.encode('utf-8')
=> batsà
Voil\u00E0!
Το πρόβλημα είναι ότι όταν καλείτε την str(), η python χρησιμοποιεί την προεπιλεγμένη κωδικοποίηση χαρακτήρων για να προσπαθήσει να κωδικοποιήσει τα bytes που της δώσατε, τα οποία στην περίπτωσή σας είναι μερικές φορές αναπαραστάσεις χαρακτήρων unicode. Για να διορθώσετε το πρόβλημα, πρέπει να πείτε στην python πώς να χειριστεί το αλφαριθμητικό που της δίνετε χρησιμοποιώντας την .encode('whatever_unicode'). Τις περισσότερες φορές, θα πρέπει να είστε εντάξει χρησιμοποιώντας utf-8.
Για μια εξαιρετική παρουσίαση αυτού του θέματος, δείτε την ομιλία του Ned Batchelder's PyCon εδώ: http://nedbatchelder.com/text/unipain.html
Έχω διαπιστώσει ότι στις περισσότερες από τις περιπτώσεις μου, η αφαίρεση αυτών των χαρακτήρων είναι πολύ απλούστερη:
s = mystring.decode('ascii', 'ignore')