2013-05-17 10 views
14

urlparse.parse_qs ist nützlich für die Analyse von URL-Parametern, und es funktioniert gut mit einfachen ASCII-URL, dargestellt durch str. So kann ich eine Abfrage analysieren und dann den gleichen Weg konstruieren urllib.urlencode von analysierten Daten mit:Python urlparse.parse_qs Unicode-URL

>>> import urlparse 
>>> import urllib 
>>> 
>>> path = '/?key=value' #path is str 
>>> query = urlparse.urlparse(path).query 
>>> query 
'key=value' 
>>> query_dict = urlparse.parse_qs(query) 
>>> query_dict 
{'key': ['value']} 
>>> '/?' + urllib.urlencode(query_dict, doseq=True) 
'/?key=value' # <-- path is the same here 

Es funktioniert auch gut, wenn URL enthält Prozent Nicht-ASCII-param codiert:

>>> value = urllib.quote(u'значение'.encode('utf8')) 
>>> value 
'%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5' 
>>> path = '/?key=%s' % value 
>>> path 
'/?key=%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5' 
>>> query = urlparse.urlparse(path).query 
>>> query 
'key=%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5' 
>>> query_dict = urlparse.parse_qs(query) 
>>> query_dict 
{'key': ['\xd0\xb7\xd0\xbd\xd0\xb0\xd1\x87\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb5']} 

>>> '/?' + urllib.urlencode(query_dict, doseq=True) 
'/?key=%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5' # <-- path is the same here 

Aber, wenn mit django, erhalte ich die uRL mit request.get_full_path(), und es gibt Pfad als unicode string:

>>> path = request.get_full_path() 
>>> path 
u'/?key=%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5' # path is unicode 

Sehen sie, was jetzt passieren wird:

>>> query = urlparse.urlparse(path).query 
>>> query 
u'key=%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5' 
>>> query_dict = urlparse.parse_qs(query) 
>>> query_dict 
{u'key': [u'\xd0\xb7\xd0\xbd\xd0\xb0\xd1\x87\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb5']} 
>>> 

query_dict enthält Unicode-String, der Bytes enthält! Keine Unicode-Punkte! Und natürlich habe ich eine UnicodeEncodeError bekam, wenn man versucht, die Zeichenfolge urlencode:

>>> urllib.urlencode(query_dict, doseq=True) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "C:\Python27\Lib\urllib.py", line 1337, in urlencode 
    l.append(k + '=' + quote_plus(str(elt))) 
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-15: ordinal not in range(128) 

Zur Zeit habe ich eine Lösung:

# just convert path, returned by request.get_full_path(), to `str` explicitly: 
path = str(request.get_full_path()) 

So sind die Fragen:

  • warum parse_qs gibt eine so seltsame Zeichenfolge zurück (Unicode, die Bytes enthält)?
  • ist es sicher, url in str zu konvertieren?

Antwort

16

Encode zurück zu Bytes vor es .parse_qs() vorbei, ASCII mit:

query_dict = urlparse.parse_qs(query.encode('ASCII')) 

Dies macht das Gleiche wie str() aber mit einer expliziten Kodierung. Ja, das ist sicher, die URL-Codierung verwendet ASCII-Codepunkte nur.

parse_qs wurde ein Unicode-Wert übergeben, also gab es auch einen Unicode-Wert zurück; Es ist nicht seine Aufgabe, Bytes zu dekodieren.