Qual é a maneira correta de usar win32inet.WinHttpGetProxyForUrl
Pergunta
Eu estou tentando usar um recurso da biblioteca Microsoft WinHttp que foi exposta pelos desenvolvedores do win32com. Infelizmente a maioria da biblioteca não parece ser documentado e não há exemplo da maneira correta de usar o win32inet apresenta através da biblioteca win32com.
Isto é o que eu tenho até agora:
import win32inet
hinternet = win32inet.InternetOpen("foo 1.0", 0, "", "", 0)
# Does not work!!!
proxy = win32inet.WinHttpGetProxyForUrl( hinternet, u"http://www.foo.com", 0 )
Como você pode ver, tudo o que eu estou tentando fazer é usar o recurso win32inet para descobrir qual o proxy é o mais adequado para uso por um determinado URL, int seu caso foo.com.
Você pode me ajudar corrigir a sintaxe da última linha? MSN tem algum documentação bom para a função de ser envolvido mas os argumentos não parecem mapear o às da biblioteca python perfeitamente.
A versão fixa desse script deve:
-
Ser capaz de olhar-se que proxy para uso para qualquer URL.
-
Deve sempre exatamente o Internet Explorer faria (ou seja, usar o mesmo proxy)
-
Ele deve ser válido em qualquer válido set-up Windows XP. Isso significa que ele deve trabalhar com um proxy configurado explicitamente e também nenhum proxy em tudo.
-
Ele só precisa trabalhar em 32 bits do Windows XP com Python 2.4.4. Ele pode usar qualquer versão oficial lançada do win32com.
Eu estou usando Python2.4.4 com win32com no Windows XP.
Atualização de 0:
OU ... você pode me dar uma implementação alternativa em ctypes? Contanto que eu posso fazê-lo funcionar Eu estou feliz!
Solução
Aqui está o código que cria sessão HINTERNET e usos que para obter detalhes de proxy, usando ctypes para acessar diretamente winhttp DLL. Ele funciona sem qualquer erro, mas não tenho set proxy na minha máquina, você pode ter de ajustar algumas constantes para obtê-lo direito. Vá através dos links do MSDN em código, de onde eu vi a 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
Outras dicas
A menos que haja uma forte razão para usar win32inet
(que é confuso nesta área devido a limitações de SWIG
), eu recomendo que você use ctypes
vez.
Pelo menos com Python 2.7.6
e Pywin 218
no Windows XP x86 e Windows 8 x64, ele funciona:
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
Vale a pena mencionar que o exemplo usa o WINHTTP_AUTOPROXY_CONFIG_URL opção autoproxy a fim de passar em uma URL explícita. Você pode usar outras opções, por exemplo, se você quiser detectar automaticamente usando DNS ou DHCP você pode fazer:
autoproxy_options = (1, 1|2, u"", None, 0, 1)
Você pode encontrar outras opções da ligação mostrou acima (no código)