2013-02-27 50 views
33

Để mã hóa URI, tôi sử dụng urllib.quote("schönefeld") nhưng khi một số ký tự khác ASCII tồn tại trong chuỗi, nó thorwsurllib.quote() throws KeyError

KeyError: u'\xe9' 
Code: return ''.join(map(quoter, s)) 

chuỗi đầu vào của tôi là köln, brønshøj, schönefeld, vv

Khi Tôi đã cố gắng chỉ in báo cáo trong cửa sổ (Sử dụng python2.7, pyscripter IDE). Nhưng trong linux nó làm tăng ngoại lệ (tôi đoán nền tảng không quan trọng).

Đây là những gì tôi đang cố gắng:

from commands import getstatusoutput 
queryParams = "schönefeld"; 
cmdString = "http://baseurl" + quote(queryParams) 
print getstatusoutput(cmdString) 

Khám phá lý do vấn đề: trong urllib.quote(), thực sự ngoại lệ được throwin tại return ''.join(map(quoter, s)).

Mã trong urllib là:

def quote(s, safe='/'): 
    if not s: 
     if s is None: 
      raise TypeError('None object cannot be quoted') 
     return s 
    cachekey = (safe, always_safe) 
    try: 
     (quoter, safe) = _safe_quoters[cachekey] 
    except KeyError: 
     safe_map = _safe_map.copy() 
     safe_map.update([(c, c) for c in safe]) 
     quoter = safe_map.__getitem__ 
     safe = always_safe + safe 
     _safe_quoters[cachekey] = (quoter, safe) 
     if not s.rstrip(safe): 
     return s 
     return ''.join(map(quoter, s)) 

Lý do là ngoại lệ trong ''.join(map(quoter, s)), cho mỗi phần tử trong s, chức năng quoter sẽ được gọi và cuối cùng danh sách sẽ được tham gia bởi '' và trả về.

Đối với thẻ không phải là ascii char è, khóa tương đương sẽ là %E8 có trong biến số _safe_map. Nhưng khi tôi gọi báo giá ('è'), nó tìm kiếm khóa \xe8. Vì vậy, chìa khóa không tồn tại và ngoại lệ ném.

Vì vậy, tôi vừa sửa đổi s = [el.upper().replace("\\X","%") for el in s] trước khi gọi số ''.join(map(quoter, s)) trong khối try-except. Bây giờ nó hoạt động tốt.

Nhưng tôi làm phiền những gì tôi đã làm là cách tiếp cận chính xác hoặc nó sẽ tạo ra bất kỳ vấn đề nào khác? Và tôi cũng có hơn 200 trường hợp của Linux, điều này rất khó triển khai bản sửa lỗi này trong mọi trường hợp.

+2

Đây có phải là Python 2 với các giá trị unicode không? Nó hoạt động tốt cho dữ liệu đã được mã hóa. –

+1

Bạn * không * nhận được lỗi cho 'urllib.quote ('sch \ xe9nefeld')'. Bạn * chỉ * nhận được lỗi cho 'urllib.quote (u'sch \ xe9nefeld ')' (lưu ý 'u''' unicode literal). –

+1

@MartijnPieters vì vậy 'cmdString =" http: // baseurl "+ trích dẫn (" schönefeld ")' điều này phải giống như 'cmdString = u" http: // baseurl "+ trích dẫn (u" schönefeld ")'? – Garfield

Trả lời

54

Bạn đang cố gắng trích dẫn dữ liệu Unicode, vì vậy bạn cần quyết định cách biến nó thành các byte an toàn cho URL.

Mã hóa chuỗi thành byte trước tiên. UTF-8 thường được sử dụng:

>>> import urllib 
>>> urllib.quote(u'sch\xe9nefeld') 
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py:1268: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal 
    return ''.join(map(quoter, s)) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 1268, in quote 
    return ''.join(map(quoter, s)) 
KeyError: u'\xe9' 
>>> urllib.quote(u'sch\xe9nefeld'.encode('utf8')) 
'sch%C3%A9nefeld' 

Tuy nhiên, mã hóa phụ thuộc vào những gì các máy chủ sẽ chấp nhận. Tốt nhất là hãy gắn vào biểu mẫu gốc đã được gửi đi.

+0

utf-8 có trường hợp mạnh hơn câu trả lời của bạn. [Tất cả các trình duyệt chính đều sử dụng utf-8] (http://www.w3.org/International/articles/idn-and-iri/#iriworks) trước khi mã hóa phần trăm trong khi tạo URI. [IRI] (http://www.ietf.org/rfc/rfc3987) tới [URI] (http://www.ietf.org/rfc/rfc3986) phải được chuyển đổi bằng utf-8. Các mã hóa khác được sử dụng trên các máy chủ kế thừa. – jfs

+0

@ J.F.Sebastian: Chắc chắn, các yếu tố đường dẫn của URI sử dụng UTF-8. Nhưng đây là phần truy vấn thay thế. Những gì một trình duyệt sử dụng để mã hóa trong chuỗi truy vấn được xác định ít hơn và đã được, trong quá khứ, dựa trên mã hóa của trang HTML mà biểu mẫu bắt nguồn từ đó. –

0

Tôi đã có những lỗi chính xác giống như @underscore nhưng trong trường hợp của tôi vấn đề là bản đồ (quoter, s) cố gắng tìm chìa khóa u'\xe9' không có trong số _safe_map. Tuy nhiên \xe9 là, vì vậy tôi đã giải quyết vấn đề bằng cách thay thế u'\xe9' bằng \xe9 trong s.

Hơn nữa, không nên tuyên bố return nằm trong số try/except? Tôi cũng phải thay đổi điều này để giải quyết hoàn toàn vấn đề.