为 Python 3 urllib 开启调试输出

22 投票
3 回答
22784 浏览
提问于 2025-04-15 11:15

在Python 2中,你可以通过以下方式从urllib获取调试输出:

import httplib
import urllib
httplib.HTTPConnection.debuglevel = 1
response = urllib.urlopen('http://example.com').read()

但是在Python 3中,这个功能似乎被移到了:

http.client.HTTPConnection.set_debuglevel(level)

不过,我是直接使用urllib,而不是http.client。我该如何设置才能让我的HTTP请求以这种方式显示调试信息呢?

这是我目前使用的代码。如果我想获取调试信息,最好的方法是什么呢?

#Request Login page
cookiejar = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookiejar))
request = urllib.request.Request(options.uri)
add_std_headers(request)
response = opener.open(request)
response_string = response.read().decode("utf8")
# ...

3 个回答

0

今天的情况跟上次回答的时候有点不一样。

我默认的 urllib3 连接是通过 PoolManager 来处理的。

开启 debug level 的功能有点缺失,不过现在有一个很不错的 logger 使用方法。

https://urllib3.readthedocs.io/en/stable/user-guide.html#logging

日志级别的值从低到高分别是:

  • DEBUG
  • INFO
  • WARNING
  • ERROR
  • CRITICAL

下面这行代码可以让你开始把调试信息输出到标准输出(stdout):

import logging
logging.basicConfig(format='%(asctime)s - %(message)s', level=logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.DEBUG)

这样你会得到类似这样的输出:

2023-02-01 21:02:24,221 - Resetting dropped connection: localhost
2023-02-01 21:02:24,227 - http://localhost:9000 "GET /web/path HTTP/1.1" 200 100
3

对于那些最近看到这个问题的人(大约从2016年5月开始),虽然之前的答案在某个时候可能是正确的,但从Python 3.5.2版本开始,http.client.HTTPConnection.debuglevel这个设置完全被忽略了,取而代之的是urllib.request.HTTPHandler的构造函数参数debuglevel

这是因为这个改动,它将http.client.HTTPConnection.debuglevel的值设置为urllib.request.HTTPHandler构造函数参数debuglevel中所设置的值,具体在这一行

有一个拉取请求已经被提出以修复这个问题,但在此之前,你可以通过修改HTTPHandlerHTTPSHandler__init__方法来让它们尊重全局值,方法如下:

https_old_init = urllib.request.HTTPSHandler.__init__

def https_new_init(self, debuglevel=None, context=None, check_hostname=None):
    debuglevel = debuglevel if debuglevel is not None else http.client.HTTPSConnection.debuglevel
    https_old_init(self, debuglevel, context, check_hostname)

urllib.request.HTTPSHandler.__init__ = https_new_init

http_old_init = urllib.request.HTTPHandler.__init__

def http_new_init(self, debuglevel=None):
    debuglevel = debuglevel if debuglevel is not None else http.client.HTTPSConnection.debuglevel
    http_old_init(self, debuglevel)

urllib.request.HTTPHandler.__init__ = http_new_init

注意:我不建议将HTTPHandler中的debuglevel设置为方法参数的默认值,因为方法参数的默认值是在函数定义时就被计算的,而对于HTTPHandler的构造函数来说,这个时间点是模块urllib.request被导入的时候。

21

你第一次说的没错。你只需要在文件的开头加上一行 http.client.HTTPConnection.debuglevel = 1 就可以在整个应用程序中开启HTTP调试功能。urllib.request 还是会使用 http.client

似乎还有一种方法可以为单个处理器设置调试级别(通过创建 urllib.request.HTTPHandler(debuglevel=1) 并用它来构建一个打开器),但在我安装的Python3(3.0b3)中,这个功能实际上并没有实现。我想在更新的版本中这个问题可能已经解决了!

撰写回答