python urllib 反引号损坏
python urllib unquote corrupt
如何让 urllib 只取消引用有效的 % 编码字符串?
html_parser = HTMLParser.HTMLParser()
url = 'Time-@#*%ed%20&'
print urllib2.unquote(url)
print html_parser.unescape(url)
结果是
Time-@#*� &
Time-@#*%ed%20&
urllib 将 '%20' 取消引用到 ' ',但它也错误地将 '%ed' 取消引用到 '�'
HTMLParser 可以转义 '&'为“&”,但无法将“%20”转换为“”
----------------编辑-----
很抱歉没有很好地解释我的问题,事实上我有很多字符串要处理,有些是 URL,有些不是。原来的字符串是Time-@#*%ed
,我把字符串改成Time-@#*%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 = 'Time-@#*%ed%20&'
print urllib.unquote(url)
print html_parser.unescape(url)
print unquote_string(url)
&
是用于 html 页面的 html entity
,而不是 url。所以 url unquoting
不会处理它。
另一方面,%ed
和 %20
是 url escapes
,它们被格式化为作为 url 的一部分进行传输,因此 html unescaping
不会不要对它们进行处理。
如果要同时转换 html 实体和 url 转义,则需要分别处理每个序列:
import urllib
import HTMLParser
import re
html_parser = HTMLParser.HTMLParser()
data = 'Time-@#*%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:--
Time-@#*í &
一个问题:要将像 ed
这样的随机字节序列转换为字符,您必须知道这些字节代表字符的编码。我只是猜测——但你必须知道,否则你通常无法像那样转换字符串。
问题在于 %ed
是 一个有效的 % 编码字符,因为 ed
是一个有效的十六进制值。如果要保持 %
不变,则应将其编码为 %
或 %
。所以你真正的问题是你的 url
字符串没有正确编码:如果 %ed
保持不变,字符串应该是:
url = 'Time-@#*%ed%20&'
因为它没有正确编码(顺便说一句,你是怎么得到它的?)你不能要求标准工具能够正确解码它。 unquote 怎么知道必须处理 %20
而 %ed
不能?
到那时,您能做的最好的事情就是构建一个自定义解码器。
url2 = url.replace('%20', ' ')
print html_parser.unescape(url2)
给出:
Time-@#*%ed &
unquote() 返回的字符串是 latin1 编码的。试试这个:
import urllib2
url = 'Time-@#*%ed%20&'
x = urllib2.unquote(url)
u = x.decode('iso-8859-1')
print u
u
将是一个 unicode 字符串。
根据有关百分比编码的维基百科页面,(link)百分比编码也可用于对 UTF-8 数据进行编码,因此您可能需要改用 x.decode('utf-8')
。这完全取决于这些数据的来源和上下文。
如何让 urllib 只取消引用有效的 % 编码字符串?
html_parser = HTMLParser.HTMLParser()
url = 'Time-@#*%ed%20&'
print urllib2.unquote(url)
print html_parser.unescape(url)
结果是
Time-@#*� &
Time-@#*%ed%20&
urllib 将 '%20' 取消引用到 ' ',但它也错误地将 '%ed' 取消引用到 '�'
HTMLParser 可以转义 '&'为“&”,但无法将“%20”转换为“”
----------------编辑-----
很抱歉没有很好地解释我的问题,事实上我有很多字符串要处理,有些是 URL,有些不是。原来的字符串是Time-@#*%ed
,我把字符串改成Time-@#*%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 = 'Time-@#*%ed%20&'
print urllib.unquote(url)
print html_parser.unescape(url)
print unquote_string(url)
&
是用于 html 页面的 html entity
,而不是 url。所以 url unquoting
不会处理它。
另一方面,%ed
和 %20
是 url escapes
,它们被格式化为作为 url 的一部分进行传输,因此 html unescaping
不会不要对它们进行处理。
如果要同时转换 html 实体和 url 转义,则需要分别处理每个序列:
import urllib
import HTMLParser
import re
html_parser = HTMLParser.HTMLParser()
data = 'Time-@#*%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:--
Time-@#*í &
一个问题:要将像 ed
这样的随机字节序列转换为字符,您必须知道这些字节代表字符的编码。我只是猜测——但你必须知道,否则你通常无法像那样转换字符串。
问题在于 %ed
是 一个有效的 % 编码字符,因为 ed
是一个有效的十六进制值。如果要保持 %
不变,则应将其编码为 %
或 %
。所以你真正的问题是你的 url
字符串没有正确编码:如果 %ed
保持不变,字符串应该是:
url = 'Time-@#*%ed%20&'
因为它没有正确编码(顺便说一句,你是怎么得到它的?)你不能要求标准工具能够正确解码它。 unquote 怎么知道必须处理 %20
而 %ed
不能?
到那时,您能做的最好的事情就是构建一个自定义解码器。
url2 = url.replace('%20', ' ')
print html_parser.unescape(url2)
给出:
Time-@#*%ed &
unquote() 返回的字符串是 latin1 编码的。试试这个:
import urllib2
url = 'Time-@#*%ed%20&'
x = urllib2.unquote(url)
u = x.decode('iso-8859-1')
print u
u
将是一个 unicode 字符串。
根据有关百分比编码的维基百科页面,(link)百分比编码也可用于对 UTF-8 数据进行编码,因此您可能需要改用 x.decode('utf-8')
。这完全取决于这些数据的来源和上下文。