Python 3.x 请求使用 unicode 字符重定向

bas*_*flp 5 python unicode character-encoding python-3.x python-requests

我试图requests.get()在 Python 3.x 中获取以下 URL :http : //www.finanzen.net/suchergebnis.asp? strSuchString= DE0005933931(此 URL 由带有搜索字符串的基本 URL 组成DE0005933931)。

请求被重定向(通过 HTTP 状态代码 301)到浏览器中的http://www.finanzen.net/etf/ishares_core_dax%AE_ucits_etf_de(在 URL 中包含字符 0xAE字符 ®)。requests.get()与重定向的 URL 一起使用也有效。

当尝试使用Python 2.7获取搜索字符串 URL 时,一切正常并且我得到重定向响应,使用Python 3.x 时出现以下错误:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xae in position 21: invalid start byte
Run Code Online (Sandbox Code Playgroud)

测试这个的代码片段:

import requests

url_1 = 'http://www.finanzen.net/suchergebnis.asp?strSuchString=LU0274208692'
# redirected to http://www.finanzen.net/etf/db_x-trackers_msci_world_index_ucits_etf_1c
url_2 = 'http://www.finanzen.net/suchergebnis.asp?strSuchString=DE0005933931'
# redirected to http://www.finanzen.net/etf/ishares_core_dax%AE_ucits_etf_de

print(requests.get(url_1).status_code)  # working
print(requests.get(url_2).status_code)  # error with Python 3.x
Run Code Online (Sandbox Code Playgroud)

更多信息:

  • 我正在使用 Python 3.6.3 在 Windows 7 上工作,requests.__version__ = '2.18.4'但我在使用其他 Python 版本(3.4、3.5)时也遇到相同的错误。
  • 使用其他搜索字符串,一切都适用于 Python 3.x,例如 http://www.finanzen.net/suchergebnis.asp?strSuchString=LU0274208692
  • 有趣的是,我什至Internal Server Error通过https://www.hurl.it尝试获取上述 URL。也许这不是 Python 问题。

任何想法,为什么这在 Python 2.7 中有效,但在 Python 3.x 中无效,我能做些什么?

Mar*_*ers 5

服务器以一个编码为 Latin-1 的 URL 响应,该 URL不是 URL 编码的;非 ASCII 字节显示为0x??十六进制转义:

Location: /etf/ishares_core_dax0xAE_ucits_etf_de
Run Code Online (Sandbox Code Playgroud)

0xAE 字节没有有效的 URL 字符;服务器在这里违反了标准。他们应该发送的是

Location: /etf/ishares_core_dax%AE_ucits_etf_de
Run Code Online (Sandbox Code Playgroud)

或者

Location: /etf/ishares_core_dax%C2%AE_ucits_etf_de
Run Code Online (Sandbox Code Playgroud)

将转义数据用于 URL 的 Latin-1 或 UTF-8 编码。

requests面对此错误,我们可以通过返回未Location更改的标头来修补以使其更健壮:

from requests.sessions import SessionRedirectMixin

def get_redirect_target(
        self, resp, _orig=SessionRedirectMixin.get_redirect_target):
    try:
        return _orig(self, resp)
    except UnicodeDecodeError:
        return resp.headers['location']

SessionRedirectMixin.get_redirect_target = get_redirect_target
Run Code Online (Sandbox Code Playgroud)

应用此补丁后,重定向按预期工作。

我创建了一个拉取请求来改进位置处理。

  • @Tomalak:然而,设计可能会更健壮。 (2认同)