win32inet.WinHttpGetProxyForUrl的正确用法是什么
我正在尝试使用微软的WinHttp库中的一个功能,这个功能是Win32com的开发者提供的。不过,遗憾的是,这个库的大部分内容似乎没有文档说明,而且也没有关于如何通过win32com库正确使用win32inet功能的例子。
这是我目前的代码:
import win32inet
hinternet = win32inet.InternetOpen("foo 1.0", 0, "", "", 0)
# Does not work!!!
proxy = win32inet.WinHttpGetProxyForUrl( hinternet, u"http://www.foo.com", 0 )
正如你所看到的,我只是想用win32inet功能来查找哪个代理适合用于特定的URL,在这个例子中是foo.com。
你能帮我修正最后一行的语法吗?MSN有一些关于这个函数的不错文档,但是参数似乎和Python库的参数不完全对应。
这个脚本的修正版本应该:
能够查找任何给定URL应该使用哪个代理。
它应该始终和Internet Explorer的行为一致(也就是说,使用相同的代理)。
它应该在任何有效的Windows XP设置上都能运行。这意味着它应该能在明确配置的代理和没有代理的情况下都能工作。
它只需要在Windows XP 32位系统上与Python 2.4.4兼容。可以使用任何官方发布的win32com版本。
我在Windows XP上使用Python 2.4.4和Win32Com。
更新 0:
或者……你能给我一个用cTypes实现的替代方案吗?只要我能让它工作,我就满意了!
3 个回答
在Windows XP x86和Windows 8 x64上,使用Python 2.7.6
和Pywin 218
时,这个方法是有效的:
import win32inet
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa384098(v=vs.85).aspx
hinternet = win32inet.WinHttpOpen("foo", 0, "", "", 0)
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa384123(v=vs.85).aspx
autoproxy_options = (2, 0, u"http://your-proxy-script-path", None, 0, 1)
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa384097(v=vs.85).aspx
proxy = win32inet.WinHttpGetProxyForUrl(hinternet, u"http://www.google.com",
autoproxy_options)
print proxy
值得一提的是,这个例子使用了自动代理选项WINHTTP_AUTOPROXY_CONFIG_URL,目的是为了传入一个明确的URL。你也可以使用其他选项,比如如果你想通过DNS或DHCP自动检测,可以这样做:
autoproxy_options = (1, 1|2, u"", None, 0, 1)
你可以在上面代码中提到的链接找到其他选项。
除非有很强的理由要使用 win32inet
(因为它在这方面比较麻烦,主要是受限于 SWIG
的一些问题),否则我建议你使用 ctypes
。
这里的代码是用来创建一个 HINTERNET 会话,并利用这个会话来获取代理的详细信息。它使用 ctypes 直接访问 winhttp 的 DLL 文件。代码运行没有错误,但我机器上没有设置代理,所以你可能需要调整一些常量才能让它正常工作。可以查看代码中的 msdn 链接,那是我获取这个 API 信息的地方。
import ctypes
import ctypes.wintypes
winHttp = ctypes.windll.LoadLibrary("Winhttp.dll")
# http://msdn.microsoft.com/en-us/library/aa384098(VS.85).aspx
# first get a handle to HTTP session
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY=0
WINHTTP_NO_PROXY_NAME=WINHTTP_NO_PROXY_BYPASS=0
WINHTTP_FLAG_ASYNC=0x10000000
HINTERNET = winHttp.WinHttpOpen("PyWin32", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC)
print HINTERNET
# now get proxy using HTTP session
# http://msdn.microsoft.com/en-us/library/aa384097(VS.85).aspx
"""
BOOL WinHttpGetProxyForUrl(
__in HINTERNET hSession,
__in LPCWSTR lpcwszUrl,
__in WINHTTP_AUTOPROXY_OPTIONS *pAutoProxyOptions,
__out WINHTTP_PROXY_INFO *pProxyInfo
);
"""
# create C structure for WINHTTP_AUTOPROXY_OPTIONS
#http://msdn.microsoft.com/en-us/library/aa384123(VS.85).aspx
"""
typedef struct {
DWORD dwFlags;
DWORD dwAutoDetectFlags;
LPCWSTR lpszAutoConfigUrl;
LPVOID lpvReserved;
DWORD dwReserved;
BOOL fAutoLogonIfChallenged;
} WINHTTP_AUTOPROXY_OPTIONS;
"""
class WINHTTP_AUTOPROXY_OPTIONS(ctypes.Structure):
_fields_ = [("dwFlags", ctypes.wintypes.DWORD),
("dwAutoDetectFlags", ctypes.wintypes.DWORD),
("lpszAutoConfigUrl", ctypes.wintypes.LPCWSTR),
("lpvReserved", ctypes.c_void_p ),
("dwReserved", ctypes.wintypes.DWORD),
("fAutoLogonIfChallenged",ctypes.wintypes.BOOL),]
WINHTTP_AUTOPROXY_AUTO_DETECT = 0x00000001;
WINHTTP_AUTO_DETECT_TYPE_DHCP = 0x00000001;
WINHTTP_AUTO_DETECT_TYPE_DNS_A = 0x00000002;
options = WINHTTP_AUTOPROXY_OPTIONS()
options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT
options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP|WINHTTP_AUTO_DETECT_TYPE_DNS_A
options.lpszAutoConfigUrl = 0
options.fAutoLogonIfChallenged = False
# create C structure for WINHTTP_AUTOPROXY_OPTIONS
# http://msdn.microsoft.com/en-us/library/aa383912(VS.85).aspx
"""
struct WINHTTP_PROXY_INFO {
DWORD dwAccessType;
LPWSTR lpszProxy;
LPWSTR lpszProxyBypass;
};
"""
class WINHTTP_PROXY_INFO(ctypes.Structure):
_fields_ = [("dwAccessType", ctypes.wintypes.DWORD),
("lpszProxy", ctypes.wintypes.LPCWSTR),
("lpszProxyBypass", ctypes.wintypes.LPCWSTR),]
info = WINHTTP_PROXY_INFO()
ret = winHttp.WinHttpGetProxyForUrl(HINTERNET, "http://www.google.com", ctypes.pointer(options), ctypes.pointer(info) )
print "proxy success?",ret
if not ret:
# some error lets see what is that?
import win32api
import win32con
errorCode = win32api.GetLastError()
print "win32 Error:",errorCode
s = ""
print win32api.FormatMessage(errorCode)
print info.dwAccessType, info.lpszProxy, info.lpszProxyBypass