windows环境下的Python HTTP请求模块

windows环境下的Python HTTP请求模块

网络上关于Python的HTTP请求大部分都是利用了urllib,httplib,pycurl,但是经过我试用之后,都没有对cookie以及ssl良好的支持,所以本模块主要使用了wininet API来发送HTTP请求,经过测试之后,wininet库很好的封装了ssl,cookie的支持,因此将wininet库在Python中的调用方式公开。

因为wininet是windows对Internet的封装,所以只支持windows系统。

在Linux下,我们可以选择curl库来执行http请求。 PS : chrome的网络请求就是使用了curl。

Python中对curl的封装有pycurl,但是pycurl的作者封装的curl是不带ssl版本,所以无法发起https请求,在这里就不提了,有兴趣的朋友可以访问pycurl的下载地址来试用。

上代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#coding:utf-8
import ctypes
from urlparse  import urlparse
import threading
 
INTERNET_OPEN_TYPE_PRECONFIG  = 0
INTERNET_OPEN_TYPE_PROXY  = 3
INTERNET_OPEN_TYPE_DIRECT  = 1
INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY  = 4
 
INTERNET_SERVICE_HTTP  = 3
INTERNET_FLAG_RELOAD  = 2147483648
HTTP_ADDREQ_FLAG_REPLACE  = 2147483648
HTTP_ADDREQ_FLAG_ADD = 536870912
INTERNET_OPEN_TYPE_DIRECT  = 1
INTERNET_FLAG_SECURE  = 8388608
HTTP_QUERY_STATUS_CODE  = 19
 
wininet  = ctypes.windll.LoadLibrary( 'wininet.dll' )
 
class wininetHttp():
 
     def httpRequest( self ,url,method = "GET" ,proxy = " ",username=" ",password=" ",headers=" ",data=" ",timeout = 20 ):
         """
         发出一个HTTP请求
         参数:
         url: 完整网址
         method: 请求方法,可以是GET或POST
         proxy: 代理地址
         username: 用户名
         password: 密码
         headers: 协议头
         data: 提交数据
         timeout: 请求超时值
         返回值:
         元组(header,html)
         """
         requestThread  = _httprequest(url,method,proxy,username,password,headers,data)
         requestThread.daemon  = True #线程随主线程一起退出
         requestThread.start()
         requestThread.join(timeout)
         ret  = requestThread.getResponse()
         return ret
 
class _httprequest(threading.Thread):
 
     response  = ( 0 ,'')
 
     def __init__( self ,url,method,proxy,username,password,headers,data):
         threading.Thread.__init__( self )
         self .url  = url
         self .url_info  = urlparse(url)
         self .method  = method
         self .proxy  = proxy
         self .username  = username
         self .password  = password
         self .headers  = headers
         self .data  = data
 
     def run( self ):
         dwAccessType  = self .proxy  and INTERNET_OPEN_TYPE_PROXY  or INTERNET_OPEN_TYPE_DIRECT
         lpszProxyName  = self .proxy  and 'http=' + self .proxy  or None
         lpszAgent  = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36'
         hOpen  = wininet.InternetOpenA(lpszAgent,dwAccessType,lpszProxyName, None , 0 )
         if not hOpen:
             return
         nServerPort  = ( self .url_info.scheme  = = 'https' and 443 or 80
         hConn  = wininet.InternetConnectA(hOpen, self .url_info.netloc.lower(),nServerPort, self .username, self .password,INTERNET_SERVICE_HTTP, 0 , 0 )
         if not hConn:
             wininet.InternetCloseHandle(hOpen)
             return
         dwFlags  = ( self .url_info.scheme  = = 'https' and INTERNET_FLAG_SECURE  or INTERNET_FLAG_RELOAD
         hRequest  = wininet.HttpOpenRequestA(hConn, self .method, self .url_info.path, 'HTTP/1.1' , None , 0 ,dwFlags, 0 )
         if not hRequest:
             wininet.InternetCloseHandle(hConn)
             wininet.InternetCloseHandle(hOpen)
             return
         if not 'Accept: ' in self .headers:
             self .headers  + = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n'
         if not 'Referer: ' in self .headers:
             self .headers  + = 'Referer: %s\r\n' % self .url
         if not 'Accept-Language: ' in self .headers:
             self .headers  + = 'Accept-Language: zh-CN,zh;q=0.8\r\n'
         if self .method.upper()  = = 'GET' :
             wininet.HttpSendRequestA(hRequest,  self .headers, len ( self .headers), None 0 )
         elif self .method.upper()  = = 'POST' :
             if self .data ! = '':
                 if not 'Content-Type: ' in self .headers:
                     self .headers  = self .headers  + "Content-Type: application/x-www-form-urlencoded\r\n"
                 self .headers  = self .headers  + "Content-Length: %s\r\n" % len ( self .data)
             wininet.HttpSendRequestA(hRequest,  self .headers, len ( self .headers), self .data, len ( self .data))
         else :
             wininet.InternetCloseHandle(hRequest)
             wininet.InternetCloseHandle(hConn)
             wininet.InternetCloseHandle(hOpen)
             return
         data_buf  = (ctypes.c_char  * 2048 )()
         ret_data  = ''
         = ctypes.c_int( 1 )
         while x.value ! = 0 :
             wininet.InternetReadFile(hRequest,data_buf, 2048 ,ctypes.byref(x))
             buf  = (ctypes.c_char  * x.value)()
             ctypes.memmove(buf,data_buf,x.value)
             ret_data  + = buf[:x.value]
 
         head_buf  = ctypes.create_string_buffer( 2048 )
         buf_size  = ctypes.c_int( 2048 )
         wininet.HttpQueryInfoA(hRequest, 22 ,head_buf,ctypes.byref(buf_size), 0 )
 
         wininet.InternetCloseHandle(hRequest)
         wininet.InternetCloseHandle(hConn)
         wininet.InternetCloseHandle(hOpen)
 
         self .response  = (head_buf.value,ret_data)
         return
 
     def getResponse( self ):
         return self .response

因为wininet无法设置超时,所以模块中的超时是利用Python threading模块来控制。

学Python才几天,如果代码中有写的不对的地方或者是有更好的解决方案,欢迎联系我一起讨论~

代码自由使用,转载需注明原出处

其实Python的学习,只要多看官方doc就可以了。(●´∀`●)

 

你可能感兴趣的:(windows环境下的Python HTTP请求模块)