在Python中测试HTTPS代理

7 投票
4 回答
10903 浏览
提问于 2025-04-19 17:49

我管理着很多HTTPS代理(就是那些有自己SSL连接的代理)。我正在用Python开发一个诊断工具,目的是通过每个代理尝试连接到一个网页,如果有哪个代理连接不上,就给我发个邮件。

我打算用urllib来通过每个代理连接,并返回一个应该显示“成功”的页面,代码如下。

def fetch(url):
    connection = urllib.urlopen(
    url,
    proxies={'http':"https://"+server+':443'}
    )
    return connection.read()


print fetch(testURL)

这个方法能完美地获取我想要的页面,但问题是,即使代理服务器的信息不正确或者代理服务器不活动,它仍然会获取到我想要的页面。所以要么它根本没有使用代理服务器,要么就是尝试使用了代理,但在失败时却没有通过代理连接。

我该怎么解决这个问题呢?

补充:似乎没有人知道怎么做。我打算开始看看其他语言的库,看看它们是否能更好地处理这个问题。有没有人知道用其他语言,比如Go,是否更容易?

补充:我刚在下面的评论中写了这个,但我觉得可能存在误解。“这个代理有自己的SSL连接。所以如果我访问google.com,我首先要和foo.com进行密钥交换,然后再和目标地址bar.com或baz.com进行交换。目标地址不一定要是https,代理是https。”

4 个回答

0

你觉得使用超时设置怎么样?如果代理在30秒内没有成功连接,就应该记录为未连接。

def fetch(url, server):
 proxy_handler = urllib2.ProxyHandler({'http':'https://'+server+':443'})
 opener = urllib2.build_opener(proxy_handler, urllib2.HTTPHandler(debuglevel=0))
 urllib2.install_opener(opener)

 try:
  response = opener.open( url, timeout = 30)
  return response.read()
 except:
  print "Can't connect with proxy %s" % (server)

print fetch(url,serverIp)

你可以把 debuglevel = 1 改一下,这样可以查看连接的详细信息。

我用这个来处理全球代理,结合我的网络连接,30秒是我判断是否连接成功的最大超时时间。在我的测试中,如果连接时间超过30秒,那基本上就是失败了。

1

从代码来看,urllib似乎不支持这个功能,而且urllib2是否支持也不太清楚。不过,我们可以考虑直接使用curl(或者叫curllib),这通常是处理HTTP请求的首选工具(虽然它比较复杂,所以才有了urllib等工具)。

看看命令行工具curl,它看起来很有前途:

   -x, --proxy <[protocol://][user:password@]proxyhost[:port]>
          Use the specified HTTP proxy. If the port number is not specified, it is assumed at port 1080.

          This  option  overrides  existing environment variables that set the proxy to use. If there's an environment variable setting a proxy, you can set
          proxy to "" to override it.

          All operations that are performed over an HTTP proxy will transparently be converted to HTTP. It means that certain protocol  specific  operations
          might not be available. This is not the case if you can tunnel through the proxy, as one with the -p, --proxytunnel option.

          User  and  password that might be provided in the proxy string are URL decoded by curl. This allows you to pass in special characters such as @ by
          using %40 or pass in a colon with %3a.

          The proxy host can be specified the exact same way as the proxy environment variables, including the protocol prefix (http://)  and  the  embedded
          user + password.

          From  7.21.7,  the  proxy  string  may  be  specified with a protocol:// prefix to specify alternative proxy protocols. Use socks4://, socks4a://,
          socks5:// or socks5h:// to request the specific SOCKS version to be used. No protocol specified, http:// and all others will be  treated  as  HTTP
          proxies.

          If this option is used several times, the last one will be used.
1

我想这段代码可能不支持https请求,对吗?如果是这样的话,上面的代码只为http定义了一个代理。你可以试着为https添加一个代理:

proxies={'https':"https://"+server+':443'}

另外一个选择是使用requests这个Python模块,而不是urllib。你可以看看这个链接:http://docs.python-requests.org/en/latest/user/advanced/#proxies

4

大多数人把 HTTPS 代理理解为能够处理 CONNECT 请求的代理。我这个例子是直接创建 SSL 连接。

try:
    import http.client as httplib # for python 3.2+
except ImportError:
    import httplib # for python 2.7


con = httplib.HTTPSConnection('proxy', 443) # create proxy connection
# download http://example.com/ through proxy
con.putrequest('GET', 'http://example.com/', skip_host=True)
con.putheader('Host', 'example.com')
con.endheaders()
res = con.getresponse()
print(res.read())

如果你的代理是反向代理,那么要把

con.putrequest('GET', 'http://example.com/', skip_host=True)

改成

con.putrequest('GET', '/', skip_host=True)`

撰写回答