Traducción de caracteres de varios bytes a ASCII de 7 bits en Python

Estoy descargando y analizando una página web a través de un script de Python. Necesito que se codifique en ASCII de 7 bits para su posterior procesamiento. Estoy usando la biblioteca de solicitudes (http://docs.python-requests.org/en/master/) en un virtualenv basado en lo que sea Ubuntu 16.04 LTS.

Me gustaría que el paquete de solicitudes, o algún paquete, maneje la traducción al ASCII, sin requerir que haga más traducciones de caracteres codificados, porque sé que voy a perder algunos caracteres. Los detalles son los siguientes:

Mi script actual de Python, que se muestra a continuación, utiliza una codificación de ISO-8859-1 en un intento de forzar la conversión de los datos de resultados a ASCII de 7 bits, con cierto éxito parcial. Pero, he configurado la codificación de resultadosy también codifica el texto cuando sale. Eso parece extraño y, de hecho, francamente incorrecto. Pero incluso si vivo con eso, tengo el problema principal que es el siguiente:

Incluso después de la codificación, veo guiones codificados en lo que parece estar en un conjunto de caracteres no ASCII. Es como si los caracteres del guión se deslizaran por la codificación de solicitudes. La secuencia de comandos que se muestra a continuación aborda este problema buscando y reemplazando la codificación de guiones de varios bytes con un carácter de guión ASCII. Esto no es un gran problema si es un carácter de varios bytes, pero sospecha que hay otros caracteres que deberán traducirse en otras páginas web que deseo procesar. ¿Simplemente necesito usar alguna otra codificación que no sea 'ISO-8859-1' con el objeto de solicitud?

Aquí está mi script (usando Python 2.7.11 en Ubuntu 16.04 LTS en 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)

Invocar simple_wget.py dentro de virtualenv muestra:

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>

Pasando esa salida a través deoc -cb para ver los valores octales ("342 200 223") de los caracteres de guión correspondientes ar'\xe2\x80\x93' en el guión de arriba:

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:~$

Cosas que he probado:

https://stackoverflow.com/a/19645137/257924 implica el uso de una codificación deascii, pero se ahoga dentro de la biblioteca de solicitudes. Cambiar el guión para que sea:

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

rendimientos:

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)

Cambiar la última línea de arriba para que sea

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

da como resultado que los guiones se eliminen, no se traduzcan, lo que no es lo que quiero.

Y esto tampoco funciona en absoluto:

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)

porque da este error:

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

que es, por lo que puedo entender dehttps://stackoverflow.com/a/10385520/257924, debido a que los "datos" no son una cadena Unicode. Una tabla de traducción de 256 caracteres no va a hacer lo que necesito de todos modos. Y además de eso es exagerado: algo dentro de Python debería traducir estos caracteres de varios bytes sin requerir un código de pirateo en mi nivel de script.

Por cierto, no estoy interesado en la traducción de páginas en varios idiomas. Se espera que todas las páginas traducidas estén en inglés estadounidense o británico.

Respuestas a la pregunta(1)

Su respuesta a la pregunta