在Python

时间:2016-07-04 02:43:20

标签: python encoding python-requests

我正在通过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”之外的其他一些编码 请求对象?

这是我的脚本(在x86_64上的Ubuntu 16.04 LTS上使用Python 2.7.11):

 #!/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)

在virtualenv中调用simple_wget.py显示:

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的{​​{1}},但它在请求库中窒息。改变了 脚本是:

#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 个答案:

答案 0 :(得分:1)

Python提供了干净地处理非ASCII字符所需的一切......只要您声明正确的编码即可。您的输入文件是UTF8编码,而不是ISO-8859-1,因为r'\xe2\x80\x93'是EN DASH字符或unicode U+2013的UTF8编码。

所以你应该:

  • 将请求中的文本作为真正的unicode字符串加载:

    url = "https://system76.com/laptops/kudu"
    
    r = requests.get(url)
    r.encoding = "UTF-8"
    data = r.text  # ok, data is a true unicode string
    
  • 在unicode中翻译违规字符

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

    它现在可以工作,因为translate映射对于byte和unicode字符串是不同的。对于字节字符串,转换表必须是长度为256的字符串,而对于unicode字符串,它必须是Unicode序列到Unicode序列,Unicode字符串或无(ref: Python Standard Library Reference Manual)的映射。

  • 然后您可以安全地将数据编码为ascii字节字符串:

    tdata = data.encode('ascii')
    

    如果某些未翻译的非ascii字符保留在data unicode字符串中,则上述命令将抛出异常。您可以看到这是一个帮助,以确保所有内容都已成功转换。