【问题标题】:Python urllib2.urlopen: Read site-body even though there is an HTTP header errorPython urllib2.urlopen:即使存在 HTTP 标头错误,也要读取站点正文
【发布时间】:2015-01-31 23:08:42
【问题描述】:

我有一个简单的 URL,我想从我的 python 脚本中调用它: http://test.my-site.com/bla-blah/createAccount (由于隐私,我更改了一些字母,所有特殊字符等都完全相同)

import urllib2

def myfunc(self, url):  
    result = urllib2.urlopen(url).read()
    # HTTP Error 400: Bad Request

当我调用上面的 URL 时,我得到了错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 406, in open
    response = meth(req, response)
  File "/usr/lib/python2.7/urllib2.py", line 519, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib/python2.7/urllib2.py", line 444, in error
    return self._call_chain(*args)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 527, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
urllib2.HTTPError: HTTP Error 400: Bad Request

我不认为它与引号(显然和/或空格)有关。 当我改为调用 URL http://test.my-site.com/bla-blah/listAccounts 时,它工作正常,结果与我在浏览器中调用 URL 时得到的文本完全相同。当然,我通过浏览器检查了第一个 URL,它工作正常。

知道这可能是什么吗?


编辑澄清:

这两个 URL 应该可以在没有任何其他参数或查询字符串的情况下调用,就像它们在上面一样。然后该站点应显示类似“错误:缺少参数”的内容。当我在浏览器中调用 URL 或通过 bash 中的 curl 调用 URL 时,确实会发生这种情况。只是 python 模块出了问题。


Edit2(也更改为帖子标题以更好地匹配情况)

谢谢,你是对的:如果我这样做 curl -v 'http://test.my-site.com/bla-blah/createAccount',我会得到以下信息:

* About to connect() to <blackened> port 80 (#0)
*   Trying 193.46.215.110... connected
> GET <blackened> HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: <blackened>
> Accept: */*
> 
< HTTP/1.1 400 Bad Request
< content-language: en-US
< server: <blackened>
< date: Thu, 04 Dec 2014 07:20:15 GMT
< set-cookie: beng_proxy_session=e2e037e7e79c1b03; HttpOnly; Path=/; Version=1; Discard
< p3p: CP="CAO PSA OUR"
< content-length: 234
< 
error: parameter x missing
error: parameter y missing
* Connection #0 to host <blackened> left intact
* Closing connection #0

如您所见,存在 HTTP 标头错误。但是 curl (和浏览器)继续打印站点正文(“参数丢失......”),但是 python urllib 在看到标题错误后停止并且不打印正文。 (头错误顺便说一句是服务器应用程序发送的东西,我猜。所以这与python urllib无关) 所以我们更近了一步,但即使出现错误,我仍然需要查看主体,因为我必须知道(并显示)到底出了什么问题。 但是刚才我找到了解决方案:

try:
    response = urllib2.urlopen("http://test.my-site.com/bla-blah/createAccount")
    contents = response.read()
    print("success: %s" % contents)
except urllib2.HTTPError as e:
    contents = e.read()
    print("error: %s" % contents)

这样我就可以得到网站的正文,无论是错误还是成功。

(顺便说一句,这是我得到解决方案的帖子:Overriding urllib2.HTTPError or urllib.error.HTTPError and reading response HTML anyway

非常感谢!

【问题讨论】:

  • 你怎么称呼你的myfunc()
  • 没关系,当我直接在python中调用这些东西时也会发生同样的情况

标签: python urllib2


【解决方案1】:

编辑 2

Python 在收到状态码为 400 的 HTTP 响应时引发异常。响应正文中可能有一些您看不到的文本,因为存在异常并且未读取数据。该文本可能是“错误:缺少参数”。

可能 curl 正在做同样的事情,但是,它显示响应的正文而不是合适的,因此您会看到“错误:缺少参数”。与您的浏览器类似的行为。

尝试运行curl -v http://test.my-site.com/bla-blah/createAccount。这将以详细模式运行 curl,您将能够看到响应并检查是否返回状态代码 400。如果是状态码 400 则urllib2.urlopen() 没有问题,只需在查询字符串中发送参数即可。

编辑 1

以下是curl请求和urllib2.urlopen请求的区别...

[mhawke@localhost ~]$ python
GET /bla-blah/createAccount HTTP/1.1
Accept-Encoding: identity
Host: localhost:12345
Connection: close
User-Agent: Python-urllib/2.7

[mhawke@localhost ~]$ nc -l localhost 12345
GET /bla-blah/createAccount HTTP/1.1
User-Agent: curl/7.32.0
Host: localhost:12345
Accept: */*

也许您可以尝试在 Python 中添加/删除标头以实现 curl 生成的相同请求。

原答案

URL http://test.my-site.com/bla-blah/listAccounts 看起来像是一个 HTTP GET 请求,而 http://test.my-site.com/bla-blah/createAccount 可能需要一个包含“创建帐户”所需的数据字段的 HTTP POST 请求。

我不知道您的服务器应用程序需要哪些数据,但是(如果我的猜测是正确的)这通常是您需要考虑做的事情:

import urllib2
from urllib import urlencode

data = {'username': 'droids', 'password': '123droids321', 'phone': '012351234'}
result = urllib2.urlopen(url, urlencode(data)).read()

urlencoded 数据的存在会生成一个 POST 请求,而不是您当前代码将发出的 GET 请求。

请注意,有一个更有用的 HTTP 模块:requests。看看吧。

【讨论】:

  • 不,这些请求都是用GET调用的,可以不带参数调用。您会看到一些基本的 HTML 输出,例如“缺少参数”。此外,我刚刚在 bash 中用 curl 检查了它,它确实有效,只有 python 模块有问题......遗憾的是我不能使用请求,因为我必须在我们的每台服务器上手动 pip-install 它,这根本无法维护......
  • 那么,另一种可能性是createAccount 需要在 URL 中传递所需参数的查询字符串?您没有在问题中表明这一点,并且 URL 的混淆也无济于事。
  • 不,正如我所说,我可以在浏览器中或通过 curl 调用http://test.my-site.com/bla-blah/createAccount,而无需任何其他参数或查询字符串,它可以工作
  • 那么,你的 python 代码是:urllib2.urlopen(url),你的 curl 测试命令是:curl url?生成的请求存在细微差别(我已将这些添加到我的答案中),但没有一个应该触发 HTTP 400 响应。是否有任何代理可能会更改请求?
  • @Droids - 更新答案。请以详细模式运行 curl 以检查响应中的实际 HTTP 状态代码。
猜你喜欢
  • 1970-01-01
  • 2010-10-25
  • 2015-02-05
  • 1970-01-01
  • 2010-12-12
  • 2011-09-02
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多