Перевод многобайтовых символов в 7-битный ASCII в Python

Я загружаю и анализирую веб-страницу через скрипт Python. Мне нужно, чтобы он был закодирован в 7-битный ASCII для дальнейшей обработки. Я использую библиотеку запросов (http://docs.python-requests.org/en/master/) в virtualenv, основанном на том, что есть в Ubuntu 16.04 LTS.

Я бы хотел, чтобы пакет запросов или какой-то другой пакет обрабатывал перевод в ASCII, не требуя от меня дальнейшего перевода закодированных символов, потому что я знаю, что пропущу некоторые символы. Детали следующие:

Мой текущий скрипт Python, показанный ниже, использует кодировку ISO-8859-1 в попытке принудительно преобразовать данные результата в 7-битный ASCII с некоторым частичным успехом. Но я установил кодировку результатаа также также закодировать текст, когда он выходит. Это кажется странным и, на самом деле, совершенно неправильным. Но даже если я живу с этим, у меня есть главная проблема, которая заключается в следующем:

Даже после кодирования, я вижу штрихи, закодированные в том, что, кажется, находится в некотором наборе символов не ASCII. Как будто символы тире проскальзывали через кодировку запросов. Приведенный ниже сценарий решает эту проблему путем поиска и замены многобайтовой кодировки тире на символ ASCII. Это не имеет большого значения, если это один многобайтовый символ, но подозреваю, что есть другие символы, которые нужно будет перевести на другие веб-страницы, которые я хочу обработать. Нужно ли просто использовать какую-либо другую кодировку, отличную от «ISO-8859-1», с объектом запросов?

Вот мой скрипт (с использованием Python 2.7.11 на Ubuntu 16.04 LTS на x86_64):

 #!/bin/bash

 import sys
 import os
 import string
 import re
 import requests

 url = "https://system76.com/laptops/kudu"

 r = requests.get(url)

 #
 # Why do I have to BOTH set r.encoding AND call r.text.encode
 # in order to avoid the errors?:
 #
 encoding = 'ISO-8859-1'
 r.encoding = encoding
 data = r.text.encode(encoding)

 #
 # Split the lines out, find the offending line,
 # and translate the multi-byte characters:
 #
 lines = data.splitlines()
 for line in lines:
     m = re.search(r'2.6 up to 3.5 GHz', line)
     if m:
         print "line:      {}".format(line)
         m = re.search(r'\xe2\x80\x93', line)
         # The '-' in the next line is a ASCII dash character:
         fixed_line = re.sub(r'\xe2\x80\x93', '-', line)
         print "fixed_line {}".format(line)

Вызов simple_wget.py в рамках virtualenv показывает:

theuser@thesystem:~$ simple_wget.py
line:                           <td>2.6 up to 3.5 GHz – 6 MB cache – 4 cores – 8 threads</td>
fixed_line                      <td>2.6 up to 3.5 GHz - 6 MB cache - 4 cores - 8 threads</td>

Передача этого выхода черезoc -cb чтобы увидеть восьмеричные значения ("342 200 223") символов тире, соответствующихr'\xe2\x80\x93' в сценарии выше:

theuser@thesystem:~$ simple_wget.py | od -cb
0000000   l   i   n   e   :                          \t  \t  \t  \t  \t
        154 151 156 145 072 040 040 040 040 040 040 011 011 011 011 011
0000020  \t   <   t   d   >   2   .   6       u   p       t   o       3
        011 074 164 144 076 062 056 066 040 165 160 040 164 157 040 063
0000040   .   5       G   H   z     342 200 223       6       M   B    
        056 065 040 107 110 172 040 342 200 223 040 066 040 115 102 040
0000060   c   a   c   h   e     342 200 223       4       c   o   r   e
        143 141 143 150 145 040 342 200 223 040 064 040 143 157 162 145
0000100   s     342 200 223       8       t   h   r   e   a   d   s   <
        163 040 342 200 223 040 070 040 164 150 162 145 141 144 163 074
0000120   /   t   d   >  \n   f   i   x   e   d   _   l   i   n   e    
        057 164 144 076 012 146 151 170 145 144 137 154 151 156 145 040
0000140  \t  \t  \t  \t  \t  \t   <   t   d   >   2   .   6       u   p
        011 011 011 011 011 011 074 164 144 076 062 056 066 040 165 160
0000160       t   o       3   .   5       G   H   z       -       6    
        040 164 157 040 063 056 065 040 107 110 172 040 055 040 066 040
0000200   M   B       c   a   c   h   e       -       4       c   o   r
        115 102 040 143 141 143 150 145 040 055 040 064 040 143 157 162
0000220   e   s       -       8       t   h   r   e   a   d   s   <   /
        145 163 040 055 040 070 040 164 150 162 145 141 144 163 074 057
0000240   t   d   >  \n
        164 144 076 012
0000244
theuser@thesystem:~$

Вещи, которые я пробовал:

https://stackoverflow.com/a/19645137/257924 подразумевает использование кодировкиascii, но он задыхается внутри библиотеки запросов. Меняем скрипт на:

#encoding = 'ISO-8859-1'
encoding = 'ascii' # try https://stackoverflow.com/a/19645137/257924
r.encoding = encoding
data = r.text.encode(encoding)

выходы:

theuser@thesystem:~$ ./simple_wget
Traceback (most recent call last):
  File "./simple_wget.py", line 18, in <module>
    data = r.text.encode(encoding)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 10166-10168: ordinal not in range(128)

Изменение последней строки выше, чтобы быть

data = r.text.encode(encoding, "ignore")

в результате черточки просто удаляются, а не переводятся, а это не то, что я хочу.

И это тоже не работает вообще:

encoding = 'ISO-8859-1'
r.encoding = encoding
data = r.text.encode(encoding)

charmap = {
    0x2014: u'-',   # em dash
    0x201D: u'"',   # comma quotation mark, double
    # etc.
}
data = data.translate(charmap)

потому что это дает эту ошибку:

Traceback (most recent call last):
  File "./simple_wget.py", line 30, in <module>
    data = tmp2.translate(charmap)
TypeError: expected a string or other character buffer object

что, насколько я могу понять изhttps://stackoverflow.com/a/10385520/257924, из-за того, что «данные» не являются строкой Unicode. Таблица перевода из 256 символов не будет делать то, что мне нужно. И кроме того, это излишне: что-то внутри Python должно переводить эти многобайтовые символы, не требуя взлома кода на моем уровне сценария.

Кстати, меня не интересует многоязычный перевод страниц. Ожидается, что все переведенные страницы будут на американском или британском английском.

Ответы на вопрос(1)

Ваш ответ на вопрос