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

下載本文檔

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

文檔簡介

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

Web瀏覽器是基本的Web客戶端。主要用來在Web上查詢或者文件。而Web的高級客戶端并高級Web客戶端的一個例子就是網(wǎng)絡(luò)爬蟲(aka蜘蛛和機器人。這些程序可以基于不同目的在因 脫機瀏覽—將文檔到本地,重新設(shè)定超,為本地瀏覽器創(chuàng)建鏡像我們下邊介紹網(wǎng)絡(luò)爬蟲:crawl.py,抓取Web的開始頁面地址(URL,該頁面和其它后續(xù)鏈接頁面,但是僅限于那些與開始頁面有著相同的頁面。如果沒有這個限制的話,你的硬盤將會被耗盡!crwal.py的代碼在例子20.2中展示。1–1113–49行Retriever類的責(zé)任是從Web頁面,解析每個文檔中的并在必要的時候把它們加入法展現(xiàn)了它的功能:構(gòu)造器(init()、filename()、download()parseAndGetLinks()。filename(URL找出安全、有效的相關(guān)文件名并在本地。大體上說,它會去掉URL的“http://”前綴,使用剩余的部分作為文件名,并創(chuàng)建必要的文件夾路徑。那些沒有“index.htm構(gòu)造器實例化了一個Retriever對象,并把URL和通過filename()獲得的相應(yīng)文件名都作為本Example20.2AdvancedWebClient:aWebCrawler載的Web頁面(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()方法實際會連上網(wǎng)絡(luò)去給定的頁面。它使用URL調(diào)用urllib.urlretrieve()函數(shù)并把結(jié)果保存在filename中(該值由filename()返回如果成功,如果Crawler判定沒有錯誤發(fā)生,它會調(diào)用parseAndGetLinks()方法來解析新的頁面并決定51-98 它就變短,在的頁面中發(fā)現(xiàn)新的則會讓它變長。Crawler包含的另兩個數(shù)值是seen,一個所有“我們已看過(已)的的列表,和dom,我們把主的在這里,并用這個值來判定后續(xù)是否是該域的一部分。目。每有一個頁面成功它就會增加。除了構(gòu)造器Crawler還有其他兩個方法,getPage()和go()。go()只是簡單的啟動Crawler,它而這個的真正工作者,卻是getPage()方法。成功,計數(shù)器會增加并且會被加到“已看”列表。它會反復(fù)地檢查每個已頁面中的所有鏈接并是否有要被加入待隊列。go()中的主循環(huán)會不停的推進處理過程直到隊列為空,在擴充隊列時都會被忽略掉。100-114被直接調(diào)用時,它就會使用這個指定的。否則,進入交互模式,提示用戶輸入起始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ù)器處理客戶端數(shù)據(jù)CGI 性在于它對超文本的兼容性,文本以一種或者是高亮的形式指向另外一個相關(guān)文檔??梢酝ㄟ^鼠標Web用戶那里獲得特蘇信息的唯一形式(Javaapplets。反過來,在客戶提交了特定數(shù)據(jù)后,就要求立即生成HTML頁面?,F(xiàn)在Web服務(wù)器僅有一點做的很不錯,獲取用戶對文件的請求,并將這個文件(也就是說HTML文件)返回給客戶端。它們現(xiàn)在還不具有處理字段類特殊數(shù)據(jù)的機制。將這些請求送到可以生成動態(tài)HTMLWeb這整個過程開始于Web服務(wù)器從客戶端接到了請求(GET或者POST)并調(diào)用合適的程序。然后開始等待HTML頁面—與此同時,客戶端也在等待。一旦程序完成,會將生成的動態(tài)HTML頁面返CG(Common客戶端輸入給Web服務(wù)器端的表單可能包括處理過程和一些在數(shù)據(jù)庫中的表單需要記住的是,在任何時候都可能有任何一個用戶去填寫這個字段,或者點擊提交按鈕或者,這更CGI創(chuàng)建HTML的CGI應(yīng)用程序通常是用高級編程語言來實現(xiàn)的,可以接受、處理數(shù)據(jù),向服務(wù)器端HTMLPerl,PHP,C/C++,Python。WebC/C++WebAphachePostgreSQL,Java(Tomcat,PH塊,以及SSL/security。然而,如果你工作在私人小型的或者小組織的Web上的話就沒有必要使用這種強大而復(fù)雜的Web服務(wù)器,CGI是一個適用于小型Web開發(fā)的工具。更進一步來有很多Web應(yīng)用程序開發(fā)框架和內(nèi)容管理系這些都彌補了過去CGI的不足。CGI執(zhí)行拷貝,并提供了一個有效的HTML做為最終的客戶端輸出。因此,為了開發(fā)更加高效的Web服務(wù)有必要理解CGI實現(xiàn)的基本原理。CGI應(yīng)用程當(dāng)一個CGI開始執(zhí)行時,它需要檢索用戶-支持表單,但這些數(shù)據(jù)必須要從Web的客戶端才可以這些不同于標準輸出的輸出將會返回到連接的Web客戶端,而不是返回到屏幕、CUI窗口或者硬盤上返回來的數(shù)據(jù)必須是具有一系列有效頭文件的HTMLWeb的客戶端,由于瀏覽器只能識別有效的HTTP數(shù)據(jù)(也就是MIME都問價和HTML),那么返回的也只能是個錯 ,We在cgi模塊中有個主要類:FieldStorage類,它完成了所有的工作。在PythonCGI開始時Web(Web)讀出有關(guān)的用戶信息。一旦這個對象對于簡單的Web表單,你將會經(jīng)常發(fā)現(xiàn)所有的MiniFieldStorage實例。下邊包含的所有的例子建立CGI應(yīng)用程20.5.1建立Web服務(wù)器為了可以用Python進行CGI需要安裝一個Web以處理PythonCGI請求的模式,然后讓你的Web服務(wù)器CGI。其中有些操作你也許需要獲得系統(tǒng)管理員的如果你需要一個真正的Web服務(wù)器,可以并安裝Aphache。Aphache的插件或模塊可以處理PythonCGI,但這在我們的例子里并不是必要的。如果你準備把自己的服務(wù)"帶入真實世界",也許會階段獲得知識,你也可以現(xiàn)在提前閱讀那部分。然而,這并不是本章的焦點。$python-m這將會在當(dāng)前機器的當(dāng)前下建立一個端為8000的Web服務(wù)器。然后可以在啟動這個服務(wù)器的下建立一個Cgi–bin,將PythonCGI放到那里將一些HTML文件放到那個下,或許有些.pyCGI在Cgi-bin中,然后就可以在地址欄中輸入這些地址來Web站點啦。正如你可以在代碼中看到的一樣,這個表單包括兩個輸入變量:和howmany,這兩個值將會被傳到我們的CGIfriends1.py中。你會注意到在例子中CGI初始化到主機默認的cgi-bin(“Action連接(如果這個信息與你開發(fā)環(huán)境不一樣的話,在測試Web頁面和CGI之前請更新你的表單事件。同時由于表單事件中缺少METHOD子,所有的請求將會采用默認的GET方法。選擇GET方法是因為我們(ak“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 按下回車鍵獲得相同的效果)當(dāng)這些發(fā)生后,在例20.4中的,friends1.py將會隨CGI一起Python(14-17。表單的變量FieldStorage實例,包含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中分離出來的。有一點需要向CGI初學(xué)者指明的是,在向CGI返回結(jié)果時,須先返回一個適當(dāng)?shù)腍TTP頭文件后才會返回結(jié)果HTML頁面了區(qū)分這些頭文件和結(jié)果HTML頁面friends1.py的20-6erickallen”,單擊“10friends”單選按鈕。這次的屏幕鏡像圖展示的是在WindowsIE3瀏覽器的效果。Web注意GET請求是如何將表單中的變量和值加載在URL地址條觀察到了friends.htm頁而friends.py輸出到屏幕上的則是“dynamic”?我們這樣做的一個原因就是:指明生成表單和結(jié)果頁面 1-5除了通常的起始、和模塊導(dǎo)入行,我們還把HTTPMIMIHTML正文部分分離出來,放在了這里。因為在返回的兩種頁面(表單頁面和結(jié)果頁面)中都使用它,而又不想重復(fù)寫文本。當(dāng)需要輸出時,把這個頭字串加在相應(yīng)的HTML正文中。7-29所有這些代碼都是為了整合CGI里的friends.htm表單頁面。我們對表單頁面的文本使用一個變量formhtml,還有一個用來創(chuàng)建單選按鈕的字符串變量fradio。我們從friends.htm了這個單選按鈕HTML文本,但我們意在展示如何使用Python來生成的動態(tài)輸出—見22-27行的for循環(huán)。20.5生成表單和結(jié)果頁面將friends.html和friends1.py合并成friends2.py。得到的可以同時顯示表單和動態(tài)生HTML結(jié)果頁面,同時可以巧妙的知道應(yīng)該輸出哪個頁面。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àn)在你或許會想“既然我也可以選擇howmany那為什么我們要用一個變量呢?”這是一個很好的問題,因為在這種情況下你當(dāng)然可以只用hwomany創(chuàng)立action的另一個原因是 31-39 41-56因為這個也以、也許不能取得所期待的字段(例如,第一次運行時生成一個表單第53-56行作了這種判定。20-5全面交互的Web站 我們最后一個例子將會完成這個循環(huán)。如面中,用戶在表單頁中輸入他/信息,然后我現(xiàn)在在例子20.6中我們展示我們最后的更新,friends3.py。810-1969-7175-82表單,但不需要有動作因為我們只是簡單的后退到瀏覽器歷史中的上一個頁面。盡管我們的目為了以后還可以繼續(xù)開發(fā)這個 ,給它增 的錯誤檢測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這個的一個目的是創(chuàng)建一個有意義的,以便從結(jié)果頁面返回表單頁面。當(dāng)有錯誤發(fā)生時,用戶可以使用這個返回表單頁面去更新他/她填寫的數(shù)據(jù)。新的表單頁面只有當(dāng)它包含了用一個值。這個值如果給出的話,會入到name字段。顯然地,在初始表單頁面上它將是空值。第41我們根據(jù)當(dāng)前選定的朋友數(shù)目設(shè)置了單選按鈕。最后,通過第49行和52-55行更新了的doResults()函數(shù),我們創(chuàng)建了這個包含已有信息的,它會讓用戶“返回”到我們更改后的表單62friends1.pyfriends2.py頁面。我們加了一個對string.capwords()函數(shù)的調(diào)用從而自動的將用戶名置成大寫。capwords()同時故意忘記檢查單選按鈕。單擊Submit按鈕后將會返回錯誤頁面,請看第二個截屏圖20-10. 20-10Friends(無效的用戶輸入)Camino(Friends3.py)是現(xiàn)在在頁面底部有個額外的連接。這個連接將會把我們帶到表單頁面。新表單頁面和最初的頁面20-12.HTMLPythonHTMLgen模塊的連接,HTMLgen是Python的一個擴展模塊,于生成HTML頁面。(friends3.py)CGI中使Unicode編子 為了看到Unicode的作用,會用CGI生成一個多語言功能的Web頁面。首先我們用Unicode字符串定義一些消息。我們假設(shè)你的編輯器只能輸入ASCII編碼。因此,非ASCII編碼的字符使用\u轉(zhuǎn)義符輸入。實際上從文件或數(shù)據(jù)庫中也能這些消息。#GreetinginEnglish,#ChineseandJapanese. O=u"""CGI產(chǎn)生的第一個頭信息內(nè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)在我們來看看CGI編程的高級方面。這包括的使用(保存在客戶端的緩存數(shù)據(jù),同一個CGI字段的多重值,和用multipart表單實現(xiàn)的文件上傳。為了節(jié)省空間,會在同一個Mulitipart目前,CGI特別只允許兩種表單編碼,“application/x-www-form-urlencoded”和<FORMenctype="application/x-www-form-urlencoded"<FORMenctype="multipart/form-data"在表單提交時你可以使用任一種編碼,但在目前上傳的文件僅能表現(xiàn)為multipart<INPUTtype=file這個指令表現(xiàn)為一個空的文本字段,同時旁邊有個按鈕,可以讓你瀏覽文件系統(tǒng),找到multipart的。同時還需要有一個單獨的編碼,因為它還沒有聰明到“通過URL編碼”的程度,尤其是對不論你使用的是默認編碼還是multipart編碼,cgi模塊都會以同樣的方式來處理它們,在表單提交時提供鍵和相應(yīng)的值。你還可以像以前那樣通過FieldStorage實例來數(shù)據(jù)。 MiniFielStorage由于HTTP是一個“無狀態(tài)信息”的協(xié)議,如你在本章最開始看到的截圖一樣,是通過GET請求中的鍵值對來完成信息從一個頁面到另一個頁面的傳遞。實現(xiàn)這個功能的另外法如我們以前看到的一樣,是使用隱藏的表單字段,如在后期friends.py中對action變量的處理。這些還有一種可以保持對多個頁面瀏覽連續(xù)性的方法就是在客戶端保存這些數(shù)據(jù)。這就是引進的原因。服務(wù)器可以向客戶端發(fā)送一個請求來保存 ,而不必用在返回的Web頁面中嵌入數(shù)據(jù)的方法來保持數(shù)據(jù)。連接到最初的服務(wù)器的主域上(這樣一個服務(wù)器就不能設(shè)置或性,如域子路徑,安全傳輸請求。有了coockies,我們不再需要為了用戶而將數(shù)據(jù)從一頁傳到另一頁了。雖然這在隱私問題上也了大量的爭論,多數(shù)Web站點還是合理地使用了。為了準備代碼,在客戶端獲得請求文件前,Web服務(wù)器向客戶端發(fā)送“Set”頭文件要求客戶端一旦在客戶端建立了,HTTP_環(huán)境變量會將那些自動放到請求中發(fā)送給串(也就是說,使用str.split()或者手動解析。以分號(;)分隔,每個鍵-值對中間都由等和multipart編碼一樣,同樣于網(wǎng)景,他們實現(xiàn)了 用至今,在下邊的Web站點中你可以接觸這些文檔: 一旦標準化以后,這些文檔最終都被了,你可以從評論請求文檔(RFCs)中獲得更多現(xiàn)在的信息?,F(xiàn)今發(fā)布的的的文件是RFC2109.使用高級CGIadvcgi.pyfriends3.py的差別不是很大。默認的第一頁是用戶填寫的表單,它由四個主要部分組成:用戶設(shè)置字符串,字段,編程語言復(fù)選框列表,文件提交框。在圖20-14中可以看到示圖。圖“Browse.“Choose”,“...”等。mutipartFieldStorage由于這是服務(wù)器端第一次接到數(shù)據(jù),這時,當(dāng)我們向客戶端返回結(jié)果頁面時,我們使用“Set:”頭文件來捕獲瀏覽器端的。 20-14IE5MacOSX如果我們單擊下方的那個,沒有任何表單數(shù)據(jù)提交給我們的,因此會顯示一個表單頁藏或者作為URL中的請求參數(shù))?實際上是這些數(shù)據(jù)都被保存在客戶端的 當(dāng)檢測到表單沒有數(shù)據(jù)時,它會返回一個表單頁面,但是在表單頁面建立前,它們從客戶端的中抓取了數(shù)據(jù)(當(dāng)用戶在單擊了那個的時候?qū)詣觽魅耄┎⑶蚁鄳?yīng)的將其填入表單中。因此當(dāng)表單最終顯示出來時,先前的輸入便會魔術(shù)般的顯示在用戶面前(20-18。 advcgi.py和我們本章前部分提到的CGIfriends3.py相當(dāng)?shù)南?。它有表單頁、結(jié)果頁、錯誤頁可以返回。新的中除了有所有的高級CGI特性外,我們還在中增加了的面向?qū)ο?0-16CGI提交演示Opera8Win32系統(tǒng)1-7象,所以這個字符串與打開一個文件并使用文件句柄去數(shù)據(jù)很相似。 圖圖20–17ResultspagegeneratedandreturnedbytheWebserverinOpera4on9-12在AdvCGI類之后,header和url(靜態(tài))變量被創(chuàng)建出來,在顯示所有不同頁面的方法中14-80所有這個塊中的代碼都是用來創(chuàng)建、顯示表單頁面的。那些數(shù)據(jù)屬性都是不言自明的。getCPP()取得Web客戶端發(fā)來的信息,而showForm()校對所有這些信息并把表單頁面 圖圖20–18 FormpagewithdataloadedfromtheClient82-91行93-144結(jié)果頁面的生成使用了本塊代碼。setCPP()方法要求客戶端為我們的應(yīng)用程序,而doResults()方法所有數(shù)據(jù)并把輸出發(fā)回客戶端。Example20.8AdvancedCGIApplication也可以從客戶端(Web瀏覽器)讀寫。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格的基于過程編寫的程序不同。go()方法中包含所有新到的數(shù)據(jù)并決定顯示哪個頁面的邏輯showForm()doResults()self.error處理字段(154-159)的方法和我們先前看到的一樣,一個鍵-值對;然而,在收集語言信息時卻需要一點技巧,原因是須檢查一個(Mini)FieldStorage對象或一個該對象的列表。使用熟悉的type()內(nèi)建函數(shù)來達到目的。最終,我們會有一個單獨或多個語言名的因為showResults()方法從客戶那里取得了新的收入值,所以它負責(zé)設(shè)置,通過調(diào)setCPP ()。而showForm()必須讀出 過它對getCPP()的調(diào)用實現(xiàn)。最后,我們看看文件上傳處理(第178-187行。不論一個文件是否已經(jīng)上傳,F(xiàn)ieldStorage都會從file屬性中獲得一個文件句柄。在第180行,如果沒有指明文件名,那么我們只須把它設(shè)成空字符串。如果過value屬性,那么文件的整個內(nèi)容都會被放到value里。還有一個更好的做法,你可以去文件指針——file屬性——并且可以每次只讀一行或者其他更慢一些的處理方法。doResults()函數(shù),從文件中抽取數(shù)據(jù)。由于空間限制doResults()將只顯示文件的最前1K內(nèi)容,這也表明顯示一個4M的二進制文件是不需要(或未必有效/有用)的。Web(HTTP)服務(wù)到現(xiàn)在為止,我們已經(jīng)討論了如何使用PythonWeb戶端并用CGI求處理幫助Web服務(wù)器執(zhí)行了一些工作。我們通過第20.2和20.3的學(xué)習(xí)知道了Python可以用來建立簡單和復(fù)雜的Web客戶端。而對復(fù)雜的CGI請求沒有說明。Netscape,AOL,Safari,Camino,Epiphany,GaleonLynx器是最流行的Web客戶端,那么什么是最常用的Web服務(wù)器呢?它們就是Apache,NetscapeIIS,thttpd,Zeus,和Zope。由于這些服務(wù)器都遠遠超過了你的應(yīng)用程序要求,這里我們使用Python建立簡單但有用的Web服務(wù)PythonWeb所有的基礎(chǔ)代碼都在Python的標準庫立一個Web服務(wù)一個基本的服務(wù)器和一個“處理器”基礎(chǔ)的(Web)HTTPBaseHTTPServer模塊中你可以找到一個名叫HTTPServer的服務(wù)器基本類。最基本,最普通的是vanilla處理器,被命名BaseHTTPResquestHandler,這個可以在基本myhttpd.py用于SimpleHTTPServer模塊中的SimpleHTTPRequestHandler,建立在BaseHTTPResquestHandler基礎(chǔ)上,直接執(zhí)行標準的GET和HEAD請求。這雖然還不算完美,但已經(jīng)CGIHTTPServerCGIHTTPRequestHandlerSimpleHTTPRequestHandler并為POST請求提供支持。它可以調(diào)用CGI完成請求處理過程,也可以將生成的HTML返回給客戶端。將對BaseHTTPRequestHandler實現(xiàn)簡單的GET處理功能。Table20.6WebServerModulesand模 描 提供基本的WebHTTPServer和 POSTCGICGIHTTPRequestHandler這個服務(wù)的子類BaseHTTPRequestHandlerdo_GET()方法在基礎(chǔ)服務(wù)器接到GET(200面,否則將會返回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ù)器是太簡單了,它甚至不能處理普通的文本文件。這部分給讀正如你所看到的一樣,建立一個Web服務(wù)器并在純Python中運行并不會花太多時間。為你的特定應(yīng)用程序定制改進處理器將需要做事情。請查看本部分的相關(guān)庫來獲得模塊及其類Example20.9SimpleWebServer它通過使用BaseHTTPServerBaseHTTPRequestHandlerdo_GET()方法來處理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客戶端的處理類 控制器:向瀏覽器加載Web文檔 解析簡單的SGML文件 HTTP 包含許多不同XML特點的解析器(見下文) 簡單的適用于SAX2的XML(SAX)解析器 XMLElemntflexiblecontainer ExpatXML Table20.7Web編程相關(guān)模塊(續(xù)) 自描述XML-RPC服務(wù)器的框架Web服務(wù)器 Web SimpleHTTPServersWebCGI(HTTP html/main.html 郵件、MIME處理及數(shù)據(jù)編碼格式 管 消息的信箱類 Table20.7Web編程相關(guān)模塊(續(xù)) 提供和MIME類型相關(guān)的功能MimeWriter生成MIME編碼的多種文件 可以解析多種MIME編碼文件 編使用

溫馨提示

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

評論

0/150

提交評論