Python 新手之旅 V1.10 - 單元 6 - Python 中豐富的標準模組庫



Python 的標準模組庫 (standard library) 具有非常豐富的內容,整理官網提供的 Library Reference ,細數有以下分類


  • 內建函數 (function) 、常數 (constant) 、型態 (type) 、例外 (exception)
  • 文字處理
  • 二進位資料處理
  • 額外的資料型態
  • 數字及數學相關
  • 函數程式設計
  • 檔案及目錄存取
  • 資料保存及資料庫
  • 資料壓縮
  • 檔案格式
  • 密碼處理
  • 作業系統相關
  • 並時處理
  • 網路通訊相關
  • 網路資料處理
  • 格式化文件處理
  • 網路協定相關
  • 多媒體處理
  • 國際化文字相關
  • 程式框架
  • 圖形介面
  • 發展工具
  • 除錯工具
  • 發布工具
  • 執行期間處理
  • 客製化 Python 直譯器
  • 模組工具
  • Python 語言處理
  • 格式化輸出處理
  • MS-Windows 特定處理
  • UNIX 特定處理

功能非常多,除了新進發展出的手機 App 外,幾乎想開發什麼都已經囊括在標組模組庫中了。像是直接用 Python 把自己電腦設定為簡單的伺服器 (server)


$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 ...

這樣在瀏覽器中輸入網址 http://127.0.0.1:8000 ,就會自動尋找啟動目錄下的 index.html ,如下



我們也可以寫個簡單版本的 HTML 解譯器來解析 HTML 文件,例如以下的 demo.py


001from html.parser import HTMLParser
002
003document = """<html>
004<head>
005<title>My Home Page</title>
006</head>
007<body>
008<p>Hello! Welcome!</p>
009</body>
010"""
011
012class TitleParser(HTMLParser):
013    def __init__(self):
014        self.handledtags=['title']
015        self.processing=None
016        HTMLParser.__init__(self)
017
018    def handle_starttag(self, tag, attrs):
019        if tag in self.handledtags:
020            self.data=''
021            self.processing=tag
022
023    def handle_data(self, data):
024        if self.processing:
025            self.data+=data
026
027    def handle_endtag(self, tag):
028        if tag==self.processing:
029            self.processing=None
030
031    def gettitle(self):
032        return self.data
033
034if __name__ == '__main__':
035    tp=TitleParser()
036    tp.feed(document)
037    print(tp.gettitle())

此處的例子採用 Python 3 。

TitleParser 繼承自 HTMLParser ,而 handle_starttag()handle_data()handle_endtag() 都是來自 HTMLParser


012class TitleParser(HTMLParser):

handle_starttag() 處理遇到的開始標籤,這裡把標籤名稱都儲存在屬性 handledtags 之中,由於只有一個 'title' ,所以只會處理 <title> 標籤


018def handle_starttag(self, tag, attrs):
019    if tag in self.handledtags:
020        self.data=''
021        self.processing=tag

handle_data() 處理標籤內的資料,參數 data 就是標籤內的文字,這裡把標籤內的文字儲存到屬性 data


023def handle_data(self, data):
024    if self.processing:
025        self.data+=data

至於 handle_endtag() 則是處理遇到結束標籤的情況


027def handle_endtag(self, tag):
028    if tag==self.processing:
029        self.processing=None

測試程式碼的部分是呼叫 feed() ,然後把 HTML 文件當參數給 TitleParser 解析, feed() 會依 HTML 文件內標籤的順序依序處理


036tp.feed(document)

簡單說, TitleParser 就是取得 HTML 文件的標題,然後把標題內容儲存在屬性 (attribute) data 中,此例用把 HTML 文件放在字串 (string) 來測試,執行結果如下


$ python3 demo.py
My Home Page
$

可是命令列對一般使用者不是很友善,這點我們倒是可以利用標準模組庫中內建的 tkinterTitleParser 設計 GUI , tkinter 是 Python 連結到 Tk 的模組 (module) , Tk 則是跨平台、輕量化、開放原始碼的 GUI 工具。


大部份的 GUI 框架都是先做出排版 (layout) ,這排版就是設定版面中放入小工具 (widget) 的模式,例如格子的模式,就得設定每個小工具要放在哪個格子,最後就是設定小工具跟使用者互動的事件 (event) ,例如使用者按了按鈕後,程式要如何做出回應。


tkinter 的概念大同小異,我們打算設計 SimpleBrowser 類別,這個類別繼承自 tkinter 中的 Frame ,也就是 GUI 中的視窗,然後在這個視窗做出可以解析網址取出標題列的功能,全部程式如下


001from tkinter import *
002from tkinter.ttk import *
003from urllib.request import urlopen
004
005from demo import TitleParser
006
007class SimpleBroswer(Frame):
008    def __init__(self, master=None):
009        Frame.__init__(self, master)
010        self.grid()
011        self.createWidgets()
012        self.address=""
013        self.data=None
014
015    def createWidgets(self):
016        self.sitebar=Entry(self)
017        self.sitebar["width"]=40
018        self.sitebar.grid(row=0, column=0)
019
020        self.gobutton=Button(self)
021        self.gobutton["text"]="Go"
022        self.gobutton["width"]=5
023        self.gobutton.grid(row=0, column=1)
024        self.gobutton["command"]=self.go
025
026        self.display=Text(self)
027        self.display["width"]=50
028        self.display["height"]=4
029        self.display.grid(row=1, column=0,
030                          columnspan=2)
031
032    def go(self):
033        self.address=self.sitebar.get()
034        self.data=urlopen(self.address)
035        web=TitleParser()
036        str=self.data.read().decode("utf-8")
037        web.feed(str)
038        print(web.data)
039        self.display.delete(1.0, END)
040        self.display.insert(INSERT, web.data)
041        self.data.close()
042
043if __name__ == '__main__':
044    root = Tk()
045    root.wm_title("Simple Browser")
046    app = SimpleBroswer(master=root)
047    app.mainloop()

SimpleBrowser 的建構子先呼叫 grid() 將其設定為格子版面管理,接著再用 createWidgets() 建立所有的小工具


008def __init__(self, master=None):
009    Frame.__init__(self, master)
010    self.grid()
011    self.createWidgets()
012    self.address=""
013    self.data=None

我們預計在視窗中放入三個小工具,分別是 EntryButtonText 三種視窗元件,分別儲存在屬性 sidebargobuttondisplay 中。例如 gobutton ,建立初值就用 Button


020self.gobutton=Button(self)

建立好 gobutton 後,就可以用串列的方式設定相關屬性,像是設定按鈕的文字


021self.gobutton["text"]="Go"

還要呼叫 grid() 設定在格子的位置


023self.gobutton.grid(row=0, column=1)

至於 "command" 則是設定按下按鈕後去執行哪個方法


024self.gobutton["command"]=self.go

這個 GUI 設定成按下按鈕就執行方法 go() ,除了 demo 中的 TitleParser 外,也用到 urllib.requesturlopen() 開啟指定網址的檔案


032def go(self):
033    self.address=self.sitebar.get()
034    self.data=urlopen(self.address)
035    web=TitleParser()
036    str=self.data.read().decode("utf-8")
037    web.feed(str)
038    print(web.data)
039    self.display.delete(1.0, END)
040    self.display.insert(INSERT, web.data)
041    self.data.close()

開啟後如下圖



來試試看囉!輸入 Yahoo 首頁的網址,按下 Go



重新輸入 Facebook 首頁的網址,按下 Go



其實這就是個簡易版的瀏覽器了,倒是想開發自己的瀏覽器,直接整合開源的排版引擎如 WebKit 、 Gecko 等,以及 JavaScript 引擎如 V8 、 SpiderMonkey 等,也就完全不用自己寫諸多解析 HTML 文件的細節了。

tkinter 很方便也很好用,如果要用 MVC 模式來分析的話, M 就是 TitleParser 類別, V 是 SimpleBroswer 類別中的 createWidgets() 方法, C 則是 go() 方法。雖說嚴格的 MVC 模式三者都需要是分開的類別或檔案,倒是簡單的程式把 V 跟 C 合在一起倒無妨。


開發程式應該要專注在 M 的部分,至於 V 則直接套用已經有的框架即可,因為這就像已經有人把輪子都做好了,我們拿輪子裝上去就可以了,大可不必完全重新再次發明輪子。


the end


Python 新手之旅 V1.10 (Google Play)

沒有留言: