本文為《爬著學(xué)Python》系列第十二篇文章慷荔。
本來打算周更的膀钠,鴿了好幾個星期杖刷。原因一個是面向?qū)ο竽瞧獙嵲谟悬c難寫斤儿,另一個是我去弄了個Web項目-Qotes剧包,GitHub地址。之前跟著書和實驗樓的在線課試過幾次Flask往果,這次是真正的實戰(zhàn)疆液。
體驗還算不錯。
于是本專題說好了講爬蟲的陕贮,結(jié)果第一個大實踐內(nèi)容是web項目實戰(zhàn)堕油。本文就算在介紹Flask框架之前先給個實例,以后根據(jù)此實例展開講細(xì)節(jié)吧肮之。
Qotes開發(fā)初衷
再貼一下鏈接Qotes掉缺。
其實項目的開發(fā)初衷在網(wǎng)站中寫了。我本來在簡書寫這個專題是為了整理知識的戈擒,因為簡書的Markdown編輯器很好用眶明。但是我后來發(fā)現(xiàn)一個問題,簡書采取了筆記類應(yīng)用的文檔管理方式筐高,就是一個筆記簿里面可以加一篇篇的筆記搜囱,但是筆記里面不能再加筆記,也不能在筆記簿里面再創(chuàng)建筆記簿柑土。這給我?guī)砹撕艽蟮睦_
我解釋一下我困擾的地方在哪里蜀肘。
- 可以看到我的文集里面小說分了正文和設(shè)定兩個部分,要是可以把這兩個文集放在一個文件夾“小說”中不就和上面的其他文集邏輯一致了嗎冰单,但是這做不到幌缝,除非我把小說設(shè)定的一系列文章混在小說正文文集的頭或者尾部。
- 文集內(nèi)部也會存在問題诫欠。比如說“日記本”里面是我的一些雜亂的零碎的隨時筆記。但是單一的結(jié)構(gòu)讓我很難將這些筆記進(jìn)行整理浴栽。比如《mongodb tips》這里面其實可以分好幾篇文章荒叼,但是如果分開來,那么又和該文集中的其他文章邏輯不一致了典鸡。
總結(jié)起來就是:1文集不能包含2文章不能包含被廓。
我后來想過別的方案。最靠譜的是這個:用Typora在Github上寫學(xué)習(xí)筆記萝玷。
但是總覺得有些大材小用了嫁乘,而且Github打開的速度不太理想(大多數(shù)時候正常昆婿,有時要2s左右,很難受)蜓斧,更大問題在于Github的private repository需要收費仓蛆,收費就算了還不方便。功能更符合這個應(yīng)用場景的GitHub pages又被墻挎春,體驗實在算不上好看疙。于是還是決定用簡書。于是還是有些不舒服直奋。
后來覺得還是自己寫一個吧能庆。于是我就試著寫了。
Qotes的特點
卡片
首先要解決的是文章和文集的包含問題脚线。最后我的解決方案是這樣的:
- 所有的筆記都是卡片形式存在
- 所有卡片在數(shù)據(jù)庫中地位是同樣的搁胆,保存在同一個collection中
- 卡片可以互相包含,每個卡片不一定有子卡片邮绿,但一定會有父結(jié)點
- 如果父結(jié)點是用戶丰涉,那么該卡片就可視為卡片集
- 當(dāng)然,每個卡片都可以看成是某卡片集的子卡片集
總結(jié)起來就是斯碌,每個卡片既是卡片又是卡片集一死。
在數(shù)據(jù)庫中等價就好像是樹結(jié)點在內(nèi)存中散布但是通過鏈接來形成樹結(jié)構(gòu),唯一的不同是root根結(jié)點有的時候是用戶傻唾,而且樹結(jié)構(gòu)一般鏈接記錄子結(jié)點信息投慈,但是本實例中卡片通過父結(jié)點信息完成結(jié)構(gòu)的鏈接。這樣做的原因是:
- 為了方便查詢冠骄,給相關(guān)字段設(shè)置索引以后伪煤,查詢速度倒比根據(jù)某個結(jié)點的子結(jié)點表中的id一個個查詢來得更快(理論上)
- 為了簡化IO操作。每個結(jié)點只能有一個父結(jié)點但是可以有許多個子結(jié)點凛辣。如果記錄子結(jié)點信息要對列表進(jìn)行操作抱既,而且卡片所屬關(guān)系的時候會涉及新舊父結(jié)點兩個卡片,當(dāng)前邏輯下只需要把該卡片的父結(jié)點信息改掉就可以扁誓。
這樣做也帶來一些問題防泵。比如說一個卡片不能屬于多個卡片,但是我所參考的傳統(tǒng)樹結(jié)構(gòu)也是不支持一個子結(jié)點有多個父結(jié)點的蝗敢。我后來開發(fā)過程中想了下捷泞,整體思路上其實和Linux的文件系統(tǒng)一切皆文件的設(shè)計有些類似,但是實現(xiàn)方式上有一些區(qū)別寿谴。
更多的實現(xiàn)細(xì)節(jié)在以后的文章中分析吧锁右。
Markdown
另一個特點就是Markdown了。首先語類上基本上要比簡書全,但是不如GFM咏瑟。當(dāng)然原則是保持Markdown的精神拂到,用純文本快速構(gòu)建文檔結(jié)構(gòu)。因此卡片的標(biāo)題直接就是卡片內(nèi)容中的<h1></h1>
亦即# title
码泞,二級標(biāo)題h2
和## subtitle
作為卡片內(nèi)容概要兄旬。這些基本內(nèi)容作為卡片預(yù)覽時候的信息。
比如說這個卡片編輯的時候不用寫標(biāo)題浦夷, 標(biāo)題和概要會自動生成辖试。
說起來簡書的文章需要標(biāo)題,文章里面又可以用<h1></h1>
其實困擾了我很久劈狐。如果不寫罐孝,文章內(nèi)容沒有一級標(biāo)題直接用二級標(biāo)題是不符合Markdown規(guī)范的,但是如果寫了肥缔,從網(wǎng)頁來看文章有兩個標(biāo)題其實是不符合HTML規(guī)范的莲兢。在markdown文件中不存在這個問題在于文件名并不算在文件內(nèi)容中,所以markdown文件可以完全符合markdown規(guī)范填寫续膳,給且僅給一個一級標(biāo)題改艇。
您也別笑我迂腐,HTML規(guī)范改到HTML5以后強調(diào)了HTML只負(fù)責(zé)內(nèi)容分級坟岔,把布局和格式交給CSS和JS來做谒兄。其實就是這種精神,而Markdown和HTML一樣是標(biāo)記語言社付,老前輩都在學(xué)習(xí)進(jìn)步承疲,見賢思齊是應(yīng)該的。
另外值得說的就是首頁的快速編輯模式鸥咖。
右邊的這個是一個編輯器燕鸽。是的,除了輸入內(nèi)容和提交按鈕什么都沒有啼辣,實時輸入啊研,實時轉(zhuǎn)化成HTML預(yù)覽,和Typora類似鸥拧。這個其實也是Markdown的精神党远,簡化輸入的同時完成格式。
技術(shù)選型
后端住涉,為了快速開發(fā)麸锉,選擇了Flask。為了方便迭代舆声,數(shù)據(jù)庫選擇了MongoDB。當(dāng)然,還有別的原因媳握,比如我比較熟悉Flask碱屁,我想嘗試一下NoSQL。
前端沒什么好說的蛾找,Bootstrap簡直是我的救星娩脾。中間學(xué)了半天Javascript和jQuery寫了幾個簡單的交互。兩種Markdown編輯器都是從Github找的開源編輯器打毛,說實話找這兩個編輯器的時間比我自己寫前面提到的幾個腳本的時間要長柿赊。
其實我有考慮在RESTful API寫完,把前端改成AJAX以后幻枉,UI優(yōu)化一下碰声,可能會用Golang重新寫一遍這個項目。就目前來說Flask完全夠支持業(yè)務(wù)熬甫,雖然沒做壓力測試胰挑,但是我設(shè)置的最大同時連接數(shù)才1000,不出編碼上的太大的意外肯定是足以應(yīng)付的椿肩。這不是我對自己的技術(shù)自信瞻颂,是MongoDB實在太強大了。想重構(gòu)代碼不過就是我想試一試Golang的體驗郑象。
其實選MongoDB是我心血來潮一時之間的決定贡这。Flask的MongoDB外部庫ODM沒一個好用的,真是心累厂榛,可能是我被SQLAlchemy和flask-sqlalchemy慣壞了吧盖矫。總之我后來直接用pymongo自己寫簡單映射了噪沙,代碼可能不太好看但是效果還可以炼彪,中間不斷改的時候發(fā)現(xiàn)可迭代性非常理想。在這里夸一下pymongo的文檔正歼,簡直是模范辐马,太羨慕了,是我見過的除了PythonHOWTOs以外體驗最好的文檔局义。我現(xiàn)在回來看喜爷,如果用MySQL并不會更適合我的數(shù)據(jù)結(jié)構(gòu)設(shè)計不說,開發(fā)可能還是會更麻煩的萄唇。
目前的一些坑
private card還沒做檩帐。這是我目前最緊急的TODO。
由于備案的關(guān)系另萤,我索性關(guān)閉了用戶之間交流信息的接口來規(guī)避風(fēng)險湃密,設(shè)計上是一般用戶只能創(chuàng)建自己的卡片诅挑,只能瀏覽自己的以及我的卡片。這樣基本算最大程度上利用個人博客能做的業(yè)務(wù)了泛源。用戶可以把它當(dāng)小工具拔妥,但是就備案性質(zhì)來說它還是個人博客,沒有越界达箍。
關(guān)注功能也索性直接擱置了没龙,評論功能是從一開始就沒打算做。別人的筆記缎玫,哪怕公開的硬纤,但就別BB了。當(dāng)然赃磨,如果想體驗比較完整的功能也可以發(fā)郵件給我筝家,郵箱去站點找吧,貼在這里怕被爬到時候一堆垃圾郵件煞躬。簡書的反爬實在太雞肋了肛鹏,限制數(shù)量的做法未免有點自欺欺人。
大寫加粗的移動端體驗不佳恩沛。這個其實對我來說不算太大的問題在扰。我從來沒用過簡書app編輯文章,原因可能是SE的屏幕太小了雷客。而且作為幾年的WP用戶芒珠,我已經(jīng)習(xí)慣不用手機完成電話、短信和看新聞搅裙、天氣以外的功能了(我真的不是在黑windowphone)皱卓。電腦完成工作更方便,手機碼不了代碼部逮,我的手機上除了簡書裝了不怎么用娜汁,OneNote也是不常用的。以前用WP還會用兄朋,iOS端OneNote簡直蠢掐禁,還不如打開電腦操作。
但是我仔細(xì)一思索颅和,對于我不是問題但是對于其他人不一定適用傅事。雖然Bootstrap對移動端的顯示已經(jīng)盡力了,但是我寫的主要的交互方式拖拽在手機瀏覽器上真的很難有用武之地峡扩,只能希望什么時候我能像個勞模還會樂意做個app吧蹭越。
于是這篇文章其實和Flask關(guān)系不大
不是這樣的。這篇文章只是先介紹一下實踐項目教届。中間還是有非常多的經(jīng)驗值得交流的响鹃。Flask和MongoDB的協(xié)同工作就很值得講驾霜,應(yīng)用部署方面各種坑也是值得分享的。比如說阿里從今年8月開始封禁ECS出25端口就浪費了我很多時間來排查問題茴迁。比如centos用yum裝supervisor是有多么難受寄悯,比如flask-wtform WTForms和flask-bootstrap quick_form到底該如何取舍萤衰。至于光頭哥Flask Web Development那本書里面的各種時代坑就不談了堕义。
鏈接
- Qotes
- 項目GitHub地址
- 其他等更新技術(shù)相關(guān)文章的時候根據(jù)不同內(nèi)容再寫吧。