11.1 作为客户端与HTTP服务交互
怎么通过HTTP协议以客户端的方式访问多种服务?例如,下载数据或者与基于REST的API进行交互。
对于真的很简单HTTP客户端代码,用内置的 urllib
模块通常就足够了。
urllib.request.
urlopen
(url,data = None,[ timeout,] *,cafile = None,capath = None,cadefault = False,context = None )
打开URL url,它可以是字符串或 Request
对象。数据必须是一个指定要发送到服务器的其他数据的对象。该函数总是返回一个可以用作上下文管理器的对象。
urllib.parse.
urlencode
(query,doseq = False,safe ='',encoding = None,errors = None,quote_via = quote_plus ))
将可能包含str
或bytes
对象的映射对象或两个元素的元组序列转换为百分比编码的ASCII文本字符串。如果结果字符串将用作函数的POST操作的数据,urlopen()
则应将其编码为字节,否则将导致 TypeError
。
urllib.request.
Request
(url,data = None,headers = {},origin_req_host = None,unverifiable = False,method = None )
此类是URL请求的抽象。
url 应该是包含有效URL的字符串。data 必须是一个指定要发送到服务器的其他数据的对象。headers 应该是一个字典,并且将被视为如同 add_header()
以每个键和值作为参数调用时一样。这通常用于“欺骗” User-Agent
标头值,该标头值由浏览器用来标识自己–一些HTTP服务器仅允许来自普通浏览器的请求而不是脚本。
https://docs.python.org/3/library/urllib.request.html
发送一个简单的HTTP GET请求到远程的服务上,示例:
>>> from urllib import request,parse
>>> url = 'http://httpbin.org/get'
>>> parms = {'name1' : 'value1','name2' : 'value2'}
>>> querystring = parse.urlencode(parms)
>>> u = request.urlopen(url+'?'+querystring)
>>> u.read()
b'{\n "args": {\n "name1": "value1", \n "name2": "value2"\n }, \n "headers": {\n "Accept-Encoding": "identity", \n "Host": "httpbin.org", \n "User-Agent": "Python-urllib/3.7"\n }, \n "origin": "218.28.192.28, 218.28.192.28", \n "url": "https://httpbin.org/get?name1=value1&name2=value2"\n}\n'
注:http://httpbin.org 这个站点会接收发出的请求,然后以JSON的形式将相应信息回传回来。
使用POST方法在请求主体中发送查询参数,可以将参数编码后作为可选参数提供给 urlopen()
函数,示例:
>>> posturl = 'http://httpbin.org/post'
>>> parms = {'name1' : 'value1','name2' : 'value2'}
>>> querystring = parse.urlencode(parms)
>>> u = request.urlopen(posturl,querystring.encode ('ascii'))
>>> u.read()
b'{\n "args": {}, \n "data": "", \n "files": {}, \n "form": {\n "name1": "value1", \n "name2": "value2"\n }, \n "headers": {\n "Accept-Encoding": "identity", \n "Content-Length": "25", \n "Content-Type": "application/x-www-form-urlencoded", \n "Host": "httpbin.org", \n "User-Agent": "Python-urllib/3.7"\n }, \n "json": null, \n "origin": "218.28.192.28, 218.28.192.28", \n "url": "https://httpbin.org/post"\n}\n'
在发出的请求中提供一些自定义的HTTP headers ,示例:
>>> headers = {'User-agent':'none/ofyoubusiness','spam':'Eggs'}
>>> req = request.Request(posturl,querystring.encode('ascii'),headers=headers)
>>> u = request.urlopen(req)
>>> u.read()
b'{\n "args": {}, \n "data": "", \n "files": {}, \n "form": {\n "name1": "value1", \n "name2": "value2"\n }, \n "headers": {\n "Accept-Encoding": "identity", \n "Content-Length": "25", \n "Content-Type": "application/x-www-form-urlencoded", \n "Host": "httpbin.org", \n "Spam": "Eggs", \n "User-Agent": "none/ofyoubusiness"\n }, \n "json": null, \n "origin": "218.28.192.28, 218.28.192.28", \n "url": "https://httpbin.org/post"\n}\n'
如果要做的不仅仅只是简单的GET或POST请求,那 urllib.request 就不适用了。
这时候需要第三方模块 requests
,使用 requests 重新实现上面的示例:
>>> import requests
>>> url = 'http://httpbin.org/post'
>>> headers = {'User-agent' : 'none/ofyourbusiness','Spam' : 'Eggs'}
>>> parms = {'name1' : 'value1','name2' : 'value2'}
>>> resp = requests.post(url,data=parms,headers=headers)
>>> resp.text
'{\n "args": {}, \n "data": "", \n "files": {}, \n "form": {\n "name1": "value1", \n "name2": "value2"\n }, \n "headers": {\n "Accept": "*/*", \n "Accept-Encoding": "gzip, deflate", \n "Content-Length": "25", \n "Content-Type": "application/x-www-form-urlencoded", \n "Host": "httpbin.org", \n "Spam": "Eggs", \n "User-Agent": "none/ofyourbusiness"\n }, \n "json": null, \n "origin": "218.28.192.28, 218.28.192.28", \n "url": "https://httpbin.org/post"\n}\n'
>>> resp.content
b'{\n "args": {}, \n "data": "", \n "files": {}, \n "form": {\n "name1": "value1", \n "name2": "value2"\n }, \n "headers": {\n "Accept": "*/*", \n "Accept-Encoding": "gzip, deflate", \n "Content-Length": "25", \n "Content-Type": "application/x-www-form-urlencoded", \n "Host": "httpbin.org", \n "Spam": "Eggs", \n "User-Agent": "none/ofyourbusiness"\n }, \n "json": null, \n "origin": "218.28.192.28, 218.28.192.28", \n "url": "https://httpbin.org/post"\n}\n'
>>> resp.json
<bound method Response.json of <Response [200]>>
能以多种方式从请求中返回响应结果的内容,从上面的代码来看, resp.text
是以Unicode解码的响应文本; resp.content
得到原始的二进制数据;resp.json
得到JSON格式的响应内容。
利用requests通过基本认证登录Pypi:
>>> resp = requests.get('http://pypi.python.org/pypi?:action=login',auth=('user','password'))
利用requests将HTTP cookies从一个请求传递到另一个:
>>> resp1 = requests.get(url)
>>> resp2 = requests.get(url,cookies=resp1.cookies)
用requests上传内容:
>>> import requests
>>> url = 'http://httpbin.org/post'
>>> file = r'C:\Users\Administrator\Desktop\c.csv'
>>> files = {'file':(file,open(file,'rb'))}
>>> r = requests.post(url,files=files)
>>> r
<Response [200]>
11.2 创建TCP服务器
怎么实现一个服务器,通过TCP协议和客户端通信?
socketserver
可以让我们很容易的创建简单的TCP服务器。
https://python3-cookbook.readthedocs.io/zh_CN/latest/c11/p02_creating_tcp_server.html
11.3 创建UDP服务器
跟TCP一样,UDP服务器也可以通过使用 socketserver
库很容易的被创建。
11.4 通过CIDR地址生成对应的IP地址集
使用 ipaddress
模块很容易的实现这样的计算:
>>> net = ipaddress.ip_network('123.45.67.64/27')
>>> for i in net:
print(i)
123.45.67.64
123.45.67.65
123.45.67.66
...
11.5 创建一个简单的REST接口
11.13