网络编程
python是一个很强大的网络编程工具,首先,它有很多针对常见网络协议的库,在库顶部可以获得抽象层,这样可以集中精力在程序的逻辑处理上,而不是停留在网络实现的细节上;其次,python处理字节流的各种模式方面很擅长,因此可以轻松处理各种协议格式。
少数几个网络设计模块
socket模块
在网络编程中的一个基本组件就是套接字(socket)。套接字主要是两个程序之间“信息通道”。程序可能(通过网络连接)分布在不同的计算机上,通过套接字相互发送信息。在Python中的大多数的网络编程都隐藏了socket模块的基本细节,并且不直接和套接字交互。
套接字包括两个:服务器套接字和客户端套接字。
创建一个服务器套接字后,让它等待连接。这样它就在某个网络地址处(ip地址和一个端口号的组合)监听。
处理客户端套接字通常比处理服务器套接字容易,因为服务器必须准备随时处理客户端的连接,同时还要处理多个连接,而客户端只是简单的连接,完成事务,断开连接。
一个套接字就是一个socket模块中的socket类的实例。有三个参数:第一个是地址族(默认是socket.AF_INET),第二个参数是流(默认是socket.SOCK_STREAM,默认值)或数据报(socket.SOCK_DGRAM)套接字。第三个参数是使用的协议(默认是0,使用默认值即可)。对于一个普通的套接字,不需要提供任何参数。
服务器端套接字使用bind方法后,再调用listen方法监听这个给定地址。客户端套接字使用connect方法连接到服务器在connect方法中使用的地址与bind方法中的地址相同。在这种情况下,一个地址就是一个格式为(host,port)的元组,其中host是主机名,port是端口号。Listen方法只有一个参数,即服务器未处理的连接的长度。
服务器套接字开始监听后,它就可以接受客户端的连接。这个步骤使用accept方法来完成。这个方法会堵塞(等待)直到客户端连接,然后该方法就返回一个格式为(client,address)的元组。服务器能处理客户端到它满意的程度,然后调用一个accept方法开始等待下一个连接。这个过程通常都是在一个无限循环中实现的。
套接字有两个方法:send和rev,用于传输数据。可以使用字符串参数调用send以发送数据,用一个所需的(最大)字节数做参数调用recv来接收数据。如果不能确定使用哪个数字比较好,那么1024是个很好的选择。
小型服务器
import socket
s=socket.socket()
host=socket.gethostname()
port=1234
s.bind((host,port))
s.listen(5)
while True:
c,addr = s.accept()
print "Got connect from",addr
c.send('tkx for connecting')
c.close()
小型客户端
import socket
s=socket.socket()
host=socket.gethostname()
port=1234
s.connect((host,port))
print s.recv(1024)
urllib和urllib2模块
在能使用的各种网络工作库中,功能最强大的是urllib和urllib2。它们能让通过网络访问文件,就像那些文件存在于你电脑上一样。通过一个简单的函数调用,几乎可以把任何URL所指向的东西用作程序的输入。
这两个模块功能差不多,但urllib更好一些。如果只使用简单的下载,urllib就足够了。但如果需要使用HTTP验证或cookie或者要为自己的协议写扩展程序的话,urllib2是个好的选择。
打开远程文件
>>> from urllib import urlopen
>>> webpage=urlopen("http://blog.csdn.net/signjing")
Urlopen返回的类文件对象支持close、read、readline和readlines方法,当然也支持迭代。
获取远程文件
函数urlopen提供一个能从中读取数据的类文件对象。如果希望urllib为你下载文件并在本地文件存在一个文件的副本,那么可以使用urlretrieve。
Urlretrieve返回一个元组(filename,headers)而不是类文件对象,filename是本地文件的名字(由urllib自动创建),headers包含一些远程文件的信息。
>>> import urllib
>>> urllib.urlretrieve('http://www.baidu.com','d:\\baidu.html')
('d:\\baidu.html', <httplib.HTTPMessage instance at 0x02BFC788>)
如果没有指定文件名,文件会放在临时的位置,用open函数可以打开它。完成了对它的操作,就可以删除它以节省空间,要删除临时文件,可以用urlcleanup函数,不需要提供参数。
其它模块
模块 | 描述 |
asynchat | asyncore的增强版本 |
asyncore | 异步套接字处理程序 |
cgi | 基本的CGI支持 |
Cookie | Cookie对象操作,主要用于服务器 |
cookielib | 客户端cookie支持 |
| Email消息支持 |
ftplib | FTP客户端模块 |
gopherlib | gopher客户端模块 |
httplib | http客户端模块 |
imaplib | imap4客户端模块 |
mailbox | 读取几种邮箱的格式 |
mailcap | 通过mailcap文件访问MIME配置 |
mhlib | 访问MH邮箱 |
nntplib | NNTP客户端模块 |
poplib | pop客户端模块 |
robotparser | 支持解析web服务器的robot文件 |
SimpleXMLRPCServer | 一个简单的xml-rpc服务器 |
smtpd | smtp服务器端模块 |
smtplib | smtp客户端模块 |
telnetlib | telnet客户端模块 |
urlparse | 支持解释url |
xmlrpclib | xml-rpc的客户端支持 |
SocketServer和它的朋友们
SocketServer模块是标准库中很多服务器框架的基础。
SocketServer包含了4个基本的类:针对TCP套接字流的TCPServer;针对UDP数据报套接字的UDPServer;以及针对性不强的UnixStreamServer和UnixDatagramServer。
多连接
到目前为止讨论的服务器解决方案都是同步的:即一次只能连接一个客户端并处理它的请求。
怎么样同时处理多个连接呢?
三种方法:分叉(forking)、线程(threading)以及异步I/O(asynchronous I/O)。
详略;
Twisted
Twisted是一个事件驱动的python网络框架,原来是为网络游戏开发的,现在被所有类型的网络软件使用。
下载并安装Twisted
编写Twisted服务器
这章之前编写的基本套接字服务器是显式的。其中的一些有很清楚的事件循环,用来查找新的连接和新数据,而基于SocketServer的服务器有一个隐式的循环,在循环中服务器查找连接并为每个连接创建一个处理程序,但处理程序在要读取数据时必须是显式的。
Twisted使用一个事件甚至多个基于事件的方法。要编写基本的服务器,就要实现处理比如新客户端连接、新数据到达以及一个客户端断开连接等事件的事件处理程序。具体的类能通过基本类建立更精炼的事件。
Python和万维网
万维网程序设计涉及的领域相当广,这里只选择三个主题:屏幕抓取、CGI和mod_python。
屏幕抓取
屏幕抓取是程序下载网页并且提取信息的过程。这个技术很有用,如果你想在你的程序中使用在线的网页中所包含的信息,就可以使用这个技术。如果所涉及的网页是动态的那就更有用了,也就是说网页是不停变化的。
Tidy和XHTML解析
python标准库中有很多支持结构化格式的库,例如html和xml。本节介绍一种用来处理xhtml的工具,xhtml是html最新的方言,是xml的一种形式。
对于包含正确而且有效的xhtml的网页而言,解析的工作很简单。问题在于旧版的html的方言较为随意,有些人甚至不关心这种随意的方言的限制。原因可能在于大部分网络浏览器都是很“宽容”的,并且会尽它们最大的努力来渲染最混乱且无意义的html。如果对于网页作者来说这是可以接受的,那么浏览器可能会很满意。而这却使屏幕抓取工作变得有点困难。
标准库中解析html的一般方法是基于事件的,所以需要编写像解析器一样顺序处理数据的事件处理程序。标准库模块sgmllib和htmllib可以用这种方式解析非常混乱的html,但如果希望提取基于文档结构的数据,那么在缺失标签的情况下可能要碰碰运气了。如果愿意的话,这么做当然也没问题,不过还有另外一种方法:Tidy。
tidy是什么
tidy是用来修复不规范且随意的HTML的工具。它能以相当智能的方法修复一般的错误,做那些你不愿意做的事情。它也是可设置的,也可以打开或关闭各种修改选项。
当然,tidy不能修复HTML文件的所有问题,但是它会确保文件的格式是正确的(也就是所有元素都正确嵌套),这样一来解析的时候就轻松多了。
获取tidy库
http://www.egenix.com/products/python/mxExperimental/mxTidy
但为什么用xhtml
XHTML和旧版本的HTML之间的最主要区别是XHTML对于显式关闭所有元素要求更加严格。所以在HTML中可能只用一个开始标签(<p>标签)结束一段然后开始下一段,而在XHTML中首先需要显式地关闭当前段落(用</p>标签)。这种行为让XHTML更容易解析,因为可以直接告诉程序什么时候进入或者离开各种元素。
XHTML的另外一个好处是它是XML的一种,所以可以对它使用XML的工具,如XPath。
解析这类从Tidy中获得的表现良好的XHTM方法是使用标准库模块(和类)HTMLParser。
使用htmlparser
使用HTMLParser的意思就是继承它,并且对handle_starttage或handle_data等事件处理方法进行覆盖。
如果要进行屏幕抓取,一般不需要实现所有的解析器回调,也可能不用创造整个文档的抽象表示法来查找自己需要的内容。如果只需要记录所需信息的最小部分,那么这就足够了。
Beautiful Soup
Beautiful Soup是个小模块,用来解析和检查经常在网上看到的那类乱七八糟而且不规范的HTML。
http://www.crummy.com/software/BeautifulSoup/
如果针对RSS feed进行分析,可以使用另外一个和Beautiful Soup相关的工具,叫做Scrape N Feed。
http://www.crummy.com/software/ScrapeNFeed/
使用CGI构建动态网页
CGI是网络服务器可以将查询(一般来说是通过Web表单)传递到专门的程序中并且在网页上显示结果的标准机制。它是创建万维网应用程序而不用编写特殊用途的应用服务器的简单方法。
python CGI程序设计的关键工具是cgi模块。cgitb是另外一个在CGI脚本开发过程中的有用模块。
使CGI脚本可通过网络访问(运行)之前,需要将它们放到网络服务器可以访问的地方,并且加入pound bang行,设置合适的文件许可。
第一步:准备网络服务器
假设可以访问网络服务器——换句话说可以在网络上放置文件。一般来说,可以把网页、图片等放在特殊的目录中。
CGI程序也应该放在通过网络可以访问的目录中。并且必须将它们标识为CGI脚本,这样网络服务器就不会将普通源代码作为网页处理。有两种方法可以实现这个功能:
将脚本放在叫做cgi-bin的子目录中;
把脚本文件扩展名改为.cgi;
具体的工作方式因服务器而异。
第二步:加入Pound Bang行
当把脚本放在正确位置(可能将其改为了特定的扩展名)后,需要在脚本的开始处增加pound bang行。没有这行的话,网络服务器就不知道如何执行脚本。一般来说,只要把下面这行加到脚本开始处就可以了:
#!/usr/bin/env python
注意,它一定要是第一行(之前没有空行)。如果不能正常功能,需要查看python可执行文件的确切位置,并使用全路径。如果还是不行,可以看看行结尾符是否是合法的,确保把文件存为了一个普通的unix风格的文本文件。
在windows系统中,可以使用python二进制版本的全路径,如:
#!c:\Python22\python.exe
第三步:设置文件许可
这里主要是指在unix或linux系统上需要给脚本文件以读取和执行的权限。
一般来说,不允许CGI脚本修改计算机上的任何文件。
CGI安全风险
使用CGI程序时也有安全问题存在。如果允许CGI脚本写服务器上的文件,那么除非非常小心地编写代码,否则可能会造成数据的损毁。同样,如果将用户提供的数据看作python代码或shell命令运行,也就承担了运行任意代码的风险,这是个很大(极其巨大)的安全问题。
简单的CGI脚本
#!/usr/bin/env python
print ‘Content-type:text/plain’
print ‘Hello,world!’
Content-type后面跟着一个冒号、一个空格和一个类型名text/plain。这表明页面是普通文本,如果页面是html,这一行应该是:
print ‘Content-type: text/html’
在所有的首部被打印后,打印一个空行表示文档即将开始。
使用cgitb调试
有时候编程的错误会让程序因为没有捕获的异常而以堆栈跟踪终止。当通过CGI运行程序时,这种情况很有可能会由服务器返回的无帮助错误信息。
cgitb是用于CGI回溯到模块,导入它并调用enable函数,就能得到包含出错信息的十分有用的网页。
注意,应在开发完成后关掉cgitb功能,因为回溯页不是为程序的一般用户准备的。
使用cgi模块
目前为止,程序只能产生输出,而不能接受任何形式的输入。输入是通过html表单提供给cgi脚本的键值对,或称字段。可以使用cgi模块的FieldStorage类从cgi脚本中获取这些字段。当创建FieldStorage实例时,它会从请求中获取输入变量,然后通过类字典接口将它们提供给程序。FieldStorage的值可以通过普通的键查找方式访问,但是因为一些技术原因,FieldStorage的元素并不是真正所要的值。
简单的表单
略;
更进一步:mod_python
安装mod_python
如果喜欢cgi,很可能会爱上mod_python。它是python网络服务器的扩展模块,可以从mod_python的网站上获取。它可以让python解释器直接成为apache的一部分,这样一来可以在程序中应用很酷的东西了。最重要的是它提供了python中编写apache处理程序的功能,和使用c语言不通,它是标准的。使用mod_python处理程序框架可以访问丰富的api,深入apache内核,等等。
除了基本功能外,还带有用于web开发的处理程序:
cgi处理程序
psp处理程序
发布处理程序
详略;