使用 Python 3 編寫系列實用腳本
課程簡介:本課程教授如何使用 Python 3 編寫一個轉換 markdown 為 HTML 的腳本文件,這個腳本能夠進行批量處理操作,可以自定義 HTML 的 CSS 樣式(默認沒有樣式),可以自定義輸出目錄(默認為 markdown 文件所在目錄)
本課程由FrostSigh發布在實驗樓,完整教程及在線練習地址:使用 Python 3 編寫系列實用腳本
1. Markdown to HTML
2. 文本文件編碼檢測與轉換 3. 文件校驗第一部分 Markdown to HTML
一、實驗簡介
1.1 知識點
- Python 3 的模塊的安裝
- Python 3 基礎知識
- 使用os模塊進行路徑相關的操作
- markdown模塊的使用
- 使用 BeautifulSoup模塊格式化 HTML
- 命令行選項的實現
二、實驗步驟
2.1 安裝包
首先更新一下軟體源
$ sudo apt-get update
安裝 pip3,pip 是 Python2 的軟體包管理系統,使用它來安裝 Python2 的模塊非常簡便,而 pip3 則是對應於 Python3 的版本
$ sudo apt-get install python3-pip
安裝 markdown,本實驗使用這個模塊編譯 Markdown 文件
$ sudo pip3 install markdown
安裝 BeautifulSoup,本實驗使用 BeautifulSoup 僅是為了格式化 HTML 代碼為可讀性更強的代碼,不需要可以不安裝
$ sudo pip3 install beautifulsoup4
2.2 編寫 MarkdownToHtml 類
類名定義為 MarkdownToHtml 吧
class MarkdownToHtml:
我們的類有4個屬性,3個方法屬性,1個數據屬性
因為 markdown 模塊生成的 HTML 代碼是不包括 head 標籤的,這樣會可能造成瀏覽器中渲染 HTML 時顯示亂碼,而且我們有時可能也需要添加 CSS 來美化網頁
所以我們需要一個數據屬性存放生成 HTML 代碼時用到的 head 標籤以及準備存放可能用到的 style 標籤
headTag = "<head><meta charset="utf-8" /></head>"
構造方法,有一個參數 cssFilePath ,默認值為 None
def __init__(self,cssFilePath = None): if cssFilePath != None: self.genStyle(cssFilePath)
方法 genStyle() 讀取外部 CSS 文件的內容並存放到 headTag 變數中
關於文件讀寫操作,最常見的是這樣的操作:
f = open(cssFilePath,"r")cssString = f.read()f.close()
然而更推薦使用關鍵字 with 處理文件對象,它的先進之處在於文件用完後會自動關閉,就算髮生異常也沒關係。它是 try finally 塊的簡寫
with open(cssFilePath,"r") as f: cssString = f.read()
因此,方法 genStyle() 的代碼如下
def genStyle(self,cssFilePath): with open(cssFilePath,"r") as f: cssString = f.read() self.headTag = self.headTag[:-7] + "<style type="text/css">" + cssString + "</style></head>"
接下來是方法 markdownToHtml() ,作用是編譯 Markdown 輸出 HTML
有3個參數,分別是 Markdown 源碼路徑,輸出文件目錄(可選),輸出文件名稱(可選)
def markdownToHtml(self, sourceFilePath, destinationDirectory = None, outputFileName = None):
若是方法調用時沒指定輸出目錄和輸出文件名,那麼我們將默認使用源文件目錄和源文件名
if not destinationDirectory: # 未定義輸出目錄則將源文件目錄(注意要轉換為絕對路徑)作為輸出目錄 destinationDirectory = os.path.dirname(os.path.abspath(sourceFilePath))if not outputFileName: # 未定義輸出文件名則沿用輸入文件名 outputFileName = os.path.splitext(os.path.basename(sourceFilePath))[0] + ".html"
os.path.abspath() 將參數路徑轉為絕對路徑並返回
os.path.dirname() 獲得參數路徑的目錄部分並返回(如 "homea.txt" 為參數,返回 "home")
os.path.basename() 返回參數路徑字元串中的完整文件名(文件名+後綴名)
os.path.splitext() 將參數轉換為包含文件名和後綴名兩個元素的元組並返回
關於 os 模塊更多詳情,參見官方文檔
還有一個問題,輸出文件的路徑我們通過拼接 destinationDirectory,outputFileName 這兩個變數中的字元串得到,若是變數 destinationDirectory 中的字元串並不以 "/" 字元結尾,那麼輸出文件的路徑會是錯誤的,所以需要處理一下:
if destinationDirectory[-1] != "/": destinationDirectory += "/"
然後讀取源文件
文件打開函數 open() 有一個參數是 encoding ,若是不指定它,那麼將會默認使用平台的編碼,而在 Windows 命令行里默認是 GBK 編碼的,對於使用 UTF-8 編碼格式的 Mardown 文件將會出錯,因此為了在任意平台保證腳本正確,無論是讀取 Markdown 還是之後的寫入 HTML 文件都需要傳入這個參數 encoding="utf8"
with open(sourceFilePath,"r", encoding="utf8") as f: markdownText = f.read()
之後使用 markdown.markdown() 這個函數編譯 markdownText 變數中的 Markdown 字元串
markdown.markdown() 有一個位置參數和若干可選參數,除了 markdown 字元串,我們還要用到參數 output_format 來設定輸出 HTML 的版本
另外,前面說過 markdown 模塊生成的 HTML 代碼是不包括 head 標籤的,需要加上它
rawHtml = self.headTag + markdown.markdown(markdownText,output_format="html5")
把變數 rawHtml 中的 HTML 的字元串寫入文件
with open(destinationDirectory + outputFileName, "w", encoding="utf8") as f: f.write(rawHtml)
有一個可選的步驟是,把上面一段代碼改成下面這段,因為 markdown 模塊生成的 HTML 代碼可閱讀性很差,可以把 rawHtml 中的 HTML 代碼用 BeautifulSoup 模塊格式化為可讀性更強的代碼
beautifyHtml = BeautifulSoup(rawHtml,"html5lib").prettify()with open(destinationDirectory + outputFileName, "w", encoding="utf8") as f: f.write(beautifyHtml)
至此,方法 markdownToHtml() 編寫完成,類 MarkdownToHtml 編寫完成
2.3 完成腳本
上一小節完成了 MarkdownToHtml 類,這一節將完成其它部分
需要在腳本文件開頭導入模塊,建議把自帶模塊放在第三方模塊前面
import sysimport os# 不使用 BeautifulSoup 模塊可不導入from bs4 import BeautifulSoupimport markdown
腳本文件支持 3 種命令行參數,分別是一個到多個 Markdown 文件路徑,選項 -s 和選項 -o,
選項 -s 是 CSS 文件路徑,選項 -o 是輸出目錄
剩下的代碼所做的工作是這樣的:根據命令行參數來使用類 MarkdownToHtml 的實例編譯一個到多個 Markdown 源文件
本實驗的剩餘代碼除了用到了下面兩個函數,只是運用 Python 的基本語法來處理一些邏輯,這裡不會細講(給出的代碼有較為詳細的注釋),各位同學可以自己先嘗試來編寫這一部分代碼
os.path.isfile() 檢測參數是否為文件路徑,是返回 True,否則返回 False
os.path.isdir() 檢測參數是否為目錄,是返回 True,否則返回 False
本實驗剩餘的所有代碼如下:
if __name__ == "__main__": mth = MarkdownToHtml() # 做一個命令行參數列表的淺拷貝,不包含腳本文件名 argv = sys.argv[1:] # 目前列表 argv 可能包含源文件路徑之外的元素(即選項信息) # 程序最後遍歷列表 argv 進行編譯 markdown 時,列表中的元素必須全部是源文件路徑 outputDirectory = None if "-s" in argv: cssArgIndex = argv.index("-s") +1 cssFilePath = argv[cssArgIndex] # 檢測樣式表文件路徑是否有效 if not os.path.isfile(cssFilePath): print("Invalid Path: "+cssFilePath) sys.exit() mth.genStyle(cssFilePath) # pop 順序不能隨意變化 argv.pop(cssArgIndex) argv.pop(cssArgIndex-1) if "-o" in argv: dirArgIndex = argv.index("-o") +1 outputDirectory = argv[dirArgIndex] # 檢測輸出目錄是否有效 if not os.path.isdir(outputDirectory): print("Invalid Directory: " + outputDirectory) sys.exit() # pop 順序不能隨意變化 argv.pop(dirArgIndex) argv.pop(dirArgIndex-1) # 至此,列表 argv 中的元素均是源文件路徑 # 遍歷所有源文件路徑 for filePath in argv: # 判斷文件路徑是否有效 if os.path.isfile(filePath): mth.markdownToHtml(filePath, outputDirectory) else: print("Invalid Path: " + filePath)
可能有同學有疑問,if __name__ == "__main__": 有何作用,它的作用在於保證這個 if 塊內的代碼不會在腳本文件作為模塊導入的時候被執行
另外,使用 argparse 模塊處理命令行參數更容易也更用戶友好,在之後的課程將會使用到這個模塊
2.4 測試腳本
使用 wget 把這個測試用 markdown 文件下載下來
$ wget http://labfile.oss.aliyuncs.com/courses/580/test.md
以及 CSS 文件
$ wget http://labfile.oss.aliyuncs.com/courses/580/GithubMarkdownCSS.css
把 markdown 文件複製多份
假設你的腳本名字為 mth.py;markdown 文件有 test.md,test2.md,test3.md;且當前目錄有 Desktop 這個子目錄。那麼可以運行下面的命令來測試你的腳本文件,注意是 python3 而不是python
$ python3 mth.py test.md test2.md test3.md -s ./GithubMarkdownCSS.css -o ./Desktop
你可以用瀏覽器打開生成的 HTML 文件查看效果
三、實驗總結
本實驗完成後,知道了如何安裝 Python3 的模塊,這與 Python2 有很大的不同,明白怎樣操作文件更安全,了解了如何使用 markdown 模塊來編譯 markdown 輸出 HTML ,熟悉了使用 os 模塊進行路徑相關的操作,以及模仿系統命令實現了程序命令行選項
四、完整代碼
本節完整代碼及第二第三部分詳細教程,可在實驗樓中查看並在線完成,立即【開始實驗】
第二部分. 文本文件編碼檢測與轉換
第三部分. 文件校驗五、參考資料
- Python 3 官方文檔
- markdown 模塊文檔
- BeautifulSoup 模塊文檔
推薦閱讀:
※跟黃哥學習python第四章
※使用python操縱metasploit簡單小記
※人人都愛數據科學家!Python數據科學精華實戰課程系列教程連載 ----長期更新中,敬請關注!
※Python3中BeautifulSoup的使用方法
※用Python做Lorenz attrator的動畫模擬