现在的位置: 首页 > 综合 > 正文

windows环境下的Python HTTP请求模块

2017年11月04日 ⁄ 综合 ⁄ 共 5075字 ⁄ 字号 评论关闭

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),None0)
        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就可以了。(●´∀`●)

 

抱歉!评论已关闭.