2001 年 7 月 01 日 本文介紹了 Txt2Html,由 David 創(chuàng)建的公共域工作項(xiàng)目,用于說(shuō)明 Python 的編程技巧。Txt2Html 是“基于 Web 的過(guò)濾代理”-- 一種替用戶(hù)讀取基于 Web 的文檔,然后將修改過(guò)的頁(yè)面顯示到用戶(hù)瀏覽器的程序。為了使這成為可能,Txt2Html 以 CGI 程序的形式運(yùn)行,查詢(xún)外部 Web 資源的信息,并利用規(guī)則表達(dá)式。David 將為您逐步解釋、說(shuō)明和演示這些多種用途的子任務(wù)。 在撰寫(xiě)本 developerWorks 系列文章的過(guò)程中,我曾遇到過(guò)以最佳格式進(jìn)行撰寫(xiě)的問(wèn)題。文字處理程序格式都是專(zhuān)用的,在格式之間轉(zhuǎn)換總不能盡如人意,也很麻煩(而且每種格式都會(huì)各自將文檔綁定到不同的專(zhuān)用工具,這種情況又與開(kāi)放源碼的精神相違背)。HTML 還算中立 -- 也許您現(xiàn)在閱讀的文章正是這種格式 -- 但它也添加了標(biāo)記,而這些標(biāo)記很容易引起誤輸入(或者使人束縛于 HTML 增強(qiáng)型編輯器)。DocBook 是一種有趣的 XML 格式,它可以轉(zhuǎn)換成許多目標(biāo)格式,并且它擁有技術(shù)文章(或書(shū)籍)的正確語(yǔ)義;但就像 HTML 一樣,在撰寫(xiě)過(guò)程中會(huì)擔(dān)心許多標(biāo)記。LaTeX 特別適合復(fù)雜的印刷格式;但它也有許多標(biāo)記,而這些文章并不需要復(fù)雜的印刷格式。 為了在寫(xiě)作時(shí)能真正省心 -- 特別是要具有平臺(tái)和工具的中立性 -- 無(wú)格式 ASCII 正是最好的選擇。但是,因特網(wǎng)(特別是 Usenet)建議在完全無(wú)格式文本的基礎(chǔ)上,開(kāi)發(fā)一種“智能 ASCII”文檔的非正式標(biāo)準(zhǔn)(請(qǐng)參閱 參考資料 )。“智能 ASCII”只添加了一點(diǎn)額外的語(yǔ)義內(nèi)容和上下文,而且它們?cè)谖谋撅@示中看起來(lái)是那么“自然”。電子郵件、新聞組郵件、FAQ、項(xiàng)目自述文件 (README) 和其它電子文檔通常包括一些印刷/語(yǔ)義元素,如強(qiáng)調(diào)字前后的星號(hào)、標(biāo)題下的下劃線、描述文本關(guān)系的豎直和水平空格、有選擇性的全大寫(xiě)和其它一些信息。Project Gutenberg(請(qǐng)參閱 參考資料 )是一種驚人的成果,它將許多想法加入其自身格式構(gòu)思中,并認(rèn)為“智能 ASCII”是長(zhǎng)時(shí)間保存和分發(fā)好書(shū)的最佳選擇。即使這些文章不會(huì)像文學(xué)名著那樣經(jīng)久不衰,仍決定將它們寫(xiě)成“智能 ASCII”格式,并用方便的 Python 腳本將它們自動(dòng)轉(zhuǎn)換成其它格式。 Txt2Html 最初是一個(gè)簡(jiǎn)單的文件轉(zhuǎn)換器,從其名稱(chēng)上就可以看出。但因特網(wǎng)建議在工具上添加幾個(gè)明顯的增強(qiáng)功能。因?yàn)橛性S多讀者想以“HTML 化”格式查看的文檔都在 http: 或 ftp: 鏈接的后面,所以工具應(yīng)該真正直接處理這樣的遠(yuǎn)程文檔(而不需要下載/轉(zhuǎn)換/查看循環(huán)周期)。因?yàn)檗D(zhuǎn)換的目標(biāo)最終是 HTML,通常我們要做的就是在 Web 瀏覽器中查看轉(zhuǎn)換后的目標(biāo)文檔。 將這些放到一起后,Txt2Html 就成了“基于 Web 的過(guò)濾代理”。這個(gè)詞很奇特,也許恰好能“完全表達(dá)其含義”。它們體現(xiàn)了以下想法:程序代表您閱讀 Web 頁(yè)面(或其它資源),以某種方式處理內(nèi)容,然后以某種比原始頁(yè)面 更好 的形式(至少能滿(mǎn)足某些特殊目的)向您顯示該頁(yè)面。這種工具的一個(gè)很好例子就是 Babelfish 翻譯服務(wù)(請(qǐng)參閱 參考資料 )。在通過(guò) Babelfish 運(yùn)行了 URL 之后,您看到的 Web 頁(yè)面與原始頁(yè)面非常相似,但它顯示了您能夠讀懂的文字,而不是您不理解的語(yǔ)言。在某種程度上,所有顯示搜索結(jié)果頁(yè)面摘要的搜索引擎所做的都是相同的事情。但那些搜索引擎(按設(shè)計(jì))在目標(biāo)頁(yè)面的格式以及外觀方面有更多的自由度,同時(shí)會(huì)去掉許多內(nèi)容。當(dāng)然,Txt2Html 并不如 Babelfish 那樣功能強(qiáng)大;但概念上,它們很大程度上完成相同的事情。請(qǐng)參閱 參考資料以獲取更多的例子,其中一些還很幽默。 Txt2Html 最大的優(yōu)點(diǎn)是使用許多編程技巧,而這些技巧對(duì)于不同面向 Web 使用 Python 是共通的。本文將介紹那些技巧,并會(huì)說(shuō)明編碼技巧和一些 Python 模塊的作用域。請(qǐng)注意:Txt2Html 中的實(shí)際模塊叫做 dmTxt2Html,以避免與其他人編寫(xiě)的模塊名稱(chēng)發(fā)生沖突。
Python 標(biāo)準(zhǔn)發(fā)行版中的 cgi 模塊對(duì)于任何用 Python 開(kāi)發(fā)“公共網(wǎng)關(guān)接口”應(yīng)用程序的人來(lái)說(shuō)都是意外驚喜??梢圆皇褂盟鼇?lái)創(chuàng)建 CGI,但您不會(huì)這樣做。 最通常的情況下,您會(huì)通過(guò) HTML 表單與 CGI 應(yīng)用程序進(jìn)行交互。要填寫(xiě)調(diào)用 CGI 的表單以執(zhí)行使用規(guī)范的操作。例如,Txt2Html 文檔使用這個(gè)例子來(lái)調(diào)用 HTML 表單(Txt2Html 自身生成的表單比較復(fù)雜,并且可能會(huì)改變,但示例將會(huì)很好地工作,甚至是在您自己的 Web 頁(yè)面中): 調(diào)用 ‘Txt2Html‘ 的 HTML 表單
可以在 HTML 表單中包括許多輸入字段,而字段可以是許多不同類(lèi)型中的一種(文本、復(fù)選框、單選列表、單選按鈕等)。任何講述 HTML 的好書(shū)可以幫助初學(xué)者創(chuàng)建定制 HTML 表單。此處最需要牢記的是每個(gè)字段都有名稱(chēng)屬性,而以后會(huì)在 CGI 腳本中使用該名稱(chēng)來(lái)引用該字段。另一個(gè)需要了解的細(xì)節(jié)是表單可以使用以下兩種方法中的一種:"get" 和 "post"。它們的基本差異是 "get" 在 URL 中包括了查詢(xún)信息,并且這個(gè)方法使用戶(hù)易于保存特定查詢(xún)以便日后重復(fù)使用。另一方面,如果您不希望用戶(hù)保存查詢(xún),請(qǐng)使用 "post" 方法。 以上表單調(diào)用的 Python 腳本將導(dǎo)入 cgi 以使整理其調(diào)用表單變得更容易。這個(gè)模塊所做的一件事就是隱藏 CGI 腳本中 "get" 和 "post" 方法之間差異的任何細(xì)節(jié)。在進(jìn)行調(diào)用之前,這并不是 CGI 創(chuàng)建程序需要操心的細(xì)節(jié)。該 CGI 模塊的主要作用是處理類(lèi)似于字典樣式的調(diào)用 HTML 表單中的所有字段。您所得到的并不是 真正 的 Python 字典,但它們的使用方式極其相似: 使用 Python [cgi] 模塊
在以上幾行中,要注意幾處細(xì)節(jié)。我們所使用的一個(gè)技巧是設(shè)置 sys.stderr = sys.stdout。如果我們的腳本遇到了一個(gè)未捕獲的錯(cuò)誤,通過(guò)這個(gè)操作,追溯就顯示回到客戶(hù)機(jī)瀏覽器。這可以節(jié)省許多調(diào)試 CGI 應(yīng)用程序的時(shí)間。但您也許不想讓用戶(hù)看到這些(或者如果它們可能向您報(bào)告問(wèn)題詳細(xì)信息,您也許會(huì)向用戶(hù)顯示這些內(nèi)容)。接著,我們將 HTML 表單值讀取到類(lèi)似于字典的 至此,HTML 表單中的所有東西都成了純 Python 變量,而且我們可以在其它任何 Python 程序中處理它們。
就像大多數(shù) Python 模塊一樣,urllib 以直觀且簡(jiǎn)單的方法處理許多復(fù)雜事物。urllib 中的 urlopen() 函數(shù)可以處理任何遠(yuǎn)程資源 -- 無(wú)論是 http:、ftp: 還是 gopher: --就將它當(dāng)作是本地文件。如果使用 urlopen() 抓取了一個(gè)遠(yuǎn)程(偽)文件對(duì)象,可以將它當(dāng)作本地(只讀)文件的文件對(duì)象來(lái)進(jìn)行處理: 使用 Python [urllib] 模塊
我曾遇到過(guò)一個(gè)小問(wèn)題,由于生成資源的平臺(tái)和您的平臺(tái)使用不同的行結(jié)束約定,生成的文本中可能會(huì)發(fā)生某些奇怪的事(這似乎是 urllib 中的錯(cuò)誤)。這個(gè)問(wèn)題的解決方法是在以上代碼中執(zhí)行小小的 .readlines() 循環(huán)。不管該資源原來(lái)是什么樣子,這個(gè)操作會(huì)給您一個(gè)字符串,它都有所使用平臺(tái)的正確行結(jié)束約定(估計(jì)可能合理)。
由于本文篇幅限制,這里只討論一部分規(guī)則表達(dá)式。 參考資料中列出了許多關(guān)于該主題的參考書(shū)籍。 re 模塊在 Txt2Html 中的使用很廣泛,用于標(biāo)識(shí)源文本中的各種文本模式。我們查看一個(gè)比較復(fù)雜的例子: 使用 Python [re] 模塊
URLify() 是一個(gè)小巧函數(shù),它的功能正如其名稱(chēng)所示。如果在“智能 ASCII”文件中遇到了類(lèi)似于 URL 的字符串,它將轉(zhuǎn)換成 HTML 輸出中同一個(gè) URL 真正的熱鏈接。讓我們看看 re.sub() 的作用。首先,從最主要的角度來(lái)看,函數(shù)的目的是“查找與第一個(gè)模式中的值匹配的字符串,然后通過(guò)將第三個(gè)變量作為要操作的字符串,以第二個(gè)模式替換匹配結(jié)果”。非常好,從這些角度來(lái)看,它與 string.replace() 沒(méi)有什么區(qū)別。 第一個(gè)模式有幾個(gè)元素。首先,請(qǐng)注意括號(hào):最高層次由兩對(duì)括號(hào)組成:(\S) 前復(fù)雜的字符串。括號(hào)對(duì)與可能組成部分替換模式的“子表達(dá)式”匹配。第二個(gè)子表達(dá)式 (\s) 只表示“查找與任何空格字符匹配的字符串,讓我們回過(guò)來(lái)看什么與之匹配”。因此,讓我們研究一下第一個(gè)子表達(dá)式。 Python 規(guī)則表達(dá)式有它自己的一些技巧。其中一個(gè)技巧是子表達(dá)式開(kāi)始處的 ?: 運(yùn)算符。這表示“查找子模式的匹配字符串,但不包括反向引用中的匹配結(jié)果”。那么,讓我們檢查一下這個(gè)子表達(dá)式:
首先,請(qǐng)注意這個(gè)子表達(dá)式本身由兩個(gè)子表達(dá)式組成,兩者之間的字符并不屬于任何一方。但是,每個(gè)子表達(dá)式都由 在規(guī)則表達(dá)式中,方括號(hào)只表示“查找與方括號(hào)中任何字符的匹配字符”。但是,如果第一個(gè)字符是插入記號(hào) (^),含義則相反,它表示“查找任何與后面的字符 不匹配的字符”。因此,我們正在查找 不 是空格、CR、LF、"<" 或 ")" 的字符(還請(qǐng)注意,可以通過(guò)在字符前面加 "\",避開(kāi)對(duì)于規(guī)則表達(dá)式有特殊意義的字符)。結(jié)尾處的加號(hào)表示“查找最后字符串的一個(gè)或多個(gè)匹配”(星號(hào)表示“零個(gè)或多個(gè)”,問(wèn)號(hào)表示“零個(gè)或一個(gè)”)。 這個(gè)規(guī)則表達(dá)式有許多內(nèi)容有待理解,但如果多看幾遍,您就會(huì)明白這就是 URL 的格式。 接著就是替換部分。這就更簡(jiǎn)單了。看上去類(lèi)似
|
聯(lián)系客服