系列4python之詳細(xì)初學(xué)者教程講義-20.web應(yīng)用_第1頁(yè)
系列4python之詳細(xì)初學(xué)者教程講義-20.web應(yīng)用_第2頁(yè)
系列4python之詳細(xì)初學(xué)者教程講義-20.web應(yīng)用_第3頁(yè)
系列4python之詳細(xì)初學(xué)者教程講義-20.web應(yīng)用_第4頁(yè)
系列4python之詳細(xì)初學(xué)者教程講義-20.web應(yīng)用_第5頁(yè)
免費(fèi)預(yù)覽已結(jié)束,剩余82頁(yè)可下載查看

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

WebCGIWeb應(yīng)用:客戶(hù)端/服務(wù)器計(jì) WebWeb許用戶(hù)在網(wǎng)上查詢(xún)文檔。另外Web服務(wù)器端,進(jìn)程運(yùn)行在信息提供商的主機(jī)上。這些服務(wù)器等服務(wù)器端被設(shè)置為“”運(yùn)行。圖20-1列舉了Web應(yīng)用的體驗(yàn)。這里,一個(gè)用戶(hù)執(zhí)行一個(gè)像瀏覽器的這類(lèi)客戶(hù)端程序與Web服務(wù)器取得連接,就可以在因特網(wǎng)上任何地方獲得數(shù)據(jù)。圖20-1因特網(wǎng)上的Web客戶(hù)端和Web服務(wù)器。在因特網(wǎng)上客戶(hù)端向服務(wù)器端發(fā)送一個(gè)請(qǐng)求,然數(shù)據(jù)的表單。這個(gè)請(qǐng)求經(jīng)過(guò)服務(wù)器端的處理,然后會(huì)以特定的格式(HTML行的:一旦一個(gè)客戶(hù)的請(qǐng)求完成后,活動(dòng)將被終止??梢噪S時(shí)發(fā)送新的請(qǐng)求,但是他們會(huì)被處理成URL請(qǐng)求的一部分,以便提供一些狀態(tài)信息。另外一個(gè)選項(xiàng)是“”--保存在客戶(hù)端的客戶(hù)狀態(tài)信息。在本章的后面部分,會(huì)看到如何使用URL和來(lái)保存狀態(tài)信息。路,實(shí)際包含了不定節(jié)點(diǎn)的連通。作為一個(gè)客戶(hù)端用戶(hù),所有這些實(shí)現(xiàn)細(xì)節(jié)都會(huì)被隱 。抽象成為了從客戶(hù)端到所的服務(wù)器端的直接連接。被隱的HTTP,TCP/IP協(xié)議將會(huì)處理所有的繁重工作。中間的環(huán)節(jié)信息用戶(hù)并不關(guān)心,所以將這些執(zhí)行過(guò)程隱是有好處的。圖20-2展 20-2WebWeb表左側(cè)的焦點(diǎn)是Web客戶(hù)端,在家上網(wǎng)的用戶(hù)通過(guò)撥號(hào)連接到ISP(因特網(wǎng)供應(yīng)商)上,上班族使用WebWeb荷(高數(shù)量用戶(hù)群)而設(shè)計(jì)成了可以重復(fù)數(shù)據(jù)的系統(tǒng)。小公司的Web站點(diǎn)或許不需要這么大的硬盤(pán)或者網(wǎng)絡(luò)設(shè)備,也許僅有一個(gè)或者幾個(gè)“整合”服務(wù)器安放在他們的ISP處就可以了。ISPWebWeb,F(xiàn)TP,Gopher(WebSMTP件傳輸協(xié)議(這個(gè)協(xié)議用于最古老的也是應(yīng)用最廣泛的電子郵件,NNTP(對(duì)傳輸協(xié)議??梢赃@樣區(qū)分“因特網(wǎng)編程”和“WebWebWeb使用Python進(jìn)行Web應(yīng)用:創(chuàng)建一個(gè)簡(jiǎn)單的Web客戶(hù) Web數(shù)據(jù)。這樣做的一個(gè)重要原因就是瀏覽器的能力有限,也就是說(shuō),它主要用于查看并同其他Web站一個(gè)使用urllib模塊或者Web上的信息的應(yīng)用程序[使用urllib.urlopen()或者urllib.urlre-trieve()]可以被認(rèn)為是簡(jiǎn)單的Web客戶(hù)端。你所要做的就是提供一個(gè)有效的Web統(tǒng)一資源定位符簡(jiǎn)單的Web應(yīng)用包擴(kuò)使用被稱(chēng)為URL(統(tǒng)一資源)的Web地址。這個(gè)地址用來(lái)在Web上定位一個(gè)文檔,或者調(diào)用一個(gè)CGI程序來(lái)為你的客戶(hù)端產(chǎn)生一個(gè)文檔。URL是大型標(biāo)識(shí)符URI(統(tǒng)一資源標(biāo)識(shí))的一部分。這個(gè)超集是建立在已有名慣例基礎(chǔ)上的。一個(gè)URL是一個(gè)簡(jiǎn)單的URI,使已存在的協(xié)議或規(guī)劃(也就是http,ftp等)作為地址的一部分。為了進(jìn)一步描繪這些 non-URLURI,URN(統(tǒng)一資源名稱(chēng)例如123主大街。這個(gè)和其他國(guó)家不同,他們有自己的規(guī)則。URL使用這種格式:Table20.1WebAddressComponentsURL部 CGI & 20.1描述了各個(gè)部件都是使用這時(shí)是不需要用戶(hù)名和的。部 描 (默認(rèn)Python支持兩種不同的模塊,分別以不同的功能和兼容性來(lái)處理URL。一種是urlparse,一種是urllib。這里會(huì)簡(jiǎn)單的介紹下它們的功能。urlpasrseURLurlparse(),urlparse(urlstr,defProtSch=None,urlparse()urlstr解析成一個(gè)6prot_sch,net_loc,path,params,query,可以使用defProtSch。allowFrag標(biāo)識(shí)一個(gè)URL是否允許使用零部件。下邊是一個(gè)給定URL經(jīng)urlparse()后的輸出:>>>urlparse.urlparse( ,'/doc/FAQ.html','','',urlunparse()的功能與urlpase()完全相反—它拼合一個(gè)6-元組(prot_sch,net_loc,path,params,query,frag)urltup,URLurlparse()后的輸出返回值。于是,我們可urlunparse(urlparse(urlstr))=列頁(yè)面的URL。Urljoin()的語(yǔ)法是:urljoin(baseurl,newurl,Table20.3CoreurlparseModuleurlparse功 描 defPotcaloFa newurl,allowFrag 與newurl連接起來(lái)。例如:>>>urlparse.urljoin(',...'20.3urlparseurllib模塊:urllib模塊提供了所有你需要的功能,除非你計(jì)劃寫(xiě)一個(gè)更加低層的網(wǎng)絡(luò)客戶(hù)端。urllib提供了了一個(gè)高級(jí)的Web交流庫(kù),支持Web協(xié)議,HTTP,F(xiàn)TP和Gopher協(xié)議,同時(shí)也支持對(duì)本地文件的。urllib模塊的特殊功能是利用上述協(xié)議數(shù)據(jù)(從因特網(wǎng)、局域網(wǎng)、主機(jī)上)。使用這個(gè)模塊可以避免使用httplib,ftplib和gopherlib這些模塊,除非你想用更低層的功能。在那些情況下這些模塊都是可選擇的(注意:大多數(shù)以*lib命名的模塊用于客戶(hù)端相關(guān)協(xié)議開(kāi)發(fā)。并不是所有情況都是這樣的,或許urllib應(yīng)該被命名為“internetlib”或者其他什么相似的名字)。Urllib模塊提供了在給定的URL地址數(shù)據(jù)的功能,同時(shí)也可以通過(guò)字符串的編碼、來(lái)確保它們是有效URL字符串的一部分。我們接下來(lái)要談的功能包括urlopen(),urlretrieve(),quote(),unquote(),quote_plus(),unquote_plus(),和urlencodeurlopen(urlstr,urlopen()打開(kāi)urlstr所指向的URL如果沒(méi)有給定協(xié)議或者規(guī)劃或者文件規(guī)劃早已傳入對(duì)于所有的HTTP請(qǐng)求,常見(jiàn)的請(qǐng)求類(lèi)型是“GET情況中,向Web服務(wù)器發(fā)送的請(qǐng)求字符串(編碼鍵值或,如urlencode()函數(shù)的字符串輸出[如下])應(yīng)該是urlstr的一部分。我們?cè)谙逻呉矔?huì)討論。GETPOSTWeb一旦連接成功,urlopen()將會(huì)返回一個(gè)文件類(lèi)型對(duì)象,就像在目標(biāo)路徑下打開(kāi)了一個(gè)可讀文件。例如,如果我們的文件對(duì)象是f,那么我們的“句柄”將會(huì)支持可讀方法如:f.read(),f.readline(),f.readlines(),f.close()f.fileno().此外,()方法可以返回MIME(MultipurposeInternetMailExtension,多目標(biāo)因特HTML(HyperTextMarkupLanguage,超文本標(biāo)記語(yǔ)言,純文本文件,生成(指ExpertsGroup)或者GIF(GraphicsInterchangeFormat)文件。其他的如多文件,特殊類(lèi)型文件需要通過(guò)擴(kuò)展的應(yīng)用程序才能打開(kāi)。Table20.4urllib.urlopen()File-likeObjectMethodsurlopen()對(duì)象方法描述 f fURL 這些文件類(lèi)型對(duì)象的方法在表20.4中有描述。 邊是urlretrieve()的語(yǔ)法:urlretrieve(urlstr,localfile=None,除了像urlopen()這樣從URL中內(nèi)容,urlretrieve()可以方便地將urlstr定位到的整個(gè)如果可能,downloadStatusHook這個(gè)函數(shù)將會(huì)在每塊數(shù)據(jù)或傳輸完成后被調(diào)用。調(diào)用時(shí)使urlretrieve()返回一個(gè)2-元組,(filename,mime_hdrs).filename是包含數(shù)據(jù)的本地文件名,mime_hdrs是對(duì)Web服務(wù)器響應(yīng)后返回的一系列MIME文件頭。要獲得的信息,可以看milsMessagemime_hdrs是空的。介紹urlretrieve()更的應(yīng)用。urllib.quote()andquote*URLURL的或者不被Web服務(wù)器作為有效URL接收的特殊字符串必須被轉(zhuǎn)換。這就是quote*()函數(shù)的功能。quote(urldata,逗號(hào),下劃線,,斜線和字母數(shù)字這類(lèi)符號(hào)是不需要轉(zhuǎn)化。其他的則均需要轉(zhuǎn)換。另外,那些不被允許的字符前邊會(huì)被加上百分號(hào)(%)同時(shí)轉(zhuǎn)換成16進(jìn)制,例xxxx”代表這個(gè)字母的ASCII碼的十六進(jìn)制值。當(dāng)調(diào)用quote*()時(shí),urldata字符串被轉(zhuǎn)換成了一個(gè)可在URL字符串中使用的等價(jià)值。safe(/).quote_plus()與quote()很像,另外它還可以將空格編碼成+號(hào)。下邊是一個(gè)使用quote()和>>>name='joe>>>number=>>>base=>>>final='%s?name=%s&num=%d'%(base,name,>>>mama&num=6'>>>'http:%3a//www/%7efoo/cgi->>>urllib.quote_plus(final)urllib.unquote()式的字母都轉(zhuǎn)換成它們的ASCII碼值。Unquote*()的語(yǔ)法如下:調(diào)用unquote()函數(shù)將會(huì)把urldata中所有的URL-編碼字母都,并返回字符串在1.5.2版的Python中,urlopen()函數(shù)接收字典的鍵-值對(duì),并將其編譯成CGI請(qǐng)求的URL字符串的一部分。鍵值對(duì)的格式是“鍵=值”,以連接符(&)劃分。更進(jìn)一步,鍵和它們的值被傳到quote_plus()函數(shù)中進(jìn)行適當(dāng)?shù)木幋a。下邊是urlencode()輸出的一個(gè)例子:>>>aDict={'name':'GeorginaGarcia','hmdir':'~ggarcia'>>>urllib.urlencode(aDict)urllib和urlparse還有一些其他的功能,在這里我們就不一一概述了。閱讀相關(guān)文檔可以獲得接字層支持在1.6版中urllib模塊通過(guò)接字層(SSL)支持開(kāi)放的HTTP連接.socket模塊的變化是增加并實(shí)現(xiàn)了SSL。隨后,urllib和httplib模塊被上傳用于支持URL在“https”連接規(guī)劃中的SSLimaplib,poplibsmtplibTable20.5CoreurllibModuleFunctionsurllib函數(shù) postQuery- local- 將URLurlstr定位的文件到localfile或臨時(shí)文件中(localfile將會(huì)獲得的統(tǒng)計(jì)信息 將urldata中編碼后的字母 除了將加好轉(zhuǎn)換成空格后其他功能與unquote()相似。 將字典鍵-值對(duì)編譯成有效的CGI請(qǐng)求字符串,用quote_plus()urllib2模名和)需求的Web站點(diǎn)。最簡(jiǎn)單的“獲得已驗(yàn)證參數(shù)”的方法是使用前邊章節(jié)中描述的URL部件net_loc,也就是說(shuō):這種解決方案的問(wèn)題是不具有可編程性。然而使用urllib2,我們可以通過(guò)兩種不同的方式來(lái)解決這個(gè)問(wèn)題。我們可以建立一個(gè)基礎(chǔ)認(rèn)證處理器(urllib2.HTTPBasicAuthHandler),同時(shí)在基本URL冊(cè)一個(gè)登錄,這就意味著我們?cè)赪eb站點(diǎn)上定義了個(gè)安全區(qū)域。(關(guān)于域的信息可以查看開(kāi)所有的URL。另一個(gè)可選的辦法就是當(dāng)瀏覽器提示的時(shí)候,輸入用戶(hù)名和,這樣就發(fā)送了一個(gè)帶有適當(dāng)用戶(hù)請(qǐng)求的認(rèn)證頭。在20.1的例子中,我們可以很容易的區(qū)分出這兩種方法。1–79–15行器被用于建立一個(gè)URL-opener,并安裝它以便所有已打開(kāi)的URL能用到這些認(rèn)證信息。這段代碼和urllib2模塊的Python文檔是兼容的。Example20.1HTTPAuthClientThisscriptusesbothtechniquesdescribedaboveforbasic1#!/usr/bin/env2import4LOGIN=PASSWD=URL=8deffromurlparseimporturlparseas11hdlr=urllib2.HTTPBasicAuthHandler()hdlr.add_password('Archives',up(url)[1],LOGIN,opener=returndeffrombase64importreq=b64str=encodestring('%s:%s'%(LOGIN,PASSWD))[:-req.add_header("Authorization","Basic%s"%returnforfuncTypein('handler',print'***Using%s:'%url=f=print17–22行這段代碼的“request”版本創(chuàng)建了一個(gè)Request對(duì)象,并在HTTP請(qǐng)求中添加了基本的base64編碼認(rèn)證頭信息。返回“main”后(譯者注:指for循環(huán))調(diào)用urlopen()時(shí),該請(qǐng)求被用來(lái)替換其中的URL字符串。注意原始URL內(nèi)建在Requst對(duì)象中,正因?yàn)槿绱嗽陔S后的urllib2.urlopen()中調(diào)用中替換URL字符串才不會(huì)產(chǎn)生問(wèn)題。這段代碼的靈感來(lái)自于MikeFoordLeeHarrPythonCookbook上的回復(fù),具置在: /ASPN/Cookbook/Python/Recipe/26719724–29一行(舍棄了其他行HTTPHTML$pythonurlopen-auth.pyUsinghandler:Using高級(jí)Web客戶(hù)

Web瀏覽器是基本的Web客戶(hù)端。主要用來(lái)在Web上查詢(xún)或者文件。而Web的高級(jí)客戶(hù)端并高級(jí)Web客戶(hù)端的一個(gè)例子就是網(wǎng)絡(luò)爬蟲(chóng)(aka蜘蛛和機(jī)器人。這些程序可以基于不同目的在因 脫機(jī)瀏覽—將文檔到本地,重新設(shè)定超,為本地瀏覽器創(chuàng)建鏡像我們下邊介紹網(wǎng)絡(luò)爬蟲(chóng):crawl.py,抓取Web的開(kāi)始頁(yè)面地址(URL,該頁(yè)面和其它后續(xù)鏈接頁(yè)面,但是僅限于那些與開(kāi)始頁(yè)面有著相同的頁(yè)面。如果沒(méi)有這個(gè)限制的話,你的硬盤(pán)將會(huì)被耗盡!crwal.py的代碼在例子20.2中展示。1–1113–49行Retriever類(lèi)的責(zé)任是從Web頁(yè)面,解析每個(gè)文檔中的并在必要的時(shí)候把它們加入法展現(xiàn)了它的功能:構(gòu)造器(init()、filename()、download()parseAndGetLinks()。filename(URL找出安全、有效的相關(guān)文件名并在本地。大體上說(shuō),它會(huì)去掉URL的“http://”前綴,使用剩余的部分作為文件名,并創(chuàng)建必要的文件夾路徑。那些沒(méi)有“index.htm構(gòu)造器實(shí)例化了一個(gè)Retriever對(duì)象,并把URL和通過(guò)filename()獲得的相應(yīng)文件名都作為本Example20.2AdvancedWebClient:aWebCrawler載的Web頁(yè)面(Retriever。1#!/usr/bin/envpython3fromsysimportfromosimportmakedirs,unlink,fromos.pathimportdirname,exists,isdir,fromstringimportreplace,find,fromhtmllibimportfromurllibimportfromurlparseimporturlparse,fromformatterimport fromcStringIOimportStringIO classRetriever(object):#downloadges init(self,self.url=self.file=self.filename(url)deffilename(self,url,parsedurl=urlparse(url,'http:',0)##parsepath=parsedurl[1]+ext=ifext[1]=='':#nofile,useifpath[-1]==path+=path+='/'+ldir=dirname(path)#localifsep!= #os-indep.pathldir=replace(ldir,'/',ifnotisdir(ldir):#createarchivedirifexists(ldir):returndefdownload(self):#downloadretval=urlretrieve(self.url,exceptretval=('***ERROR:invalidURL"%s"'returndefparseAndGetLinks(self):#parseHTML,self.parser= return classCrawler(object):#manageentirecrawlingprocess count=0#staticdownloadedpagecounter init(self,self.q=self.seen=self.dom=defgetPage(self,r=retval=ifretval[0]=='*':#errorsituation,doprintretval,'...ski6566Crawler.count+=67print'\n(',Crawler.count,68print'URL:', print'FILE:', links=r.parseAndGetLinks()#getandprocessforeachLinkinifeachLink[:4]!='http'andfind(eachLink,'://')==-eachLink=urljoin(url,print'*',eachLink,iffind(lower(eachLink),'mailto:')!=-print'...discarded,mailtoifeachLinknotiniffind(eachLink,self.dom)==-print'...discarded,notinifeachLinknotinprint'...new,addedtoprint'...discarded,alreadyinprint'...discarded,alreadyprocessed'defgo(self):#processlinksinwhileurl=defiflen(argv)>url=url=raw_input('EnterstartingURL:106 except(KeyboardInterrupt, url=''ifnoturl:robot= =='main正如你,download()方法實(shí)際會(huì)連上網(wǎng)絡(luò)去給定的頁(yè)面。它使用URL調(diào)用urllib.urlretrieve()函數(shù)并把結(jié)果保存在filename中(該值由filename()返回如果成功,如果Crawler判定沒(méi)有錯(cuò)誤發(fā)生,它會(huì)調(diào)用parseAndGetLinks()方法來(lái)解析新的頁(yè)面并決定51-98 它就變短,在的頁(yè)面中發(fā)現(xiàn)新的則會(huì)讓它變長(zhǎng)。Crawler包含的另兩個(gè)數(shù)值是seen,一個(gè)所有“我們已看過(guò)(已)的的列表,和dom,我們把主的在這里,并用這個(gè)值來(lái)判定后續(xù)是否是該域的一部分。目。每有一個(gè)頁(yè)面成功它就會(huì)增加。除了構(gòu)造器Crawler還有其他兩個(gè)方法,getPage()和go()。go()只是簡(jiǎn)單的啟動(dòng)Crawler,它而這個(gè)的真正工作者,卻是getPage()方法。成功,計(jì)數(shù)器會(huì)增加并且會(huì)被加到“已看”列表。它會(huì)反復(fù)地檢查每個(gè)已頁(yè)面中的所有鏈接并是否有要被加入待隊(duì)列。go()中的主循環(huán)會(huì)不停的推進(jìn)處理過(guò)程直到隊(duì)列為空,在擴(kuò)充隊(duì)列時(shí)都會(huì)被忽略掉。100-114被直接調(diào)用時(shí),它就會(huì)使用這個(gè)指定的。否則,進(jìn)入交互模式,提示用戶(hù)輸入起始URL。crawl.py的例子如下所示:%Enterstarting (1 home/overview.html...new,addedtohome/synopsis.html...new,addedtohome/order.html...new,addedto ...discarded,mailtohome/overview.html...discarded,alreadyinhome/synopsis.html...discarded,alreadyinhome/order.html...discarded,alreadyin ...discarded,mailtoindex.html...discarded,notin(2 ...discarded,mailtohome/index.html...discarded,alreadyhome/synopsis.html...discarded,alreadyinhome/overview.html...discarded,alreadyin(3 home/synopsis.htmlFILE:home/index.html...discarded,alreadyhome/order.html...discarded,already* home/overview.html...discarded,alreadyin(4 home/overview.htmlFILE:home/synopsis.html...discarded,alreadyhome/index.html...discarded,alreadyhome/synopsis.html...discarded,alreadyhome/order.html...discarded,already CGI:幫助Web服務(wù)器處理客戶(hù)端數(shù)據(jù)CGI 性在于它對(duì)超文本的兼容性,文本以一種或者是高亮的形式指向另外一個(gè)相關(guān)文檔??梢酝ㄟ^(guò)鼠標(biāo)Web用戶(hù)那里獲得特蘇信息的唯一形式(Javaapplets。反過(guò)來(lái),在客戶(hù)提交了特定數(shù)據(jù)后,就要求立即生成HTML頁(yè)面?,F(xiàn)在Web服務(wù)器僅有一點(diǎn)做的很不錯(cuò),獲取用戶(hù)對(duì)文件的請(qǐng)求,并將這個(gè)文件(也就是說(shuō)HTML文件)返回給客戶(hù)端。它們現(xiàn)在還不具有處理字段類(lèi)特殊數(shù)據(jù)的機(jī)制。將這些請(qǐng)求送到可以生成動(dòng)態(tài)HTMLWeb這整個(gè)過(guò)程開(kāi)始于Web服務(wù)器從客戶(hù)端接到了請(qǐng)求(GET或者POST)并調(diào)用合適的程序。然后開(kāi)始等待HTML頁(yè)面—與此同時(shí),客戶(hù)端也在等待。一旦程序完成,會(huì)將生成的動(dòng)態(tài)HTML頁(yè)面返CG(Common客戶(hù)端輸入給Web服務(wù)器端的表單可能包括處理過(guò)程和一些在數(shù)據(jù)庫(kù)中的表單需要記住的是,在任何時(shí)候都可能有任何一個(gè)用戶(hù)去填寫(xiě)這個(gè)字段,或者點(diǎn)擊提交按鈕或者,這更CGI創(chuàng)建HTML的CGI應(yīng)用程序通常是用高級(jí)編程語(yǔ)言來(lái)實(shí)現(xiàn)的,可以接受、處理數(shù)據(jù),向服務(wù)器端HTMLPerl,PHP,C/C++,Python。WebC/C++WebAphachePostgreSQL,Java(Tomcat,PH塊,以及SSL/security。然而,如果你工作在私人小型的或者小組織的Web上的話就沒(méi)有必要使用這種強(qiáng)大而復(fù)雜的Web服務(wù)器,CGI是一個(gè)適用于小型Web開(kāi)發(fā)的工具。更進(jìn)一步來(lái)有很多Web應(yīng)用程序開(kāi)發(fā)框架和內(nèi)容管理系這些都彌補(bǔ)了過(guò)去CGI的不足。CGI執(zhí)行拷貝,并提供了一個(gè)有效的HTML做為最終的客戶(hù)端輸出。因此,為了開(kāi)發(fā)更加高效的Web服務(wù)有必要理解CGI實(shí)現(xiàn)的基本原理。CGI應(yīng)用程當(dāng)一個(gè)CGI開(kāi)始執(zhí)行時(shí),它需要檢索用戶(hù)-支持表單,但這些數(shù)據(jù)必須要從Web的客戶(hù)端才可以這些不同于標(biāo)準(zhǔn)輸出的輸出將會(huì)返回到連接的Web客戶(hù)端,而不是返回到屏幕、CUI窗口或者硬盤(pán)上返回來(lái)的數(shù)據(jù)必須是具有一系列有效頭文件的HTMLWeb的客戶(hù)端,由于瀏覽器只能識(shí)別有效的HTTP數(shù)據(jù)(也就是MIME都問(wèn)價(jià)和HTML),那么返回的也只能是個(gè)錯(cuò) ,We在cgi模塊中有個(gè)主要類(lèi):FieldStorage類(lèi),它完成了所有的工作。在PythonCGI開(kāi)始時(shí)Web(Web)讀出有關(guān)的用戶(hù)信息。一旦這個(gè)對(duì)象對(duì)于簡(jiǎn)單的Web表單,你將會(huì)經(jīng)常發(fā)現(xiàn)所有的MiniFieldStorage實(shí)例。下邊包含的所有的例子建立CGI應(yīng)用程20.5.1建立Web服務(wù)器為了可以用Python進(jìn)行CGI需要安裝一個(gè)Web以處理PythonCGI請(qǐng)求的模式,然后讓你的Web服務(wù)器CGI。其中有些操作你也許需要獲得系統(tǒng)管理員的如果你需要一個(gè)真正的Web服務(wù)器,可以并安裝Aphache。Aphache的插件或模塊可以處理PythonCGI,但這在我們的例子里并不是必要的。如果你準(zhǔn)備把自己的服務(wù)"帶入真實(shí)世界",也許會(huì)階段獲得知識(shí),你也可以現(xiàn)在提前閱讀那部分。然而,這并不是本章的焦點(diǎn)。$python-m這將會(huì)在當(dāng)前機(jī)器的當(dāng)前下建立一個(gè)端為8000的Web服務(wù)器。然后可以在啟動(dòng)這個(gè)服務(wù)器的下建立一個(gè)Cgi–bin,將PythonCGI放到那里將一些HTML文件放到那個(gè)下,或許有些.pyCGI在Cgi-bin中,然后就可以在地址欄中輸入這些地址來(lái)Web站點(diǎn)啦。正如你可以在代碼中看到的一樣,這個(gè)表單包括兩個(gè)輸入變量:和howmany,這兩個(gè)值將會(huì)被傳到我們的CGIfriends1.py中。你會(huì)注意到在例子中CGI初始化到主機(jī)默認(rèn)的cgi-bin(“Action連接(如果這個(gè)信息與你開(kāi)發(fā)環(huán)境不一樣的話,在測(cè)試Web頁(yè)面和CGI之前請(qǐng)更新你的表單事件。同時(shí)由于表單事件中缺少M(fèi)ETHOD子,所有的請(qǐng)求將會(huì)采用默認(rèn)的GET方法。選擇GET方法是因?yàn)槲覀儯╝k“AddressTo)Example20.3StaticFormWge12FriendsCGIDemo(static34<BODY><H3>Friendslistfor:<I>NEW5<FORMACTION="/cgi-6<B>Enteryour7<INPUTTYPE=text VALUE="NEWUSER"8<P><B>Howmanyfriendsdoyou<INPUTTYPE=radioNAME=howmanyVALUE="0"CHECKED><INPUTTYPE=radioNAME=howmanyVALUE="10"><INPUTTYPE=radioNAME=howmanyVALUE="25"><INPUTTYPE=radioNAME=howmanyVALUE="50"><INPUTTYPE=radioNAME=howmanyVALUE="100"><P><INPUT 按下回車(chē)鍵獲得相同的效果)當(dāng)這些發(fā)生后,在例20.4中的,friends1.py將會(huì)隨CGI一起Python(14-17。表單的變量FieldStorage實(shí)例,包含howmanyh的值。我們把這些值本分別存入Python的who和howmany變量中。變量reshtml包含需要返回的HTML文本的正文,還有一些Example20.4ResultsScreenCGIcode 1#!/usr/bin/env25reshtml='''Content-Type:67FriendsCGIDemo(dynamic8<BODY><H3>Friendslistfor:Yournameis:Youhave<B>%s</B>form=who= howmany=printreshtml%(who,who,提示:HTML頭文件是從HTML中分離出來(lái)的。有一點(diǎn)需要向CGI初學(xué)者指明的是,在向CGI返回結(jié)果時(shí),須先返回一個(gè)適當(dāng)?shù)腍TTP頭文件后才會(huì)返回結(jié)果HTML頁(yè)面了區(qū)分這些頭文件和結(jié)果HTML頁(yè)面friends1.py的20-6erickallen”,單擊“10friends”單選按鈕。這次的屏幕鏡像圖展示的是在WindowsIE3瀏覽器的效果。Web注意GET請(qǐng)求是如何將表單中的變量和值加載在URL地址條觀察到了friends.htm頁(yè)而friends.py輸出到屏幕上的則是“dynamic”?我們這樣做的一個(gè)原因就是:指明生成表單和結(jié)果頁(yè)面 1-5除了通常的起始、和模塊導(dǎo)入行,我們還把HTTPMIMIHTML正文部分分離出來(lái),放在了這里。因?yàn)樵诜祷氐膬煞N頁(yè)面(表單頁(yè)面和結(jié)果頁(yè)面)中都使用它,而又不想重復(fù)寫(xiě)文本。當(dāng)需要輸出時(shí),把這個(gè)頭字串加在相應(yīng)的HTML正文中。7-29所有這些代碼都是為了整合CGI里的friends.htm表單頁(yè)面。我們對(duì)表單頁(yè)面的文本使用一個(gè)變量formhtml,還有一個(gè)用來(lái)創(chuàng)建單選按鈕的字符串變量fradio。我們從friends.htm了這個(gè)單選按鈕HTML文本,但我們意在展示如何使用Python來(lái)生成的動(dòng)態(tài)輸出—見(jiàn)22-27行的for循環(huán)。20.5生成表單和結(jié)果頁(yè)面將friends.html和friends1.py合并成friends2.py。得到的可以同時(shí)顯示表單和動(dòng)態(tài)生HTML結(jié)果頁(yè)面,同時(shí)可以巧妙的知道應(yīng)該輸出哪個(gè)頁(yè)面。1#!/usr/bin/env23import45header='Content-Type:text/html\n\n'formhtml=FriendsCGI<BODY><H3>Friendslistfor:<I>NEW<FORMACTION="/cgi-<B>Enteryour<INPUTTYPE=hiddenNAME=action<INPUTTYPE=text VALUE="NEWUSER"<P><B>Howmanyfriendsdoyou<P><INPUT18fradio='<INPUTTYPE=radioNAME=howmanyVALUE="%s"%s>%s\n'deffriends=foriin[0,10,25,50,checked=ifi==checked=friends=friends+fradio%(str(i),checked,str(i))31reshtml=32FriendsCGI33<BODY><H3>Friendslistfor:34Yournameis:35Youhave<B>%s</B>3638defdoResults(who,39printheader+reshtml%(who,who,howmany)41def42form=43if 44who= 4546who='NEW48if49howmany=5051howmany=53if54doResults(who,555658 =='main5912action“hidden”變量,這一行代碼里(18)更新單選按鈕的布局和/或它們的值,而不用再寫(xiě)多行文字。這也同時(shí)提供了的靈活性,可以用邏輯來(lái)判斷哪個(gè)單選按鈕被選中—見(jiàn)我們的下一個(gè)升級(jí)版,后面的現(xiàn)在你或許會(huì)想“既然我也可以選擇howmany那為什么我們要用一個(gè)變量呢?”這是一個(gè)很好的問(wèn)題,因?yàn)樵谶@種情況下你當(dāng)然可以只用hwomany創(chuàng)立action的另一個(gè)原因是 31-39 41-56因?yàn)檫@個(gè)也以、也許不能取得所期待的字段(例如,第一次運(yùn)行時(shí)生成一個(gè)表單第53-56行作了這種判定。20-5全面交互的Web站 我們最后一個(gè)例子將會(huì)完成這個(gè)循環(huán)。如面中,用戶(hù)在表單頁(yè)中輸入他/信息,然后我現(xiàn)在在例子20.6中我們展示我們最后的更新,friends3.py。810-1969-7175-82表單,但不需要有動(dòng)作因?yàn)槲覀冎皇呛?jiǎn)單的后退到瀏覽器歷史中的上一個(gè)頁(yè)面。盡管我們的目為了以后還可以繼續(xù)開(kāi)發(fā)這個(gè) ,給它增 的錯(cuò)誤檢測(cè)20.6Web1#!/usr/bin/env23import4fromurllibimport7header='Content-Type:8url='/cgi-bin/friends3.py'errhtml=FriendsCGI<FORM><INPUTTYPE=buttondefformhtml=FriendsCGI<BODY><H3>Friendslistfor:<FORM<B>Your<INPUTTYPE=hiddenNAME=action<INPUTTYPE=text VALUE="%s"<P><B>Howmanyfriendsdoyou<P><INPUT32fradio='<INPUTTYPE=radioNAME=howmanyVALUE="%s"defshowForm(who,friends=foriin[0,10,25,50,checked=ifstr(i)==checked=friends=friends+fradio%(str(i),checked,printheader+formhtml%(who,url,who,friends)reshtml=FriendsCGI<BODY><H3>Friendslistfor:Yournameis:Youhave<B>%s</B><P>Click<AHREF="%s">here</A>toedityourdatadefdoResults(who,newurl=url+'?action=reedit(quote_plus(who),deferror=form=cgi.FieldStorage()if who= who='NEWifhowmany=ifform.has_key('action')andform['action'].value==error='Pleaseselectnumberof73howmany=0ifnotifform.has_key('action')andform['action'].value!=doResults(who,showForm(who,84 =='main8527,38-41,49,52-55這個(gè)的一個(gè)目的是創(chuàng)建一個(gè)有意義的,以便從結(jié)果頁(yè)面返回表單頁(yè)面。當(dāng)有錯(cuò)誤發(fā)生時(shí),用戶(hù)可以使用這個(gè)返回表單頁(yè)面去更新他/她填寫(xiě)的數(shù)據(jù)。新的表單頁(yè)面只有當(dāng)它包含了用一個(gè)值。這個(gè)值如果給出的話,會(huì)入到name字段。顯然地,在初始表單頁(yè)面上它將是空值。第41我們根據(jù)當(dāng)前選定的朋友數(shù)目設(shè)置了單選按鈕。最后,通過(guò)第49行和52-55行更新了的doResults()函數(shù),我們創(chuàng)建了這個(gè)包含已有信息的,它會(huì)讓用戶(hù)“返回”到我們更改后的表單62friends1.pyfriends2.py頁(yè)面。我們加了一個(gè)對(duì)string.capwords()函數(shù)的調(diào)用從而自動(dòng)的將用戶(hù)名置成大寫(xiě)。capwords()同時(shí)故意忘記檢查單選按鈕。單擊Submit按鈕后將會(huì)返回錯(cuò)誤頁(yè)面,請(qǐng)看第二個(gè)截屏圖20-10. 20-10Friends(無(wú)效的用戶(hù)輸入)Camino(Friends3.py)是現(xiàn)在在頁(yè)面底部有個(gè)額外的連接。這個(gè)連接將會(huì)把我們帶到表單頁(yè)面。新表單頁(yè)面和最初的頁(yè)面20-12.HTMLPythonHTMLgen模塊的連接,HTMLgen是Python的一個(gè)擴(kuò)展模塊,于生成HTML頁(yè)面。(friends3.py)CGI中使Unicode編子 為了看到Unicode的作用,會(huì)用CGI生成一個(gè)多語(yǔ)言功能的Web頁(yè)面。首先我們用Unicode字符串定義一些消息。我們假設(shè)你的編輯器只能輸入ASCII編碼。因此,非ASCII編碼的字符使用\u轉(zhuǎn)義符輸入。實(shí)際上從文件或數(shù)據(jù)庫(kù)中也能這些消息。#GreetinginEnglish,#ChineseandJapanese. O=u"""CGI產(chǎn)生的第一個(gè)頭信息內(nèi)容類(lèi)型(content-type)是HTTP。此處還了消息是以UTF-print'Content-type:text/html;charset=UTF-print20.7UnicodeCGI1#!/usr/bin/env23CODEC='UTF-4UNICODEO=5678911print'Content-Type:text/html;charset=%s\r'%12print13print'<HTML><HEAD><TITLE>UnicodeCGI14print15print 16print例20.7中顯示了完整的程序。 現(xiàn)在我們來(lái)看看CGI編程的高級(jí)方面。這包括的使用(保存在客戶(hù)端的緩存數(shù)據(jù),同一個(gè)CGI字段的多重值,和用multipart表單實(shí)現(xiàn)的文件上傳。為了節(jié)省空間,會(huì)在同一個(gè)Mulitipart目前,CGI特別只允許兩種表單編碼,“application/x-www-form-urlencoded”和<FORMenctype="application/x-www-form-urlencoded"<FORMenctype="multipart/form-data"在表單提交時(shí)你可以使用任一種編碼,但在目前上傳的文件僅能表現(xiàn)為multipart<INPUTtype=file這個(gè)指令表現(xiàn)為一個(gè)空的文本字段,同時(shí)旁邊有個(gè)按鈕,可以讓你瀏覽文件系統(tǒng),找到multipart的。同時(shí)還需要有一個(gè)單獨(dú)的編碼,因?yàn)樗€沒(méi)有聰明到“通過(guò)URL編碼”的程度,尤其是對(duì)不論你使用的是默認(rèn)編碼還是multipart編碼,cgi模塊都會(huì)以同樣的方式來(lái)處理它們,在表單提交時(shí)提供鍵和相應(yīng)的值。你還可以像以前那樣通過(guò)FieldStorage實(shí)例來(lái)數(shù)據(jù)。 MiniFielStorage由于HTTP是一個(gè)“無(wú)狀態(tài)信息”的協(xié)議,如你在本章最開(kāi)始看到的截圖一樣,是通過(guò)GET請(qǐng)求中的鍵值對(duì)來(lái)完成信息從一個(gè)頁(yè)面到另一個(gè)頁(yè)面的傳遞。實(shí)現(xiàn)這個(gè)功能的另外法如我們以前看到的一樣,是使用隱藏的表單字段,如在后期friends.py中對(duì)action變量的處理。這些還有一種可以保持對(duì)多個(gè)頁(yè)面瀏覽連續(xù)性的方法就是在客戶(hù)端保存這些數(shù)據(jù)。這就是引進(jìn)的原因。服務(wù)器可以向客戶(hù)端發(fā)送一個(gè)請(qǐng)求來(lái)保存 ,而不必用在返回的Web頁(yè)面中嵌入數(shù)據(jù)的方法來(lái)保持?jǐn)?shù)據(jù)。連接到最初的服務(wù)器的主域上(這樣一個(gè)服務(wù)器就不能設(shè)置或性,如域子路徑,安全傳輸請(qǐng)求。有了coockies,我們不再需要為了用戶(hù)而將數(shù)據(jù)從一頁(yè)傳到另一頁(yè)了。雖然這在隱私問(wèn)題上也了大量的爭(zhēng)論,多數(shù)Web站點(diǎn)還是合理地使用了。為了準(zhǔn)備代碼,在客戶(hù)端獲得請(qǐng)求文件前,Web服務(wù)器向客戶(hù)端發(fā)送“Set”頭文件要求客戶(hù)端一旦在客戶(hù)端建立了,HTTP_環(huán)境變量會(huì)將那些自動(dòng)放到請(qǐng)求中發(fā)送給串(也就是說(shuō),使用str.split()或者手動(dòng)解析。以分號(hào)(;)分隔,每個(gè)鍵-值對(duì)中間都由等和multipart編碼一樣,同樣于網(wǎng)景,他們實(shí)現(xiàn)了 用至今,在下邊的Web站點(diǎn)中你可以接觸這些文檔: 一旦標(biāo)準(zhǔn)化以后,這些文檔最終都被了,你可以從評(píng)論請(qǐng)求文檔(RFCs)中獲得更多現(xiàn)在的信息?,F(xiàn)今發(fā)布的的的文件是RFC2109.使用高級(jí)CGIadvcgi.pyfriends3.py的差別不是很大。默認(rèn)的第一頁(yè)是用戶(hù)填寫(xiě)的表單,它由四個(gè)主要部分組成:用戶(hù)設(shè)置字符串,字段,編程語(yǔ)言復(fù)選框列表,文件提交框。在圖20-14中可以看到示圖。圖“Browse.“Choose”,“...”等。mutipartFieldStorage由于這是服務(wù)器端第一次接到數(shù)據(jù),這時(shí),當(dāng)我們向客戶(hù)端返回結(jié)果頁(yè)面時(shí),我們使用“Set:”頭文件來(lái)捕獲瀏覽器端的。 20-14IE5MacOSX如果我們單擊下方的那個(gè),沒(méi)有任何表單數(shù)據(jù)提交給我們的,因此會(huì)顯示一個(gè)表單頁(yè)藏或者作為URL中的請(qǐng)求參數(shù))?實(shí)際上是這些數(shù)據(jù)都被保存在客戶(hù)端的 當(dāng)檢測(cè)到表單沒(méi)有數(shù)據(jù)時(shí),它會(huì)返回一個(gè)表單頁(yè)面,但是在表單頁(yè)面建立前,它們從客戶(hù)端的中抓取了數(shù)據(jù)(當(dāng)用戶(hù)在單擊了那個(gè)的時(shí)候?qū)?huì)自動(dòng)傳入)并且相應(yīng)的將其填入表單中。因此當(dāng)表單最終顯示出來(lái)時(shí),先前的輸入便會(huì)魔術(shù)般的顯示在用戶(hù)面前(20-18。 advcgi.py和我們本章前部分提到的CGIfriends3.py相當(dāng)?shù)南瘛K斜韱雾?yè)、結(jié)果頁(yè)、錯(cuò)誤頁(yè)可以返回。新的中除了有所有的高級(jí)CGI特性外,我們還在中增加了的面向?qū)ο?0-16CGI提交演示Opera8Win32系統(tǒng)1-7象,所以這個(gè)字符串與打開(kāi)一個(gè)文件并使用文件句柄去數(shù)據(jù)很相似。 圖圖20–17ResultspagegeneratedandreturnedbytheWebserverinOpera4on9-12在AdvCGI類(lèi)之后,header和url(靜態(tài))變量被創(chuàng)建出來(lái),在顯示所有不同頁(yè)面的方法中14-80所有這個(gè)塊中的代碼都是用來(lái)創(chuàng)建、顯示表單頁(yè)面的。那些數(shù)據(jù)屬性都是不言自明的。getCPP()取得Web客戶(hù)端發(fā)來(lái)的信息,而showForm()校對(duì)所有這些信息并把表單頁(yè)面 圖圖20–18 FormpagewithdataloadedfromtheClient82-91行93-144結(jié)果頁(yè)面的生成使用了本塊代碼。setCPP()方法要求客戶(hù)端為我們的應(yīng)用程序,而doResults()方法所有數(shù)據(jù)并把輸出發(fā)回客戶(hù)端。Example20.8AdvancedCGIApplication也可以從客戶(hù)端(Web瀏覽器)讀寫(xiě)。1#!/usr/bin/env2fromcgiimportfromosimportfromcStringIOimportfromurllibimportquote,fromstringimportcapwords,strip,split,join9class11header='Content-Type:formhtml=AdvancedCGI<BODY><H2>AdvancedCGIDemo<FORMMETHOD=postACTION="%s"ENCTYPE="multipart/form-<H3>My<LI><CODE><B>CPPuser=<H3>Enter<INPUTNAME=value="%s"><H3>Enteryour<INPUT VALUE="%s"><H3>Whatlanguagescanyouprogram(<I>atleastone<H3>Enterfileto<INPUTTYPE=fileNAME=upfileVALUE="%s"<P><INPUTlangSet=('Python','PERL','Java','C++','C',langItem='<INPUTTYPE=checkboxNAME=langVALUE="%s"%s>%s\n'def s(self):# sfromif foreacinmap(strip,split(environ['HTTP'],iflen(eac)>6andeac[:3]==tag=eacselfs[tag]=eval(unquote(eacexcept(NameError,selfs[tag]=unquote(eacself.s['info']=selfs['user']=''ifselfs['info']!=self.who,langStr,self.fn=split(selfs['info'],self.langs=split(langStr,self.who=self.fn='self.langs=['Python']defshowForm(self):#showfill-outself.getCPlangStr=foreachLanginifeachLanginlangStr+=AdvCGI.langItem%(eachLang,'CHECKED',langStr+=AdvCGI.langItem%(eachLang,'',eachLang)ifnotselfs.has_key('user')orselfs['user']==cookStatus='<I>hasnotbeensetuserCook=userCook=cookStatus=self printAdvCGI.header+AdvCGI.formhtml%cookStatus,userCook,self.who,langStr,self.fn)errhtml=AdvancedCGI<FORM><INPUTTYPE=buttondefprintAdvCGI.header+AdvCGI.errhtml%(self.error)reshtml=AdvancedCGI<BODY><H2>YourUploaded<H3>Yourvalueis:<H3>Yournameis:<H3>Youcanprograminthefollowing<H3>YouruploadedName:Click<AHREF="%s"><B>here</B></A>toreturntodefsetCPPs(self):#lclienttosfor inselfprint'Set:CPP%s=%s;path=/'%(eac, defdoResults(self):#displayresultsMAXBYTES=langlist=foreachLanginlanglist=langlist+'<LI>%s<BR>'%filedata=119whilelen(filedata)<MAXBYTES:#readfiledata=ifdata=='':filedata+=else:#truncateiftoofiledata+='...<B><I>(filetruncatedduetoiffiledata==filedata=<B><I>(fileuploaderrororfilenotifnotselfs.has_key('user')orselfs['user']==cookStatus='<I>hasnotbeensetuserCook=137userCook=cookStatus=selfs['user']139selfs['info']=join([self.who,140join(self.langs,','),filename],141self.setCP142printAdvCGI.header+AdvCGI.reshtml%143(cookStatus,self.who,144filename,filedata,AdvCGI.url)146defgo(self):#determinewhichpageto147selfs=148self.error=149form=150ifform.keys()==151152154if 155self.who=capwords(strip(form[156ifself.who==157self.error='Yournameisrequired.158159self.error='Yournameisrequired.161ifform.has_key(162selfs['user']=163form[164165selfs['user']=''self.langs=iflangdata=iftype(langdata)==foreachLanginself.error='Atleastonelanguagerequired.'ifupfile=self.fn=upfile.filenameorifself.fp=self.fp=StringIO('(noself.fp=StringIO('(noself.fn=''ifnot194 =='main195page=196146-196格的基于過(guò)程編寫(xiě)的程序不同。go()方法中包含所有新到的數(shù)據(jù)并決定顯示哪個(gè)頁(yè)面的邏輯showForm()doResults()self.error處理字段(154-159)的方法和我們先前看到的一樣,一個(gè)鍵-值對(duì);然而,在收集語(yǔ)言信息時(shí)卻需要一點(diǎn)技巧,原因是須檢查一個(gè)(Mini)FieldStorage對(duì)象或一個(gè)該對(duì)象的列表。使用熟悉的type()內(nèi)建函數(shù)來(lái)達(dá)到目的。最終,我們會(huì)有一個(gè)單獨(dú)或多個(gè)語(yǔ)言名的因?yàn)閟howResults()方法從客戶(hù)那里取得了新的收入值,所以它負(fù)責(zé)設(shè)置,通過(guò)調(diào)setCPP ()。而showForm()必須讀出 過(guò)它對(duì)getCPP()的調(diào)用實(shí)現(xiàn)。最后,我們看看文件上傳處理(第178-187行。不論一個(gè)文件是否已經(jīng)上傳,F(xiàn)ieldStorage都會(huì)從file屬性中獲得一個(gè)文件句柄。在第180行,如果沒(méi)有指明文件名,那么我們只須把它設(shè)成空字符串。如果過(guò)value屬性,那么文件的整個(gè)內(nèi)容都會(huì)被放到value里。還有一個(gè)更好的做法,你可以去文件指針——file屬性——并且可以每次只讀一行或者其他更慢一些的處理方法。doResults()函數(shù),從文件中抽取數(shù)據(jù)。由于空間限制doResults()將只顯示文件的最前1K內(nèi)容,這也表明顯示一個(gè)4M的二進(jìn)制文件是不需要(或未必有效/有用)的。Web(HTTP)服務(wù)到現(xiàn)在為止,我們已經(jīng)討論了如何使用PythonWeb戶(hù)端并用CGI求處理幫助Web服務(wù)器執(zhí)行了一些工作。我們通過(guò)第20.2和20.3的學(xué)習(xí)知道了Python可以用來(lái)建立簡(jiǎn)單和復(fù)雜的Web客戶(hù)端。而對(duì)復(fù)雜的CGI請(qǐng)求沒(méi)有說(shuō)明。Netscape,AOL,Safari,Camino,Epiphany,GaleonLynx器是最流行的Web客戶(hù)端,那么什么是最常用的Web服務(wù)器呢?它們就是Apache,NetscapeIIS,thttpd,Zeus,和Zope。由于這些服務(wù)器都遠(yuǎn)遠(yuǎn)超過(guò)了你的應(yīng)用程序要求,這里我們使用Python建立簡(jiǎn)單但有用的Web服務(wù)PythonWeb所有的基礎(chǔ)代碼都在Python的標(biāo)準(zhǔn)庫(kù)立一個(gè)Web服務(wù)一個(gè)基本的服務(wù)器和一個(gè)“處理器”基礎(chǔ)的(Web)HTTPBaseHTTPServer模塊中你可以找到一個(gè)名叫HTTPServer的服務(wù)器基本類(lèi)。最基本,最普通的是vanilla處理器,被命名BaseHTTPResquestHandler,這個(gè)可以在基本myhttpd.py用于SimpleHTTPServer模塊中的SimpleHTTPRequestHandler,建立在BaseHTTPResquestHandler基礎(chǔ)上,直接執(zhí)行標(biāo)準(zhǔn)的GET和HEAD請(qǐng)求。這雖然還不算完美,但已經(jīng)CGIHTTPServerCGIHTTPRequestHandlerSimpleHTTPRequestHandler并為POST請(qǐng)求提供支持。它可以調(diào)用CGI完成請(qǐng)求處理過(guò)程,也可以將生成的HTML返回給客戶(hù)端。將對(duì)BaseHTTPRequestHandler實(shí)現(xiàn)簡(jiǎn)單的GET處理功能。Table20.6WebServerModulesand模 描 提供基本的WebHTTPServer和 POSTCGICGIHTTPRequestHandler這個(gè)服務(wù)的子類(lèi)BaseHTTPRequestHandlerdo_GET()方法在基礎(chǔ)服務(wù)器接到GET(200面,否則將會(huì)返回404狀態(tài)。main(Web#myhttpd.pytothemachine...Press^Conceortwicetolocalhost--[26/Aug/200003:01:35]"GET/index.htmlHTTP/1.0"200localhost--[26/Aug/200003:01:29]code404,messageFileNotFound:/x.html--[26/Aug/200003:01:29]"GET/dummy.htmlHTTP/1.0"404localhost--[26/Aug/200003:02:03]"GET/hotlist.htmHTTP/1.0"200當(dāng)然,我們的小Web服務(wù)器是太簡(jiǎn)單了,它甚至不能處理普通的文本文件。這部分給讀正如你所看到的一樣,建立一個(gè)Web服務(wù)器并在純Python中運(yùn)行并不會(huì)花太多時(shí)間。為你的特定應(yīng)用程序定制改進(jìn)處理器將需要做事情。請(qǐng)查看本部分的相關(guān)庫(kù)來(lái)獲得模塊及其類(lèi)Example20.9SimpleWebServer它通過(guò)使用BaseHTTPServerBaseHTTPRequestHandlerdo_GET()方法來(lái)處理GET1#!/usr/bin/env23fromosimportcurdir,4fromBaseHTTPServerimport5BaseHTTPRequestHandler,67class8deff=open(curdir+sep+self.send_header('Content-except21defserver=HTTPServer(('',80), totheprint'Press^Conceortwicetoexceptprint'^Creceived,shuttingdown =='main程,還有第二十三章的WebWeb應(yīng)用都是有用的。Table20.7Web Web 新的非基于SGML的HTML、XHTML解析器htmlentitydefsHTML HTTP客戶(hù)端的處理類(lèi) 控制器:向?yàn)g覽器加載Web文檔 解析簡(jiǎn)單的SGML文件 HTTP 包含許多不同XML特點(diǎn)的解析器(見(jiàn)下文) 簡(jiǎn)單的適用于SAX2的XML(SAX)解析器 XMLElemntflexiblecontainer ExpatXML Table20.7Web編程相關(guān)模塊(續(xù)) 自描述XML-RPC服務(wù)器的框架Web服務(wù)器 Web SimpleHTTPServersWebCGI(HTTP html/main.html 郵件、MIME處理及數(shù)據(jù)編碼格式 管 消息的信箱類(lèi) Table20.7Web編程相關(guān)模塊(續(xù)) 提供和MIME類(lèi)型相關(guān)的功能MimeWriter生成MIME編碼的多種文件 可以解析多種MIME編碼文件 編使用

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論