Что такое не‑ASCII символы и почему они вызывают проблемы?
Набор символов ASCII (American Standard Code for Information Interchange) включает всего (от U+0000 до U+007F): латинские буквы, цифры, базовые знаки препинания и управляющие символы. Все остальные символы — кириллица, иероглифы, типографские кавычки (например, правый гильмет «»»), специальные пробелы, являются не‑ASCII.
Для их представления в байтах требуются расширенные кодировки, такие как UTF-8, Latin-1 или UTF-16. В Python процесс преобразования байтов в строки (декодирование) и обратно (кодирование) в простых скриптах часто проходит незаметно, но при работе со сложными инструментами парсинга, такими как BeautifulSoup, могут возникать ошибки UnicodeEncodeError, если кодировки не совпадают или если система ожидает ASCII.
Особенности работы BeautifulSoup с кодировками
Решение: всегда декодируйте байты вручную перед передачей в BeautifulSoup:
decoded_content = r.content.decode('utf-8')
Также стоит помнить, что BeautifulSoup не превращает в Tá сам по себе. Если вы видите подобные артефакты, скорее всего, проблема кроется в исходной кодировке страницы или в том, как вы читаете данные.
Популярные методы удаления не‑ASCII символов в Python
Если ваша цель — получить чистый ASCII-текст (например, только латиницу и цифры), существует несколько проверенных способов.
Использование str.encode и str.decode
Это самый простой и элегантный способ. Мы кодируем строку в ASCII с параметром errors='ignore', что заставит Python просто отбросить все не‑ASCII символы, а затем декодируем обратно в строку.
Пример:
s = "privet брат"
s1 = s.encode('ascii', errors='ignore').decode('ascii')
print(s1) # Выведет: privet
Использование метода str.translate
Метод str.translate позволяет удалить все символы из строки, содержащиеся в заданном наборе. Это работает очень быстро и эффективно. Вы можете создать словарь удаления, который будет отсекать все символы с кодом выше 127.
Регулярные выражения (модуль re)
Регулярные выражения позволяют гибко фильтровать текст. Вы можете составить паттерн, который будет находить все символы, не входящие в базовый диапазон ASCII, и заменять их на пустую строку. (Обратите внимание: используйте модуль re, а не устаревший regex, чтобы избежать проблем с совместимостью версий).
Очистка текста от специфических символов при парсинге
Часто нет необходимости удалять всю кириллицу или спецсимволы целиком. При парсинге цен или чисел со страниц (например, с сайта Финам или каталогов товаров) вы можете столкнуться со специфическими пробелами, которые выглядят как обычные, но не удаляются методом .replace(' ', '').
Например, при извлечении текста из тегов:
result = bs.findAll('span', {'class': 'catalog-index__link-text'})[1]
Вы можете получить строку вроде "от 3 836", где пробел между цифрами на самом деле является символом U+00A0 (неразрывный пробел) или U+2009 (узкий пробел). Чтобы очистить цену, необходимо явно указать эти Unicode-коды для замены:
clean_price = result.text.replace(' ', '').replace(' ', '')