Python互联网应用编程指南
1. ftplib模块
ftplib模块实现了FTP协议的客户端功能。虽然urllib包提供了更高级的接口,使得直接使用ftplib的情况较少,但如果需要对FTP连接的底层细节进行更多控制,该模块仍然很有用。使用该模块前,了解Internet RFC 959中描述的FTP协议细节会有所帮助。
-
建立FTP连接
:使用
FTP类创建FTP连接对象。
FTP([host [, user [, passwd [, acct [, timeout]]]]])
- `host`:指定主机名的字符串。
- `user`、`passwd`、`acct`:可选参数,分别指定用户名、密码和账户。
- `timeout`:超时时间(秒)。
-
FTP对象方法 :
| 方法 | 描述 |
| — | — |
|f.abort()| 尝试中止正在进行的文件传输 |
|f.close()| 关闭FTP连接 |
|f.connect(host [, port [, timeout]])| 打开到指定主机和端口的FTP连接 |
|f.cwd(pathname)| 更改服务器上的当前工作目录 |
|f.delete(filename)| 从服务器上删除文件 |
|f.dir([dirname [, ... [, callback]]])| 生成目录列表 |
|f.login([user, [passwd [, acct]]])| 使用指定的用户名、密码和账户登录服务器 |
|f.mkd(pathname)| 在服务器上创建新目录 |
|f.ntransfercmd(command [, rest])| 与transfercmd()类似,但返回一个元组(sock, size)|
|f.pwd()| 返回服务器上的当前工作目录 |
|f.quit()| 发送QUIT命令关闭FTP连接 |
|f.rename(oldname,newname)| 重命名服务器上的文件 |
|f.retrbinary(command, callback [, blocksize [, rest]])| 使用二进制传输模式执行命令并返回结果 |
|f.retrlines(command [, callback])| 使用文本传输模式执行命令并返回结果 |
|f.rmd(pathname)| 从服务器上删除目录 |
|f.sendcmd(command)| 向服务器发送简单命令并返回响应 |
|f.set_pasv(pasv)| 设置被动模式 |
|f.size(filename)| 返回文件的大小(字节) |
|f.storbinary(command, file [, blocksize])| 使用二进制传输模式执行命令并传输数据 |
|f.storlines(command, file)| 使用文本传输模式执行命令并传输数据 |
|f.transfercmd(command [, rest])| 启动FTP数据连接上的传输 | -
示例:上传文件到FTP服务器
host = "ftp.foo.com"
username = "dave"
password = "1235"
filename = "somefile.dat"
import ftplib
ftp_serv = ftplib.FTP(host,username,password)
# Open the file you want to send
f = open(filename,"rb")
# Send it to the FTP server
resp = ftp_serv.storbinary("STOR "+filename, f)
# Close the connection
ftp_serv.close
- 示例:从FTP服务器获取文档
try:
from urllib.request import urlopen # Python 3
except ImportError:
from urllib2 import urlopen # Python 2
u = urlopen("ftp://username:password@somehostname/somefile")
contents = u.read()
2. http包
http包包含用于编写HTTP客户端和服务器的模块,以及对状态管理(cookie)的支持。HTTP是一种基于文本的简单协议,其工作流程如下:
graph LR
A[客户端] --> B[连接到HTTP服务器]
B --> C[发送请求头]
C --> D[服务器处理请求]
D --> E[发送响应]
E --> A[客户端接收响应]
-
常见请求方法 :
| 方法 | 描述 |
| — | — |
|GET| 获取文档 |
|POST| 向表单提交数据 |
|HEAD| 仅返回头部信息 |
|PUT| 上传数据到服务器 | -
常见响应代码 :
| 代码 | 描述 | 符号常量 |
| — | — | — |
| 成功代码 (2xx) | | |
| 200 | OK | OK |
| 201 | Created | CREATED |
| 202 | Accepted | ACCEPTED |
| 204 | No content | NO_CONTENT |
| 重定向 (3xx) | | |
| 300 | Multiple choices | MULTIPLE_CHOICES |
| 301 | Moved permanently | MOVED_PERMANENTLY |
| 302 | Moved temporarily | MOVED_TEMPORARILY |
| 303 | Not modified | NOT_MODIFIED |
| 客户端错误 (4xx) | | |
| 400 | Bad request | BAD_REQUEST |
| 401 | Unauthorized | UNAUTHORIZED |
| 403 | Forbidden | FORBIDDEN |
| 404 | Not found | NOT_FOUND |
| 服务器错误 (5xx) | | |
| 500 | Internal server error | INTERNAL_SERVER_ERROR |
| 501 | Not implemented | NOT_IMPLEMENTED |
| 502 | Bad gateway | BAD_GATEWAY |
| 503 | Service unavailable | SERVICE_UNAVAILABLE |
3. http.client模块
http.client模块为HTTP客户端提供了底层支持。在Python 2中,该模块名为httplib。通常建议使用urllib包,但在某些情况下,可能需要处理底层细节。
-
建立HTTP连接 :
-
HTTPConnection(host [,port]):创建HTTP连接,默认端口为80。 -
HTTPSConnection(host [, port [, key_file=kfile [, cert_file=cfile ]]]):创建使用安全套接字的HTTP连接,默认端口为443。
-
-
HTTPConnection或HTTPSConnection实例方法 :
| 方法 | 描述 |
| — | — |
|h.connect()| 初始化连接 |
|h.close()| 关闭连接 |
|h.send(bytes)| 向服务器发送字节字符串 |
|h.putrequest(method, selector [, skip_host [, skip_accept_encoding]])| 向服务器发送请求 |
|h.putheader(header, value, ...)| 向服务器发送RFC - 822风格的头部 |
|h.endheaders()| 发送空白行表示头部结束 |
|h.request(method, url [, body [, headers]])| 向服务器发送完整的HTTP请求 |
|h.getresponse()| 获取服务器响应 | -
HTTPResponse实例方法和属性 :
-
方法
:
-
r.read([size]):从服务器读取最多size字节的数据。 -
r.getheader(name [,default]):获取响应头部。 -
r.getheaders():返回头部元组列表。
-
-
属性
:
-
r.version:服务器使用的HTTP版本。 -
r.status:服务器返回的HTTP状态码。 -
r.reason:服务器返回的HTTP错误消息。 -
r.length:响应中剩余的字节数。
-
-
方法
:
-
异常 :
| 异常 | 描述 |
| — | — |
|HTTPException| 所有HTTP相关错误的基类 |
|NotConnected| 请求已发出但未连接 |
|InvalidURL| 错误的URL或端口号 |
|UnknownProtocol| 未知的HTTP协议号 |
|UnknownTransferEncoding| 未知的传输编码 |
|UnimplementedFileMode| 未实现的文件模式 |
|IncompleteRead| 接收的数据不完整 |
|BadStatusLine| 收到未知的状态码 |
|ImproperConnectionState| 所有HTTP连接状态错误的基类 |
|CannotSendRequest| 无法发送请求 |
|CannotSendHeader| 无法发送头部 |
|ResponseNotReady| 无法读取响应 | -
示例:使用HTTPConnection进行文件上传
import os
try:
from httplib import HTTPConnection # Python 2
except ImportError:
from http.client import HTTPConnection # Python 3
BOUNDARY = "$Python-Essential-Reference$"
CRLF = '\r\n'
def upload(addr, url, formfields, filefields):
# Create the sections for form fields
formsections = []
for name in formfields:
section = [
'--'+BOUNDARY,
'Content-disposition: form-data; name="%s"' % name,
'',
formfields[name]
]
formsections.append(CRLF.join(section)+CRLF)
# Collect information about all of the files to be uploaded
fileinfo = [(os.path.getsize(filename), formname, filename)
for formname, filename in filefields.items()]
# Create the HTTP headers for each file
filebytes = 0
fileheaders = []
for filesize, formname,filename in fileinfo:
headers = [
'--'+BOUNDARY,
'Content-Disposition: form-data; name="%s"; filename="%s"' % \
(formname, filename),
'Content-length: %d' % filesize,
''
]
fileheaders.append(CRLF.join(headers)+CRLF)
filebytes += filesize
# Closing marker
closing = "--"+BOUNDARY+"--\r\n"
# Determine the entire length of the request
content_size = (sum(len(f) for f in formsections) +
sum(len(f) for f in fileheaders) +
filebytes+len(closing))
# Upload it
conn = HTTPConnection(*addr)
conn.putrequest("POST",url)
conn.putheader("Content-type", 'multipart/form-data; boundary=%s' % BOUNDARY)
conn.putheader("Content-length", str(content_size))
conn.endheaders()
# Send all form sections
for s in formsections:
conn.send(s.encode('latin-1'))
# Send all files
for head,filename in zip(fileheaders,filefields.values()):
conn.send(head.encode('latin-1'))
f = open(filename,"rb")
while True:
chunk = f.read(16384)
if not chunk: break
conn.send(chunk)
f.close()
conn.send(closing.encode('latin-1'))
r = conn.getresponse()
responsedata = r.read()
conn.close()
return responsedata
# Sample: Upload some files. The form fields 'name', 'email'
# 'file_1','file_2', and so forth are what the remote server
# is expecting (obviously this will vary).
server = ('localhost', 8080)
url = '/cgi-bin/upload.py'
formfields = {
'name' : 'Dave',
'email' : 'dave@dabeaz.com'
}
filefields = {
'file_1' : 'IMG_1008.JPG',
'file_2' : 'IMG_1757.JPG'
}
resp = upload(server, url,formfields,filefields)
print(resp)
4. http.server模块
http.server模块提供了用于实现HTTP服务器的各种类。在Python 2中,该模块的内容分布在BaseHTTPServer、CGIHTTPServer和SimpleHTTPServer三个库模块中。
- HTTPServer类 :实现基本的HTTP服务器。
HTTPServer(server_address, request_handler)
- `server_address`:一个元组`(host, port)`,服务器将监听该地址。
- `request_handler`:一个继承自`BaseHTTPRequestHandler`的处理类。
示例:定义一个多线程HTTP服务器,只接受特定子网的连接。
try:
from http.server import HTTPServer # Python 3
from socketserver import ThreadingMixIn
except ImportError:
from BaseHTTPServer import HTTPServer # Python 2
from SocketServer import ThreadingMixIn
class MyHTTPServer(ThreadingMixIn,HTTPServer):
def __init__(self,addr,handler,subnet):
HTTPServer.__init__(self,addr,handler)
self.subnet = subnet
def verify_request(self, request, client_address):
host, port = client_address
if not host.startswith(subnet):
return False
return HTTPServer.verify_request(self,request,client_address)
# Example of how the server runs
serv = MyHTTPServer(('',8080), SomeHandler, '192.168.69.')
serv.serve_forever()
-
预建的处理类 :
-
CGIHTTPRequestHandler:从当前目录及其子目录提供文件服务。如果文件位于特殊的CGI目录(默认是/cgi-bin和/htbin),则将其作为CGI脚本运行。支持GET、HEAD和POST方法,但不支持HTTP重定向。 -
SimpleHTTPRequestHandler:从当前目录及其子目录提供文件服务。支持HEAD和GET请求。
这两个处理类定义了以下可通过继承更改的类变量:
| 变量 | 描述 |
| — | — |
|handler.server_version| 返回给客户端的服务器版本字符串 |
|handler.extensions_map| 后缀到MIME类型的映射 |示例:使用
CGIHTTPRequestHandler启动一个独立的Web服务器。 -
try:
from http.server import HTTPServer, CGIHTTPRequestHandler # Python 3
except ImportError:
from BaseHTTPServer import HTTPServer # Python 2
from CGIHTTPServer import CGIHTTPRequestHandler
import os
# Change to the document root
os.chdir("/home/httpd/html")
# Start the CGIHTTP server on port 8080
serv = HTTPServer(("",8080),CGIHTTPRequestHandler)
serv.serve_forever()
- BaseHTTPRequestHandler类 :用于定义自定义HTTP服务器处理的基类。
BaseHTTPRequestHandler(request, client_address, server)
- 类变量:
- `server_version`:服务器报告给客户端的软件版本字符串。
- `sys_version`:Python系统版本。
- `error_message_format`:用于构建发送给客户端的错误消息的格式字符串。
- `protocol_version`:响应中使用的HTTP协议版本。
- `responses`:整数HTTP错误代码到描述问题的二元组`(message, explain)`的映射。
- 实例属性:
| 属性 | 描述 |
| --- | --- |
| `b.client_address` | 客户端地址,元组`(host, port)` |
| `b.command` | 请求类型,如`GET`、`POST`等 |
| `b.path` | 请求路径,如`/index.html` |
| `b.request_version` | 请求中的HTTP版本字符串 |
| `b.headers` | HTTP头部,存储在映射对象中 |
| `b.rfile` | 用于读取可选输入数据的输入流 |
| `b.wfile` | 用于向客户端写响应的输出流 |
- 常用方法:
| 方法 | 描述 |
| --- | --- |
| `b.send_error(code [, message])` | 发送不成功请求的响应 |
| `b.send_response(code [, message])` | 发送成功请求的响应 |
| `b.send_header(keyword, value)` | 向输出流写入MIME头部条目 |
| `b.end_headers()` | 发送空白行表示MIME头部结束 |
| `b.log_request([code [, size]])` | 记录成功请求 |
| `b.log_error(format, ...)` | 记录错误消息 |
| `b.log_message(format, ...)` | 向`sys.stderr`记录任意消息 |
示例:创建一个自定义HTTP服务器,在单独的线程中运行,监控字典内容。
try:
from http.server import BaseHTTPRequestHandler, HTTPServer # Py 3
except ImportError:
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer # Py 2
class DictRequestHandler(BaseHTTPRequestHandler):
def __init__(self,thedict,*args,**kwargs):
self.thedict = thedict
BaseHTTPRequestHandler.__init__(self,*args,**kwargs)
def do_GET(self):
key = self.path[1:] # Strip the leading '/'
if not key in self.thedict:
self.send_error(404, "No such key")
else:
self.send_response(200)
self.send_header('content-type','text/plain')
self.end_headers()
resp = "Key : %s\n" % key
resp += "Value: %s\n" % self.thedict[key]
self.wfile.write(resp.encode('latin-1'))
# Example use
d = {
'name' : 'Dave',
'values' : [1,2,3,4,5],
'email' : 'dave@dabeaz.com'
}
from functools import partial
serv = HTTPServer(("",9000), partial(DictRequestHandler,d))
import threading
d_mon = threading.Thread(target=serv.serve_forever)
d_mon.start()
5. http.cookies模块
http.cookies模块为处理HTTP cookie提供服务器端支持。在Python 2中,该模块名为
Cookie
。
- Cookie的基本概念 :Cookie用于在实现会话、用户登录等功能的服务器中进行状态管理。服务器通过在HTTP响应中添加类似以下的头部来设置Cookie:
Set-Cookie: session=8273612; expires=Sun, 18-Feb-2001 15:00:00 GMT; path=/; domain=foo.bar.com
- SimpleCookie类 :
SimpleCookie([input])
- 方法:
| 方法 | 描述 |
| --- | --- |
| `c.output([attrs [,header [,sep]]])` | 生成适合在HTTP头部设置Cookie值的字符串 |
| `c.js_output([attrs])` | 生成包含JavaScript代码的字符串,在支持JavaScript的浏览器上执行时设置Cookie |
| `c.load(rawdata)` | 使用`rawdata`中的数据加载Cookie |
- `Morsel`类实例的方法和属性:
| 方法/属性 | 描述 |
| --- | --- |
| `m.value` | 包含Cookie原始值的字符串 |
| `m.coded_value` | 包含将发送到或从浏览器接收的编码后的Cookie值的字符串 |
| `m.key` | Cookie名称 |
| `m.set(key,value,coded_value)` | 设置`m.key`、`m.value`和`m.coded_value`的值 |
| `m.isReservedKey(k)` | 测试`k`是否为保留关键字 |
| `m.output([attrs [,header]])` | 生成此Cookie的HTTP头部字符串 |
| `m.js_output([attrs])` | 输出执行时设置Cookie的JavaScript代码 |
示例:创建和使用Cookie。
c = SimpleCookie()
c["session"] = 8273612
c["user"] = "beazley"
c["session"]["path"] = "/"
c["session"]["domain"] = "foo.bar.com"
c["session"]["expires"] = "18-Feb-2001 15:00:00 GMT"
print(c.output())
# 从环境变量中恢复Cookie值
import os
c = SimpleCookie(os.environ["HTTP_COOKIE"])
session = c["session"].value
user = c["user"].value
综上所述,Python提供了丰富的模块和类来处理FTP和HTTP协议,无论是客户端还是服务器端的开发,都能找到合适的工具。通过这些工具,开发者可以轻松实现文件上传、下载、状态管理等功能。
超级会员免费看
992

被折叠的 条评论
为什么被折叠?



