2015-01-05 27 views
0

如何让urllib只引用有效的%编码字符串?python urllib无法引用损坏

html_parser = HTMLParser.HTMLParser() 
url = '[email protected]#*%ed%20&' 
print urllib2.unquote(url) 
print html_parser.unescape(url) 

结果是

[email protected]#*� & 
[email protected]#*%ed%20& 

的urllib引文结束 '%20' '',但它也错引文结束 '%ED' 到 ''

的HTMLParser能逃脱“&安培; “为 '&',但它不能将 '%20' ''

--------------编辑------

我道歉不能很好地解释我的问题,实际上我有很多字符串需要处理,有些是URL,有些则不是。原始字符串是[email protected]#*%ed,我将字符串设为[email protected]#*%ed%20&以包含这两种情况。事实证明,很难在一行代码中处理这两种情况。阅读的答案后,我写我自己的函数

#!/bin/env python 
#coding: utf8 

import sys 
import os 
import HTMLParser 
import re 
import urllib 

html_parser = HTMLParser.HTMLParser() 
url_pattern = re.compile('^(ftp|http|https)://.{4,}', flags=re.I) 
def unquote_string(url): 
    if url_pattern.search(url): 
     while True: 
      url1 = urllib.unquote(url) 
      if url1 == url: break 
      url = url1 
    else: 
     while True: 
      url1 = html_parser.unescape(url) 
      if url1 == url: break 
      url = url1 

    return url 

url = '[email protected]#*%ed%20&' 
print urllib.unquote(url) 
print html_parser.unescape(url) 
print unquote_string(url) 

回答

3

问题是%ed有效的%编码字符,因为ed是一个有效的十六进制值。如果%要保持不变,则应将其编码为%%。所以你真正的问题是,你url字符串编码不正确:如果%ed要保持不变,该字符串应该是:(?顺便说一句,你是怎么得到它)

url = '[email protected]#*%ed%20&' 

由于它的编码不正确你不能要求标准工具能够正确解码。如何能够知道%20必须处理,但%ed不得?

在这一点上,你可以做的最好的是建立一个自定义的解码器。

url2 = url.replace('%20', ' ') 
print html_parser.unescape(url2) 

其给出:

[email protected]#*%ed & 
+0

看起来我混淆了'%'和'&':-(。Post updated –

1

&是在HTML页面中使用html entity - 不是在一个URL。所以url unquoting将无法​​正常工作。

在另一方面,%ed%20url escapes格式与运输为URL的一部分,因此html unescaping不会对他们的工作。

如果你既想HTML实体和URL逃逸转换,就需要分别处理每个序列:

import urllib 
import HTMLParser 
import re 

html_parser = HTMLParser.HTMLParser() 

data = '[email protected]#*%ed%20&' 

pattern = r""" 
     %    #Match a '%' sign, followed by... 
     [0-9a-f]{2}  #two hex digits.. 
    |    #OR 
     &    #an ampersand, followed by... 
     .*?    #any character, 0 or more times, non-greedy, followed by... 
     ;    #a semi-colon 
""" 

regex = re.compile(pattern, flags=re.X | re.I) 

def replace_func(match_obj): 
    match = match_obj.group(0) 

    if match.startswith('%'): 
     my_str = urllib.unquote(match) 
     my_str = unicode(my_str, 'iso-8859-1').encode('utf-8') 

    elif match.startswith('&'): 
     unicode_str = html_parser.unescape(match) 
     my_str = unicode_str.encode('utf-8') 

    return my_str 

result = re.sub(regex, replace_func, data) 
print result 

--output:-- 
[email protected]#*í & 

一个问题:随机字节序列转换像ed到一个角色,你必须知道这些字节应该表示字符的编码。我只是猜测 - 但你必须知道,否则你通常不能做这样的字符串转换。

1

通过引文结束()返回的字符串是latin1的编码。试试这个:

import urllib2 
url = '[email protected]#*%ed%20&' 
x = urllib2.unquote(url) 
u = x.decode('iso-8859-1') 
print u 

u将是一个unicode字符串。

根据百分比编码的百科页面(link)百分比编码也可用于编码UTF-8数据,因此您可能需要使用x.decode('utf-8')来代替。这一切都取决于这些数据来自何处和上下文。