0

如何让 urllib 仅取消引用有效的 % 编码字符串?

html_parser = HTMLParser.HTMLParser()
url = 'Time-@#*%ed%20&'
print urllib2.unquote(url)
print html_parser.unescape(url)

结果是

Time-@#*� &
Time-@#*%ed%20&

urllib unquote '%20' to ' ',但它也错误地 unquote '%ed' to '�'

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)
4

3 回答 3

3

问题是这%ed 一个有效的 % 编码字符,因为ed它是一个有效的十六进制值。如果%要保持不变,则应将其编码为%or %。所以你真正的问题是你的url字符串没有正确编码:如果%ed要保持不变,字符串应该是:

url = 'Time-@#*%ed%20&'

由于它没有正确编码(顺便说一句,你是怎么得到它的?)你不能要求标准工具能够正确解码它。unquote 怎么会知道%20必须处理但%ed不能处理?

那时,您能做的最好的事情就是构建一个自定义解码器。

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

这使 :

Time-@#*%ed &
于 2015-01-05T06:47:42.590 回答
2

&html entity在 html 页面中使用 - 而不是在 url 中。所以url unquoting不会处理它。

另一方面,%ed并​​且%20url 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为字符,您必须知道这些字节应该代表字符的编码。我只是猜到了——但你必须知道,否则你通常无法进行这样的字符串转换。

于 2015-01-05T06:46:39.617 回答
1

unquote() 返回的字符串是 latin1 编码的。尝试这个:

import urllib2
url = 'Time-@#*%ed%20&'
x = urllib2.unquote(url)
u = x.decode('iso-8859-1')
print u

u将是一个 unicode 字符串。

根据 Wikipedia page on percent encoding (link)百分比编码也可用于编码 UTF-8 数据,因此您可能需要x.decode('utf-8')改用。这完全取决于这些数据的来源和上下文。

于 2015-01-05T06:51:15.580 回答