2013-06-30 21 views
5

Tôi nhận được mã nguồn của trang web và mã hóa là cp1252. Chrome hiển thị trang chính xác.Làm thế nào để giải mã cp1252 có dạng thập phân & # 147 thay vì x93?

Đây là mã của tôi:

import sys 
from urllib.request import urlopen 
from bs4 import BeautifulSoup, UnicodeDammit 
import re 
import codecs 

url = "http://www.sec.gov/Archives/edgar/data/1400810/000119312513211026/d515005d10q.htm" 
page = urlopen(url).read() 
print(page) 
# A little preview : 
# b'...Regulation S-T (&#167;232.405 of this chapter) during the preceding 12 months (or for such shorter period that the\nregistrant was required to submit and post such files).&nbsp;&nbsp;&nbsp;&nbsp;Yes&nbsp;&nbsp;<FONT STYLE="FONT-FAMILY:WINGDINGS">&#120;</FONT>...' 

soup = BeautifulSoup(page, from_encoding="cp1252") 
print(str(soup).encode('utf-8')) 
# Same preview section as above 
# b'...Regulation S-T (\xc2\xa7232.405 of this chapter) during the preceding 12 months (or for such shorter period that the\nregistrant was required to submit and post such files).\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0Yes\xc2\xa0\xc2\xa0<font style="FONT-FAMILY:WINGDINGS">x</font>' 

Từ phần xem trước, chúng ta có thể thấy rằng
& nbsp \; = \ xc2 \ xa0
& # 167; = \ xc2 \ xa7
& # 120; = X

Đối với các tiêu chuẩn mã hóa cp1252, tôi đang đề cập đến http://en.wikipedia.org/wiki/Windows-1252#Code_page_layout và /Lib/encodings/cp1252.py

Khi tôi sử dụng BeautifulSoup (trang, from_encoding = "cp1252") một số ký tự được mã hóa một cách chính xác, nhưng một số khác thì không.

ký tự | mã hóa thập phân | cp1252-> utf-8 encoding
“| & # 147; | \ xc2 \ x93 (sai)
”| & # 148; | \ xc2 \ x94 (sai)
X | & # 120; | \ xc2 \ x92 (sai)
§ | & # 167; | \ xc2 \ xa7 (ok)
þ | & # 254;
¨ | & # 168;
'| & # 146; | \ xc2 \ x92 (sai)
- | & # 150;

tôi sử dụng mã này để có được tương đương:

characters = "’ “ ” X § þ ¨ ' –" 
list = characters.split() 

for ch in list: 
    print(ch) 
    cp1252 = ch.encode('cp1252') 
    print(cp1252) 

    decimal = cp1252[0] 

    special = "&#" + str(decimal) 
    print(special) 
    print(ch.encode('utf-8')) 
    print() 

offenders = [120, 146] 

for n in offenders: 
    toHex = hex(n) 
    print(toHex) 
print() 

#120 
off = b'\x78' 
print(off) 
buff = off.decode('cp1252') 
print(buff) 
uni = buff.encode('utf-8') 
print(uni) 
print() 

#146 
off = b'\x92' 
print(off) 
buff = off.decode('cp1252') 
print(buff) 
uni = buff.encode('utf-8') 
print(uni) 
print() 

đầu ra

’ 
b'\x92' 
&#146 
b'\xe2\x80\x99' 

“ 
b'\x93' 
&#147 
b'\xe2\x80\x9c' 

” 
b'\x94' 
&#148 
b'\xe2\x80\x9d' 

X 
b'X' 
&#88 
b'X' 

§ 
b'\xa7' 
&#167 
b'\xc2\xa7' 

þ 
b'\xfe' 
&#254 
b'\xc3\xbe' 

¨ 
b'\xa8' 
&#168 
b'\xc2\xa8' 

' 
b"'" 
&#39 
b"'" 

– 
b'\x96' 
&#150 
b'\xe2\x80\x93' 

0x78 
0x92 

b'x' 
x 
b'x' 

b'\x92' 
’ 
b'\xe2\x80\x99' 

Một số ký tự không sao chép-dán vào trình soạn thảo như X kỳ lạ và kỳ lạ', vì vậy tôi đã thêm một số mã để đối phó với điều đó.

Tôi có thể làm gì để nhận \ xe2 \ x80 \ x9d thay vì \ xc2 \ x94 cho ”(& # 148;)?

thiết lập của tôi:
Windows 7
Terminal: chcp 1252 + Lucida Console phông chữ
Python 3.3
BeautifulSoup 4

Mong câu trả lời của bạn

Trả lời

1

Đây là những gì tôi đã kết thúc bằng

def reformatCp1252(match): 
    codePoint = int(match.group(1)) 

    if 128 <= codePoint <= 159: 
     return bytes([codePoint]) 
    else: 
     return match.group() 

localPage = urlopen(r_url).read() 
formatedPage = re.sub(b'&#(\d+);', reformatCp1252, localPage, flags=re.I) 
localSoup = BeautifulSoup(formatedPage, "lxml", from_encoding="windows-1252") 

Ghi chú: Tôi đang sử dụng BS4 với python3.3 trong windows7

tôi phát hiện ra rằng from_encoding đến BeautifulSoup thực sự không quan trọng, bạn có thể đặt utf-8 hoặc windows-1252 và nó cung cấp mã hóa utf-8 đầy đủ thay thế mã hóa windows-1252 thành utf-8.
Về cơ bản tất cả các codepoints được hiểu là utf-8 và byte đơn \ x? được hiểu là windows-1252.

Theo như tôi biết chỉ ký tự từ 128 đến 159 trong cửa sổ-1252 khác với các ký tự utf-8. Ví dụ, mã hóa hỗn hợp (windows-1252: \ x93 và \ x94 với utf-8: & # 376;) sẽ chỉ xuất ra một phép biến đổi chỉ trong utf-8.

byteStream = b'\x93Hello\x94 (\xa7232.405 of this chapter) &#376; \x87' 
# with code above 
print(localSoup.encode('utf-8')) 
# and you can see that \x93 was transformed to its utf-8 equivalent. 
0

đẹp súp được giải thích các mã điểm trong thực thể, đó là số, ví dụ: &#147; dưới dạng mã mã Unicode thay vì CP-1252 điểm mã. Từ tài liệu và nguồn cho BeautifulSoup 4, không rõ liệu có cách nào thay đổi cách hiểu này của các thực thể HTML hay không. (Lớp EntitySubstitution trông đầy hứa hẹn nhưng không có móc để tùy chỉnh nó được phơi bày.)

Giải pháp sau đây là hackey và sẽ chỉ hoạt động theo giả định rằng tất cả các ký tự không phải ASCII (ví dụ trên mã số 127) bị hiểu sai theo cách giống nhau (điều này sẽ không xảy ra nếu có CP-1252 ký tự thô trong bản gốc, mà BeautifulSoup sẽ giải thích chính xác, giải pháp này sẽ mangle những ký tự đó).

Giả sử rằng bạn có văn bản từ chuyển đổi Beautiful Soup (với các mã HTML hiểu là mã Unicode-điểm):

soup = BeautifulSoup(page, from_encoding="cp1252") 
txt = str(soup) 

Sau đây sẽ tái diễn dịch các mã như CP-1252:

def reinterpret_codepoints(chars, encoding='cp1252'): 
    '''Converts code-points above 127 in the text to the given 
    encoding (assuming that all code-points above 127 represent 
    code-points in the given encoding) 
    ''' 
    for char, code in zip(chars, map(ord, txt)): 
     if code < 127: 
      yield char 
     else: 
      yield bytes((code,)).decode(encoding) 

fixed_text = ''.join(reinterpret_codepoints(txt)) 

Giải pháp này không được tối ưu hóa cho hiệu suất, nhưng tôi nghĩ rằng nó có thể là đủ tốt cho trường hợp cụ thể này.

Tôi đã trích xuất tất cả các điểm mã trên 127 từ văn bản "cố định" cho URL bạn đã cung cấp trong ví dụ của mình. Đây là những gì tôi đã (dường như để trang trải các ký tự mà bạn đang quan tâm):

char | Unicode code-point | CP-1252 code-point | CP-1252 | UTF-8 
  | 160 | 160 | b'\xa0' | b'\xc2\xa0' 
§ | 167 | 167 | b'\xa7' | b'\xc2\xa7' 
¨ | 168 | 168 | b'\xa8' | b'\xc2\xa8' 
– | 8211 | 150 | b'\x96' | b'\xe2\x80\x93' 
— | 8212 | 151 | b'\x97' | b'\xe2\x80\x94' 
’ | 8217 | 146 | b'\x92' | b'\xe2\x80\x99' 
“ | 8220 | 147 | b'\x93' | b'\xe2\x80\x9c' 
” | 8221 | 148 | b'\x94' | b'\xe2\x80\x9d' 
• | 8226 | 149 | b'\x95' | b'\xe2\x80\xa2' 
0

Tham chiếu ký tự số trong HTML dùng để chỉ một Unicode điểm mã ví dụ, nó không phụ thuộc vào mã hóa ký tự của tài liệu ví dụ: &#148;U+0094 CANCEL CHARACTER*.

b"\xe2\x80\x9d" byte hiểu là utf-8 là U+201D RIGHT DOUBLE QUOTATION MARK:

u'\u201d'.encode('utf-8') == b'\xe2\x80\x9d' 
u'\u201d'.encode('cp1252') == b'\x94' 
u'\u201d'.encode('ascii', 'xmlcharrefreplace') == b'&#8221;' 

Để khắc phục các mã, loại bỏ bit không cần thiết:

from urllib.request import urlopen 
from bs4 import BeautifulSoup 

url = "http://www.sec.gov/path/to.htm" 
soup = BeautifulSoup(urlopen(url)) 
print(soup) 

Nếu nó không thành công; hãy thử sys.stdout.buffer.write(soup.encode('cp1252')) hoặc đặt PYTHONIOENCODING biến môi trường thành cp1252:xmlcharrefreplace.

Các vấn đề liên quan