设为首页 收藏本站
查看: 1906|回复: 0

[经验分享] python httplib2

[复制链接]

尚未签到

发表于 2015-4-26 11:18:32 | 显示全部楼层 |阅读模式
  httplib2使用socksipy实现代理支持,示例代码如下:



import httplib2
import socks
client = httplib2.Http(proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP, "190.253.95.219", 8080))
  
  很多代理连接死循环,一些代理连接失败,而用pycurl测试同样的代理无问题。
  
  python version:2.7
  httplib2 version:0.7.2
  socks verson:1.00
  
  socks.py模块介绍:http://socksipy.sourceforge.net/readme.txt,相关部分如下:



PROXY COMPATIBILITY
SocksiPy is compatible with three different types of proxies:
1. SOCKS Version 4 (Socks4), including the Socks4a extension.
2. SOCKS Version 5 (Socks5).
3. HTTP Proxies which support tunneling using the CONNECT method.
  
  那些httplib2失败的代理是因为socksipy仅支持使用CONNECT方法的代理服务器,CONNECT方法是HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器,即支持HTTPS。与HTTP的URL由“http://”起始且默认使用端口80不同,HTTPS的URL由“https://”起始且默认使用端口443。
  
  修改socks.py模块相关源代码,/usr/lib/python2.6/dist-packages/socks.py,添加一个"PROXY_TYPE_HTTP_NO_TUNNEL"类型,当失败时再跳到"PROXY_TYPE_HTTP"类型。
  
  补丁参考:http://code.google.com/p/xbmc-iplayerv2/source/browse/trunk/plugin.video.iplayer/lib/httplib2/socks.py,测试可用,代码如下:


DSC0000.gif DSC0001.gif View Code


  1 """SocksiPy - Python SOCKS module.
  2 Version 1.00
  3
  4 Copyright 2006 Dan-Haim. All rights reserved.
  5
  6 Redistribution and use in source and binary forms, with or without modification,
  7 are permitted provided that the following conditions are met:
  8 1. Redistributions of source code must retain the above copyright notice, this
  9    list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13 3. Neither the name of Dan Haim nor the names of his contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16   
17 THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED
18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA
23 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
26
27
28 This module provides a standard socket-like interface for Python
29 for tunneling connections through SOCKS proxies.
30
31 """
32
33 """
34
35 Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
36 for use in PyLoris (http://pyloris.sourceforge.net/)
37
38 Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
39 mainly to merge bug fixes found in Sourceforge
40
41 """
42
43 import socket
44 import struct
45 import sys
46 import base64
47
48 PROXY_TYPE_SOCKS4 = 1
49 PROXY_TYPE_SOCKS5 = 2
50 PROXY_TYPE_HTTP = 3
51 PROXY_TYPE_HTTP_NO_TUNNEL = 4
52
53 _defaultproxy = None
54 _orgsocket = socket.socket
55
56 class ProxyError(Exception): pass
57 class GeneralProxyError(ProxyError): pass
58 class Socks5AuthError(ProxyError): pass
59 class Socks5Error(ProxyError): pass
60 class Socks4Error(ProxyError): pass
61 class HTTPError(ProxyError): pass
62
63 _generalerrors = ("success",
64     "invalid data",
65     "not connected",
66     "not available",
67     "bad proxy type",
68     "bad input")
69
70 _socks5errors = ("succeeded",
71     "general SOCKS server failure",
72     "connection not allowed by ruleset",
73     "Network unreachable",
74     "Host unreachable",
75     "Connection refused",
76     "TTL expired",
77     "Command not supported",
78     "Address type not supported",
79     "Unknown error")
80
81 _socks5autherrors = ("succeeded",
82     "authentication is required",
83     "all offered authentication methods were rejected",
84     "unknown username or invalid password",
85     "unknown error")
86
87 _socks4errors = ("request granted",
88     "request rejected or failed",
89     "request rejected because SOCKS server cannot connect to identd on the client",
90     "request rejected because the client program and identd report different user-ids",
91     "unknown error")
92
93 def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
94     """setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
95     Sets a default proxy which all further socksocket objects will use,
96     unless explicitly changed.
97     """
98     global _defaultproxy
99     _defaultproxy = (proxytype, addr, port, rdns, username, password)
100
101 def wrapmodule(module):
102     """wrapmodule(module)
103     Attempts to replace a module's socket library with a SOCKS socket. Must set
104     a default proxy using setdefaultproxy(...) first.
105     This will only work on modules that import socket directly into the namespace;
106     most of the Python Standard Library falls into this category.
107     """
108     if _defaultproxy != None:
109         module.socket.socket = socksocket
110     else:
111         raise GeneralProxyError((4, "no proxy specified"))
112
113 class socksocket(socket.socket):
114     """socksocket([family[, type[, proto]]]) -> socket object
115     Open a SOCKS enabled socket. The parameters are the same as
116     those of the standard socket init. In order for SOCKS to work,
117     you must specify family=AF_INET, type=SOCK_STREAM and proto=0.
118     """
119
120     def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
121         _orgsocket.__init__(self, family, type, proto, _sock)
122         if _defaultproxy != None:
123             self.__proxy = _defaultproxy
124         else:
125             self.__proxy = (None, None, None, None, None, None)
126         self.__proxysockname = None
127         self.__proxypeername = None
128
129         self.__httptunnel = True
130
131     def __recvall(self, count):
132         """__recvall(count) -> data
133         Receive EXACTLY the number of bytes requested from the socket.
134         Blocks until the required number of bytes have been received.
135         """
136         data = self.recv(count)
137         while len(data) < count:
138             d = self.recv(count-len(data))
139             if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
140             data = data + d
141         return data
142
143     def sendall(self, content, *args):
144         """ override socket.socket.sendall method to rewrite the header
145         for non-tunneling proxies if needed
146         """
147         if not self.__httptunnel:
148             content = self.__rewriteproxy(content)
149
150         return super(socksocket, self).sendall(content, *args)
151
152     def __rewriteproxy(self, header):
153         """ rewrite HTTP request headers to support non-tunneling proxies
154         (i.e. thos which do not support the CONNECT method).
155         This only works for HTTP (not HTTPS) since HTTPS requires tunneling.
156         """
157         host, endpt = None, None
158         hdrs = header.split("\r\n")
159         for hdr in hdrs:
160             if hdr.lower().startswith("host:"):
161                 host = hdr
162             elif hdr.lower().startswith("get") or hdr.lower().startswith("post"):
163                 endpt = hdr
164         if host and endpt:
165             hdrs.remove(host)
166             hdrs.remove(endpt)
167             host = host.split(" ")[1]
168             endpt = endpt.split(" ")
169             if (self.__proxy[4] != None and self.__proxy[5] != None):
170                 hdrs.insert(0, self.__getauthheader())
171             hdrs.insert(0, "Host: %s" % host)
172             hdrs.insert(0, "%s http://%s%s %s" % (endpt[0], host, endpt[1], endpt[2]))
173
174         return "\r\n".join(hdrs)
175
176     def __getauthheader(self):
177         auth = self.__proxy[4] + ":" + self.__proxy[5]
178         return "Proxy-Authorization: Basic " + base64.b64encode(auth)
179
180     def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
181         """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
182         Sets the proxy to be used.
183         proxytype -    The type of the proxy to be used. Three types
184                 are supported: PROXY_TYPE_SOCKS4 (including socks4a),
185                 PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP
186         addr -        The address of the server (IP or DNS).
187         port -        The port of the server. Defaults to 1080 for SOCKS
188                 servers and 8080 for HTTP proxy servers.
189         rdns -        Should DNS queries be preformed on the remote side
190                 (rather than the local side). The default is True.
191                 Note: This has no effect with SOCKS4 servers.
192         username -    Username to authenticate with to the server.
193                 The default is no authentication.
194         password -    Password to authenticate with to the server.
195                 Only relevant when username is also provided.
196         """
197         self.__proxy = (proxytype, addr, port, rdns, username, password)
198
199     def __negotiatesocks5(self, destaddr, destport):
200         """__negotiatesocks5(self,destaddr,destport)
201         Negotiates a connection through a SOCKS5 server.
202         """
203         # First we'll send the authentication packages we support.
204         if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
205             # The username/password details were supplied to the
206             # setproxy method so we support the USERNAME/PASSWORD
207             # authentication (in addition to the standard none).
208             self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
209         else:
210             # No username/password were entered, therefore we
211             # only support connections with no authentication.
212             self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00))
213         # We'll receive the server's response to determine which
214         # method was selected
215         chosenauth = self.__recvall(2)
216         if chosenauth[0:1] != chr(0x05).encode():
217             self.close()
218             raise GeneralProxyError((1, _generalerrors[1]))
219         # Check the chosen authentication method
220         if chosenauth[1:2] == chr(0x00).encode():
221             # No authentication is required
222             pass
223         elif chosenauth[1:2] == chr(0x02).encode():
224             # Okay, we need to perform a basic username/password
225             # authentication.
226             self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
227             authstat = self.__recvall(2)
228             if authstat[0:1] != chr(0x01).encode():
229                 # Bad response
230                 self.close()
231                 raise GeneralProxyError((1, _generalerrors[1]))
232             if authstat[1:2] != chr(0x00).encode():
233                 # Authentication failed
234                 self.close()
235                 raise Socks5AuthError((3, _socks5autherrors[3]))
236             # Authentication succeeded
237         else:
238             # Reaching here is always bad
239             self.close()
240             if chosenauth[1] == chr(0xFF).encode():
241                 raise Socks5AuthError((2, _socks5autherrors[2]))
242             else:
243                 raise GeneralProxyError((1, _generalerrors[1]))
244         # Now we can request the actual connection
245         req = struct.pack('BBB', 0x05, 0x01, 0x00)
246         # If the given destination address is an IP address, we'll
247         # use the IPv4 address request even if remote resolving was specified.
248         try:
249             ipaddr = socket.inet_aton(destaddr)
250             req = req + chr(0x01).encode() + ipaddr
251         except socket.error:
252             # Well it's not an IP number,  so it's probably a DNS name.
253             if self.__proxy[3]:
254                 # Resolve remotely
255                 ipaddr = None
256                 req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr
257             else:
258                 # Resolve locally
259                 ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
260                 req = req + chr(0x01).encode() + ipaddr
261         req = req + struct.pack(">H", destport)
262         self.sendall(req)
263         # Get the response
264         resp = self.__recvall(4)
265         if resp[0:1] != chr(0x05).encode():
266             self.close()
267             raise GeneralProxyError((1, _generalerrors[1]))
268         elif resp[1:2] != chr(0x00).encode():
269             # Connection failed
270             self.close()
271             if ord(resp[1:2])

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-60839-1-1.html 上篇帖子: 用python 控制gpio 下篇帖子: [转]自动化测试中Python与C/C++的混合使用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表