Ошибка кодирования в Beautiful Soup: сопоставление символов с неопределенным (Python) - PullRequest
0 голосов
/ 29 мая 2018

Я написал скрипт, который должен извлекать html-страницы с сайта и обновлять их содержимое.Следующая функция ищет определенный файл в моей системе, затем пытается открыть и отредактировать его:

def update_sn(files_to_update, sn, table, title):
    paths = files_to_update['files']
    print('updating the sn')
    try:
        sn_htm = [s for s in paths if re.search('^((?!(Default|Notes|Latest_Addings)).)*htm$', s)][0]
        notes_htm = [s for s in paths if re.search('_Notes\.htm$', s)][0]

    except Exception:
        print('no sns were found')
        pass

    new_path_name = new_path(sn_htm, files_to_update['predecessor'], files_to_update['original'])
    new_sn_number = sn

    htm_text = open(sn_htm, 'rb').read().decode('cp1252')
    content = re.findall(r'(<table>.*?<\/table>.*)(?:<\/html>)', htm_text, re.I | re.S) 
    minus_content = htm_text.replace(content[0], '')
    table_soup = BeautifulSoup(table, 'html.parser')
    new_soup = BeautifulSoup(minus_content, 'html.parser')
    head_title = new_soup.title.string.replace_with(new_sn_number)
    new_soup.link.insert_after(table_soup.div.next)

    with open(new_path_name, "w+") as file:
        result = str(new_soup)
        try:
            file.write(result)
        except Exception:
            print('Met exception.  Changing encoding to cp1252')
            try:
                file.write(result('cp1252'))
            except Exception:
                print('cp1252 did\'nt work.  Changing encoding to utf-8')
                file.write(result.encode('utf8'))
                try:
                    print('utf8 did\'nt work.  Changing encoding to utf-16')
                    file.write(result.encode('utf16'))
                except Exception:
                    pass

В большинстве случаев это работает, но иногда не удается записать, и в этот момент возникает исключениевключается, и я пробую каждую возможную кодировку безуспешно:

updating the sn
Met exception.  Changing encoding to cp1252
cp1252 did'nt work.  Changing encoding to utf-8
Traceback (most recent call last):
  File "C:\Users\Joseph\Desktop\SN Script\update_files.py", line 145, in update_sn
    file.write(result)
  File "C:\Users\Joseph\AppData\Local\Programs\Python\Python36\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode characters in position 4006-4007: character maps to <undefined>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Joseph\Desktop\SN Script\update_files.py", line 149, in update_sn
    file.write(result('cp1252'))
TypeError: 'str' object is not callable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "scraper.py", line 79, in <module>
    get_latest(entries[0], int(num), entries[1])
  File "scraper.py", line 56, in get_latest
    update_files.update_sn(files_to_update, data['number'], data['table'], data['title'])
  File "C:\Users\Joseph\Desktop\SN Script\update_files.py", line 152, in update_sn
    file.write(result.encode('utf8'))
TypeError: write() argument must be str, not bytes

Может кто-нибудь подсказать мне, как лучше обрабатывать HTML-данные, которые могут иметь несовместимую кодировку?

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

В вашем коде вы открываете файл в текстовом режиме, но затем вы пытаетесь записать байты (str.encode возвращает байты), и поэтому Python выдает исключение:

TypeError: write() argument must be str, not bytes

Если вы хотите записать байты, вы должны открыть файл в двоичном режиме.

BeautifulSoup определяет кодировку документа (если это байты) и автоматически преобразует его в строку.Мы можем получить доступ к кодировке с помощью .original_encoding и использовать ее для кодирования содержимого при записи в файл.Например,

soup = BeautifulSoup(b'<tag>ascii characters</tag>', 'html.parser')
data = soup.tag.text
encoding = soup.original_encoding or 'utf-8'
print(encoding)
#ascii

with open('my.file', 'wb+') as file:
    file.write(data.encode(encoding))

Чтобы это работало, вы должны передать свой html в виде байтов в BeautifulSoup, поэтому не декодируйте содержимое ответа.

Если BeautifulSoup по какой-то причине не может определить правильную кодировку, вы можете попробовать список возможных кодировок, как вы сделали в своем коде.

data = 'Somé téxt'
encodings = ['ascii', 'utf-8', 'cp1252']

with open('my.file', 'wb+') as file:
    for encoding in encodings:
        try:
            file.write(data.encode(encoding))
            break
        except UnicodeEncodeError:
            print(encoding + ' failed.')

Кроме того, вы можете открыть файл в текстовом режиме и установить кодировку в open (вместо кодирования содержимого), но учтите, что эта опция недоступна в Python2.

0 голосов
/ 29 мая 2018

Просто из любопытства, является ли эта строка кода опечаткой file.write(result('cp1252'))?Кажется, что отсутствует метод .encode.

Traceback (most recent call last):
  File "C:\Users\Joseph\Desktop\SN Script\update_files.py", line 149, in update_sn
    file.write(result('cp1252'))
TypeError: 'str' object is not callable

Будет ли он работать идеально, если вы измените код на: file.write(result.encode('cp1252'))

Когда-то у меня была эта запись в файл с проблемой кодировки иЯ создал собственное решение через следующую ветку:

Сохранение текстов utf-8 в json.dumps как UTF8, а не как \ u escape-последовательность .

Моя проблема решенаизменив режим разбора html.parser на html5lib.Я вызвал корень моей проблемы из-за некорректного тега HTML и решил ее с помощью html5lib парсера.Для справки: это документация для каждого парсера, предоставленная BeautifulSoup.

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...