C20 Web编程
20.1介绍
C/S架构 服务端永远运行
HTTP协议 :无状态协议,不跟踪一个客户端到另一个客户端的请求,但会被处理为独立的服务请求
使用URL和cookie保存信息
URL 统一资源定位器
URI 统一资源标识器
URL是URI的一部分
prot_sch://net_loc/path;params?query#frag
prot_sch网络协议或者下载规划
net_loc 服务器位置和用户信息 具体为user:passwd@host:port
path 斜杠(/)限定文件或者CGI应用程序的路径
params 可选参数
query 连接符(&)连接键值对
frag 拆分文档中的特殊锚
20.2.2 urlparse模块
.urlparse(urlstr,defProSch=None,allowFrag=None) 将urlstr解析成各个部件,allowFrag决定是否有零部件
>>>urlparse.urlparse('http://www.python.org/doc/FAQ.html')
('http','www.python.org','/doc/FAQ.html','','','')
.urlunparse(urlup) 将urlup元组组合成一个url字符串
.urljoin(baseurl,newurl,allowFrag=None) ,将baseurl的部件的一部分替换成newurl(newurl不需要完整),
返回字符串
20.2.3 urllib模块#提供了一个高级Web库,避免了使用httplib、ftplib、gopherlib等底层模块
1.urllib.urlopen()
f=urllib.urlopen(urlstr,postQueryData=None) #以文件类型打开URL
.read([bytes]) 从f中读出所有或bytes个字节
.readline() 从f中读出一行
.readlines() 从f中读出所有行并返回一个列表
.close() 关闭url
.fileno() 返回f的文件句柄
.info() 获得f的MIME头文件(通知使用哪类应用程序打开)
.geturl() 返回f所打开的真正的url
2.urllib.urlretrieve(urlstr,local-file=None,downloadStatusHook=None)
将文件下载为localfile或者tempfile,如果已下载则downloadStautsHook有统计信息
3.urllib.quote(urldata,safe='/')
将urldata的无效的url字符编码,在safe列的则不必编码,使适用打印或web服务器
urlilib.quote_plus(urldata,safe='/')
将空格编译成(+)号(而非%20),其他功能同上
4.urllib.unquote(urldata)
将urldata解码
urllib.unquote_plus(urldata)
将加号解码成空格,其他同上
5.urllib.urlencode(dict)
将字典键--值对编译成有效的CGI请求字符串,用quote_plus()对键和值字符串分别编码
20.2.4 urllib2模块 #可以处理更复杂的请求,比如登录名和密码
方法一:建立一个基础认证服务器(urllib2.HTTPBasicAuthHandler),同时在基本URL或域上注册一个登录密码。
方法二:当浏览器提示的时候,输入用户名和密码,这样就发送了一个带有适当用户请求的认证头。
#urlopenAuth.py
import urllib2
LOGIN='wesc'
PASSWD="you'll never guess"
URL='http://localhost'
def handler_version(url):
from urlparse import urlparse as up
hdlr=urllib2.HTTPBasicAuthHandler()
hdlr.add_password('Archives',up(url)[1],LOGIN,PASSWD)
opener=urllib2.build_opener(hdlr)
urllib2.install_opener(opener)
return url
def request_version(url):
from base64 import encodestring
req=urllib2.Request(url)
b64str=encodestring('%s%s'%(LOGIN,PASSWD))[:-1]
req.add_header("Authorization","Basic %s"%b64str)
return req
for funcType in('handler','request'):
print '***using %s'%funcType.upper()
url=eval('%s_version'%funcType)(URL)
f=urllib2.urlopen(url)
print f.readline()
f.close()
20.3 高级Web客户端
网络爬虫:为搜索引擎建索引、脱机浏览、下载并保存历史记录或框架、Web页的缓存节约访问时间
#coding=UTF-8
#crawl.py
from sys import argv
from os import makedirs, unlink, sep
from os.path import dirname, exists, isdir, splitext
from string import replace, find, lower
from htmllib import HTMLParser
from urllib import urlretrieve
from urlparse import urlparse, urljoin
from formatter import DumbWriter, AbstractFormatter
from cStringIO import StringIO
class Retriever(object):#download Web pages
def __init__(self, url): #初始化
self.url = url
self.file = self.filename(url) #以filename方式新建文件
def filename(self, url, deffile='index.htm'): #开辟文件路径
parsedurl = urlparse(url, 'http:', 0)
path = parsedurl[1] + parsedurl[2] #域名和远程文件路径
ext = splitext(path)
if ext[1] == '': #no file ,ues default
if path[-1] == '/':
path += deffile #后缀
else:
path += '/' + deffile
ldir = dirname(path)
#print "thatis",ldir
if sep != '/':
ldir = replace(ldir, '/', sep) #以系统的分隔符替换'/'
if not isdir(ldir): #不存在则创建文档
if exists(ldir): unlink(ldir)
# print "thisis",ldir
makedirs(ldir or 'undenied')
return path
def download(self): #获取文件
try:
retval = urlretrieve(self.url, self.file)
except:
retval = ('*** ERROR: invalid URL "%s"' % self.url,)
print "download done"
return retval
def parseAndGetLinks(self): #定义获取links的方法
self.parser = HTMLParser(AbstractFormatter(DumbWriter(StringIO())))
self.parser.feed(open(self.file).read())
self.parser.close()
return self.parser.anchorlist
class Crawler(object):
count = 0
def __init__(self, url):
self.q = [url] #初始化队列
self.seen = []
self.dom = urlparse(url)[1] #域名部分
def getPage(self, url):
r = Retriever(url) #先下载了
retval = r.download() #下载的内容部分
if retval[0] == '*':
print retval, '... skipping parse'
return
Crawler.count += 1 #加一次爬取
print '\n(', Crawler.count, ')'
print 'URL:', url #打印链接
print 'FILE:', retval[0]
self.seen.append(url)#已爬取的添加到历史记录里
links = r.parseAndGetLinks()#获取links
for eachLink in links:
if eachLink[:4] != 'http' and find(eachLink, '://') == -1:
eachLink = urljoin(url, eachLink)#补充成完整链接
print '* ', eachLink,
if find(lower(eachLink), 'mailto:') != -1: #滤过邮件链接
print '... discarded, mailto link'
continue
if eachLink not in self.seen: #历史记录里未爬取
if find(eachLink, self.dom) == -1: #滤过非域内链接
print '... discarded, not in domain'
else:
if eachLink not in self.q:
self.q.append(eachLink) #判定为新的非重复链接,添加
print '... new, added to Q'
else:
print '... discarded, already in Q'
else:
print '... discarded, already processed'#判定已爬取
def go(self):
while self.q: #队列非空则继续爬取
url = self.q.pop() #从队列中取出
self.getPage(url) #下载并分析链接
def main():
if len(argv) > 1:
url = argv[1]
else:
try:
url = raw_input('Enter starting URL: ') #http://www.baidu.com/index.html
except:
url = ''
if not url: return
robot = Crawler(url) #入口,并初始化队列
robot.go()
if __name__ == "__main__":
main() #首先看看main函数吧,再看到go
20.4 CGI:帮助Web服务器处理客户端数据
#CGI程序与应用程序不同在于输入、输出及用户和计算机交互方面
#cgi模块主要类是FiledStorage,一旦实例化会具有一系列键值对,这些值本身可以是FiledStorage对象,也可以是MiniFiledStorage对象,或者是这些对象的列表。
20.5建立CGI应用程序
10.5.1建立Web服务器
可以用Apache
也可以建立一个基于web的简单服务器,默认8000端口
$ Python -m CGIHTTPServer
20.9相关模块 cgi cgitb htmllib HTMLparser htmlentitydefs cookie cookielib webbrowser sgmllib robotparser httplib xmllib xml xml.sax xml.dom xml.etree xml.parsers.expat xmlrpclib SimpleXMLRPCServer DocXMLRPCServer BaseHTTPServer SimpleHTTPServer CGIHTTPServer wsgiref HTMLgen BeautifulSoup poplib imaplib email mailbox mailcap mimetools mimetypes MimeWriter multifile quopri rfc822 smtplib base64 binascii binhex uu httplib ftplib gopherlib telnetlib nntplib