markdown中寫下你的文章,并使用Python將它們轉換成HTML-作者Florian Dahlitz,于2020年5月18日(15分鐘)
介紹
幾個月前,我想開通自己的博客,而不是使用像Medium這樣的網站。這是一個非常基礎的博客,所有的文章都是HTML形式的。然而,有一天,我突然產生了自己編寫Markdown到HTML生成器的想法,最終這將允許我用markdown來編寫文章。此外,為它添加諸如估計閱讀時間之類的擴展特性會更容易。長話短說,我實現了自己的markdown到HTML生成器,我真的很喜歡它!
在本系列文章中,我想向您展示如何構建自己的markdown到HTML生成器。該系列由三部分組成:
第一部分(本文)介紹了整個管線的實現。
第二部分通過一個模塊擴展了實現的管線,該模塊用于計算給定文章的預計閱讀時間。
第三部分演示如何使用管線生成自己的RSS摘要。
這三部分中使用的代碼都可以在GitHub上找到。
備注:我的文章中markdown到HTML生成器的想法基于Anthony Shaw文章中的實現。
項目構建
為了遵循本文的內容,您需要安裝幾個軟件包。我們把它們放進requirements.txt文件。
Markdown是一個包,它允許您將markdown代碼轉換為HTML。之后我們用Flask產生靜態文件。
但在安裝之前,請創建一個虛擬環境,以避免Python安裝出現問題:
激活后,您可以使用pip安裝requirements.txt中的依賴。
很好!讓我們創建幾個目錄來更好地組織代碼。首先,我們創建一個app目錄。此目錄包含我們提供博客服務的Flask應用程序。所有后續目錄都將在app目錄內創建。其次,我們創建一個名為posts的目錄。此目錄包含要轉換為HTML文件的markdown文件。接下來,我們創建一個templates目錄,其中包含稍后使用Flask展示的模板。在templates目錄中,我們再創建兩個目錄:
posts包含生成的HTML文件,這些文件與應用程序根目錄中posts目錄中的文件相對應。
shared包含在多個文件中使用的HTML文件。
此外,我們還創建了一個名為services的目錄。該目錄將包含我們在Flask應用程序中使用的模塊,或者為它生成某些東西。最后,創建一個名為static的目錄帶有兩個子目錄images和css。自定義CSS文件和文章的縮略圖將存儲在此處。
您的最終項目結構應如下所示:
令人驚嘆!我們完成了一般的項目設置。我們來看看Flask的設置。
Flask設置
路由
我們在上一節安裝了Flask。但是,我們仍然需要一個Python文件來定義用戶可以訪問的端點。在app目錄中創建main.py并將以下內容復制到其中。
該文件定義了一個具有兩個端點的基礎版Flask應用程序。用戶可以使用/route訪問第一個端點返回索引頁,其中列出了所有文章。
第二個端點是更通用的端點。它接受post的名稱并返回相應的HTML文件。
接下來,我們通過向app目錄中添加一個__init__.py,將其轉換為一個Python包。此文件為空。如果您使用UNIX計算機,則可以從項目的根目錄運行以下命令:
模板
現在,我們創建兩個模板文件index.html以及layout.html,都存儲在templates/shared目錄中。這個layout.html模板將用于單個博客條目,而index.html模板用于生成索引頁,從中我們可以訪問每個帖子。讓我們從index.html模板開始。
它是一個基本的HTML文件,其中有兩個元標記、一個標題和兩個樣式表。注意,我們使用一個遠程樣式表和一個本地樣式表。遠程樣式表用于啟用Bootstrap[1]類。第二個是自定義樣式。我們晚點再定義它們。
HTML文件的主體包含一個容器,其中包含Jinja2[2]邏輯,用于為每個post生成Bootstrap卡片[3]。您是否注意到我們不直接基于變量名訪問這些值,而是需要將[0]添加到其中?這是因為文章中解析的元數據是列表。實際上,每個元數據元素都是由單一元素組成的列表。我們稍后再看。到目前為止,還不錯。讓我們看看layout.html模板。
如你所見,它比前一個短一點,簡單一點。文件頭與index.html文件很相似,除了我們有不同的標題。當然,我們可以共用一個模板,但是我不想讓事情變得更復雜。
body中的容器僅定義一個h1標記。然后,我們提供給模板的內容被插入并呈現。
樣式
正如上一節所承諾的,我們將查看自定義CSS文件style.css. 我們在static/css中找到該文件,并根據需要自定義頁面。下面是我們將用于基礎示例的內容:
我不喜歡Bootstrap中blockquotes的默認外觀,所以我們在左側添加了一點間距和邊框。此外,blockquote段落底部的頁邊空白將被刪除。不刪除的話看起來很不自然。
最后但并非最不重要的是,左右兩邊的填充被刪除。由于兩邊都有額外的填充,縮略圖沒有正確對齊,所以在這里刪除它們。
到現在為止,一直都還不錯。我們完成了關于Flask的所有工作。讓我們開始寫一些帖子吧!
寫文章
正如標題所承諾的,你可以用markdown寫文章-是的!在寫文章的時候,除了保證正確的markdown格式外,沒有其他需要注意的事情。
在完成本文之后,我們需要在文章中添加一些元數據。此元數據添加在文章之前,并由三個破折號分隔開來---。下面是一個示例文章(post1.md)的摘錄:
注意:您可以在GitHub庫的app/posts/post1.md中找到完整的示例文章。
在我們的例子中,元數據由標題、副標題、類別、發布日期和index.html中卡片對應縮略圖的路徑組成.
我們在HTML文件中使用了元數據,你還記得嗎?元數據規范必須是有效的YAML。示例形式是鍵后面跟著一個冒號和值。最后,冒號后面的值是列表中的第一個也是唯一的元素。這就是我們通過模板中的索引運算符訪問這些值的原因。
假設我們寫完了文章。在我們可以開始轉換之前,還有一件事要做:我們需要為我們的帖子生成縮略圖!為了讓事情更簡單,只需從你的電腦或網絡上隨機選取一張圖片,命名它為placeholder.jpg并把它放到static/images目錄中。GitHub存儲庫中兩篇文章的元數據包含一個代表圖像的鍵值對,值是placeholder.jpg。
注意:在GitHub存儲庫中,您可以找到我提到的兩篇示例文章。
markdown到HTML轉換器
最后,我們可以開始實現markdown to HTML轉換器。因此,我們使用我們在開始時安裝的第三方包Markdown。我們先創建一個新模塊,轉換服務將在其中運行。因此,我們在service目錄中創建了converter.py。我們一步一步看完整個腳本。您可以在GitHub存儲庫中一次查看整個腳本。
首先,我們導入所需的所有內容并創建幾個常量:
ROOT指向我們項目的根。因此,它是包含app的目錄。
POSTS_DIR是以markdown編寫的文章的路徑。
TEMPLATE_DIR分別指向對應的templates目錄。
BLOG_TEMPLATE_文件存儲layout.html的路徑。
INDEX_TEMPLATE_FILE是index.html
BASE_URL是我們項目的默認地址,例如。https://florian-dahlitz.de.默認值(如果不是通過環境變量DOMAIN提供的話)是http://0.0.0.0:5000。
接下來,我們創建一個名為generate_entries的新函數。這是我們定義的唯一一個轉換文章的函數。
在函數中,我們首先獲取POSTS_DIR目錄中所有markdown文件的路徑。pathlib的awesome glob函數幫助我們實現它。
此外,我們定義了Markdown包需要使用的擴展。默認情況下,本文中使用的所有擴展都隨它的安裝一起提供。
注意:您可以在文檔[4]中找到有關擴展的更多信息。
此外,我們實例化了一個新的文件加載程序,并創建了一個在轉換項目時使用的環境。隨后,將創建一個名為all_posts的空列表。此列表將包含我們處理后的所有帖子。現在,我們進入for循環并遍歷POSTS_DIR中找到的所有文章。
我們啟動for循環,并打印當前正在處理的post的路徑。如果有什么東西出問題了,這尤其有用。然后我們就知道,哪個文章的轉換失敗了。
接下來,我們在默認url之后增加一部分。假設我們有一篇標題為“面向初學者的Python”的文章。我們將文章存儲在一個名為python-for-beginners.md,的文件中,因此生成的url將是http://0.0.0.0:5000/posts/python-for-beginners。
變量url_html存儲的字符串與url相同,只是我們在末尾添加了.html。我們使用此變量定義另一個稱為target_file.的變量。變量指向存儲相應HTML文件的位置。
最后,我們定義了一個變量md,它表示markdown.Markdown的實例,用于將markdown代碼轉換為HTML。您可能會問自己,為什么我們沒有在for循環之前實例化這個實例,而是在內部實例化。當然,對于我們這里的小例子來說,這沒有什么區別(只是執行時間稍微短一點)。但是,如果使用諸如腳注之類的擴展來使用腳注,則需要為每個帖子實例化一個新實例,因為腳注添加后就不會從此實例中刪除。因此,如果您的第一篇文章使用了一些腳注,那么即使您沒有明確定義它們,所有其他文章也將具有相同的腳注。
讓我們轉到for循環中的第一個with代碼塊。
實際上,with代碼塊打開當前post并將其內容讀入變量content。之后調用_md.convert將以markdown方式寫入的內容轉換為HTML。隨后,env環境根據提供的模板BLOG_TEMPLATE_FILE(即layout.html如果你還記得的話)渲染生成的HTML。
第二個with 代碼塊用于將第一個with 代碼塊中創建的文檔寫入目標文件。
以下三行代碼從元數據中獲取發布日期(被發布的日期),將其轉換為正確的格式(RFC 2822),并將其分配回文章的元數據。此外,生成的post_dict被添加到all_posts列表中。
我們現在出了for循環,因此,我們遍歷了posts目錄中找到的所有posts并對其進行了處理。讓我們看看generate_entries函數中剩下的三行代碼。
我們按日期倒序對文章進行排序,所以首先顯示最新的文章。隨后,我們將文章寫到模板目錄一個新創建的index.html文件中。別把index.html錯認為templates/shared目錄中的那個。templates/shared目錄中的是模板,這個是我們要使用Flask服務的生成的。
最后我們在函數generate_entries之后添加以下if語句。
這意味著如果我們通過命令行執行文件,它將調用generate_entries函數。
太棒了,我們完成了converter.py腳本!讓我們從項目的根目錄運行以下命令來嘗試:
您應該看到一些正在轉換的文件的路徑。假設您編寫了兩篇文章或使用了GitHub存儲庫中的兩篇文章,那么您應該在templates目錄中找到三個新創建的文件。首先是index.html,它直接位于templates目錄中,其次是templates/posts目錄中的兩個HTML文件,它們對應于markdown文件。
最后啟動Flask應用程序并轉到http://0.0.0.0:5000。
總結
太棒了,你完成了這個系列的第一部分!在本文中,您已經學習了如何利用Markdown包創建自己的Markdown to HTML生成器。您實現了整個管線,它是高度可擴展的,您將在接下來的文章中看到這一點。
希望你喜歡這篇文章。一定要和你的朋友和同事分享。如果你還沒有,考慮在Twitter上關注我@DahlitzF或者訂閱我的通知,這樣你就不會錯過任何即將發表的文章。保持好奇心,不斷編碼!
參考文獻
Bootstrap (http://getbootstrap.com/)
Primer on Jinja Templating (https://realpython.com/primer-on-jinja-templating/)
Bootstrap Card (https://getbootstrap.com/docs/4.4/components/card/)
Python-Markdown Extensions (https://python-markdown.github.io/extensions/)
Tweet
英文原文:https://florian-dahlitz.de/blog/build-a-markdown-to-html-conversion-pipeline-using-python
譯者:阿布銩
4 種方式可以在 HTML 中引入 CSS。其中有 2 種方式是在 HTML 文件中直接添加 CSS 代碼,另外兩種是引入 外部 CSS 文件。下面我們就來看看這些方式和它們的優缺點。
內聯方式
內聯方式指的是直接在 HTML 標簽中的 style 屬性中添加 CSS。
示例:
<div style="background: red"></div>
這通常是個很糟糕的書寫方式,它只能改變當前標簽的樣式,如果想要多個 <div> 擁有相同的樣式,你不得不重復地為每個 <div> 添加相同的樣式,如果想要修改一種樣式,又不得不修改所有的 style 中的代碼。很顯然,內聯方式引入 CSS 代碼會導致 HTML 代碼變得冗長,且使得網頁難以維護。
嵌入方式
嵌入方式指的是在 HTML 頭部中的 <style> 標簽下書寫 CSS 代碼。
示例:
<head> <style> .content { background: red; } </style> </head>
嵌入方式的 CSS 只對當前的網頁有效。因為 CSS 代碼是在 HTML 文件中,所以會使得代碼比較集中,當我們寫模板網頁時這通常比較有利。因為查看模板代碼的人可以一目了然地查看 HTML 結構和 CSS 樣式。因為嵌入的 CSS 只對當前頁面有效,所以當多個頁面需要引入相同的 CSS 代碼時,這樣寫會導致代碼冗余,也不利于維護。
鏈接方式
鏈接方式指的是使用 HTML 頭部的 <head> 標簽引入外部的 CSS 文件。
示例:
<head> <link rel="stylesheet" type="text/css" href="style.css"> </head>
這是最常見的也是最推薦的引入 CSS 的方式。使用這種方式,所有的 CSS 代碼只存在于單獨的 CSS 文件中,所以具有良好的可維護性。并且所有的 CSS 代碼只存在于 CSS 文件中,CSS 文件會在第一次加載時引入,以后切換頁面時只需加載 HTML 文件即可。
導入方式
導入方式指的是使用 CSS 規則引入外部 CSS 文件。
示例:
<style> @import url(style.css); </style>
比較鏈接方式和導入方式
鏈接方式(下面用 link 代替)和導入方式(下面用 @import 代替)都是引入外部的 CSS 文件的方式,下面我們來比較這兩種方式,并且說明為什么不推薦使用 @import。
小結:我們應盡量使用 <link> 標簽導入外部 CSS 文件,避免或者少用使用其他三種方式。
享興趣,傳播快樂,增長見聞,留下美好!親愛的您,這里是Learning yard新學苑。今天小編為大家帶來話說前端(5)|css的引入。
Share interest, spread happiness, increase knowledge, and leave behind beauty! Dear you, this is Learning yard New Academy. Today, Xiaobian brings you the introduction of front-end (5)|css.
前面咱們學過html,那現在就開始學習css,css是用來美化html的樣式,可以是我們的頁面更加美觀,現在講一講css的引入方法。
We have learned html before, so let's start learning css now. css is a style used to beautify html, which can make our pages more beautiful. Now let's talk about the introduction method of css.
首先,css的引入有兩種方式,一種是在標簽內部寫入樣式,例如<font color=”red”></font>,這里的color=“red”就是css樣式,引用方式是內聯式的。但是這種方法的耦合程度太高,不利于我們后續的增刪改和維護,所以不太容易采用。
First of all, there are two ways to introduce css. One way is to write styles inside the tags, such as < font color = "red" > </font >. Here, color = "red" is css style, and the quotation method is inline. However, the coupling degree of this method is too high, which is not conducive to our subsequent addition, deletion and maintenance, so it is not easy to adopt.
第二種就是外聯式,大家知道,寫代碼的時候要寫三部分<html><head></head><body></body></html>,外聯式的css就寫在< head ></ head >中間,要在其中寫<style></style>然后就可以寫css的樣式,然后直接寫標簽的名字即可,例如<style>li{color:red;}</style>,就可以使li的字體變成紅色,其他的選擇器我們下次再學。
The second one is outreach. As we all know, when writing code, you have to write three parts < html > < head ></ head > < body > </html >. Outreach css is written in the middle of < head > </head >. You should write < style></style > in it, then you can write the style of css, and then write the label directly. }</style >, you can turn li's font into red, and we'll learn other selectors next time.
今天的分享就到這里了。如果您對今天的文章有什么獨特的想法,歡迎評論留言,讓我們相約明天,祝您今天過得開心快樂!
That's all for today's sharing. If you have any unique ideas about today's article, please comment and leave a message. Let's make an appointment tomorrow and wish you a happy day!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。