Python urllib2.HTTPError:HTTP 错误 503:有效网站上的服务不可用

问题描述 投票:0回答:3

我一直在使用亚马逊的产品广告 API 来生成包含给定书籍价格的网址。我生成的一个网址如下:

http://www.amazon.com/gp/offer-listing/0415376327%3FSubscriptionId%3DAKIAJZY2VTI5JQ66K7QQ%26tag%3Damaztest04-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D041 5376327

当我单击链接或将链接粘贴到地址栏上时,网页加载正常。但是,当我执行以下代码时,出现错误:

url = "http://www.amazon.com/gp/offer-listing/0415376327%3FSubscriptionId%3DAKIAJZY2VTI5JQ66K7QQ%26tag%3Damaztest04-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0415376327"
html_contents = urllib2.urlopen(url)

错误是 urllib2.HTTPError:HTTP 错误 503:服务不可用。首先,我不明白为什么网页加载成功后会出现此错误。

另外,我注意到的另一个奇怪的行为是以下代码有时会给出所述错误,有时不会给出所述错误:

html_contents = urllib2.urlopen("http://www.amazon.com/gp/offer-listing/0415376327%3FSubscriptionId%3DAKIAJZY2VTI5JQ66K7QQ%26tag%3Damaztest04-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0415376327")

我完全不知道这种行为是如何发生的。对此有任何修复或解决方法吗?我的目标是读取 url 的 html 内容。

编辑

我不知道为什么堆栈溢出会更改我的代码,将我上面在代码中列出的亚马逊链接更改为 rads.stackoverflow。无论如何,忽略 rads.stackoverflow 链接并在引号之间使用我上面的链接。

python urllib2
3个回答
28
投票

亚马逊拒绝 urllib2 的默认用户代理。一种解决方法是使用请求模块

import requests
page = requests.get("http://www.amazon.com/gp/offer-listing/0415376327%3FSubscriptionId%3DAKIAJZY2VTI5JQ66K7QQ%26tag%3Damaztest04-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0415376327")
html_contents = page.text

如果您坚持使用 urllib2,可以通过伪造标头来实现此目的:

import urllib2
opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
response = opener.open('http://www.amazon.com/gp/offer-listing/0415376327%3FSubscriptionId%3DAKIAJZY2VTI5JQ66K7QQ%26tag%3Damaztest04-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0415376327')
html_contents = response.read()

不用担心 stackoverflow 编辑 URL。他们解释说他们正在这里这样做。


14
投票

这是因为亚马逊不允许自动访问他们的数据,所以他们拒绝您的请求,因为它不是来自正确的浏览器。如果你看一下503回复的内容,它说:

要讨论自动访问亚马逊数据,请联系 [电子邮件受保护]。 有关迁移到我们的 API 的信息,请参阅我们的 Marketplace API:https://developer.amazonservices.com/ref=rm_5_sv, 或我们的产品广告 API: https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html/ref=rm_5_ac 用于广告用例。

这是因为 Python 的

User-Agent
urllib
显然不是浏览器。你总是可以伪造
User-Agent
,但这并不是真正好的(或道德)做法。

顺便说一句,正如另一个答案中提到的,

requests
库非常适合Python中的HTTP访问。


0
投票

本的答案是对OP问题的正确且公认的答案(我猜;我还没有验证它)。

但是,由于这个问题是在谷歌搜索“python 503 urllib2”时第一个出现的问题,并且它没有解决我过去三个小时调查的问题......我将提供替代答案。

如果您不幸遇到 Python 2.6(2023 年!),那么您可能真的运气不好。

TLS 的 SNI 首次在 Python 3 中引入,并向后移植到 Python 2.7(请参阅 https://stackoverflow.com/a/27717544/8280541),但从未添加到 2.6 或更早版本。如今,许多(如果不是大多数)HTTPS 服务器将依赖于 SNI。

长话短说,SNI 允许单个 HTTPS 服务器为多个不同的站点提供服务,并使用可能不同的证书。当客户端通过 HTTPS 连接到服务器时,它所做的第一件事就是向服务器提供其 SNI(服务器名称指示),甚至在它们谈论证书之前。有了这些信息,服务器将能够向客户端提供他们想要的网站内容以及关联的证书。

确认您处于这种情况:

  • 您运行的是 Python 2.6 或更早版本吗?
  • 确认您可以使用不同的 Python 版本、
    curl
    或其他工具从同一主机访问同一地址
  • 运行
    openssl s_client -connect my.server.url:443 < /dev/null | grep subject
    ;记下它显示的服务器名称(它应该是您期望的名称)
  • 运行
    openssl s_client -noservername -connect my.server.url:443 < /dev/null | grep subject
    ;服务器名称已更改

如果是这样的话,Python 2.6 不适合你。也许是时候升级了?如果您仍然坚持使用古老且不受支持的软件,一种替代方法是通过

curl
运行
subprocess.Popen
以获得您想要的东西。

© www.soinside.com 2019 - 2024. All rights reserved.