Python urllib2.urlopen:即使存在HTTP头错误,也要读取站点正文

Python urllib2.urlopen:即使存在HTTP头错误,也要读取站点正文,python,urllib2,Python,Urllib2,我有一个简单的URL,我想从python脚本中调用它: (由于隐私原因,我更改了一些字母,所有特殊字符等都完全相同) 当我调用上述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

我有一个简单的URL,我想从python脚本中调用它: (由于隐私原因,我更改了一些字母,所有特殊字符等都完全相同)

当我调用上述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
如您所见,存在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)
这样我就得到了网站的主体,无论是错误还是成功

(顺便说一句,这是我得到解决方案的帖子:)


多谢各位

编辑2

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

curl可能也在做同样的事情,但是,它没有进行拟合,而是显示响应的主体,因此您会看到“error:parameters missing”。您的浏览器也有类似的行为

尝试运行
curl-vhttp://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有一个更有用的模块:。检查一下。

你如何调用你的
myfunc()
?这没关系,当我在pythonNo中直接调用这些东西时也会发生同样的情况,这些请求都是用GET调用的,并且可以在没有任何参数的情况下调用。您可以看到一些基本的HTML输出,比如“缺少参数”。我刚刚用bash中的curl检查了它,它肯定能工作,只有python模块有这个问题。。。遗憾的是,我不能使用请求,因为我必须在我们的每台服务器上手动pip安装它,这是不可维护的…那么,另一种可能性是
createAccount
需要URL中的查询字符串来传递所需的参数?在你的问题中,你没有表现出这一点,URL的混淆也没有帮助。不,正如我说的,我可以调用
http://test.my-site.com/bla-blah/createAccount
如果在浏览器中或通过curl没有任何进一步的参数或查询字符串,那么python代码就是:
urllib2.urlopen(url)
您的curl测试命令是:
curl url
?在生成的请求中有一些细微的差异(我已经将它们添加到了我的答案中),但是没有一个应该触发HTTP400响应。是否有任何代理可能会更改请求?@Droids-更新答案。请在详细模式下运行curl以检查响应中的实际HTTP状态代码。
[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: */*
import urllib2
from urllib import urlencode

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