日记系统 Web 版
~ 任务需求
- 通过网页访问系统:
- 每次运行时合理的打印出过往的所有笔记
- 一次接收输入一行笔记
- 在服务端保存为文件
- 同时兼容 3w 的 Net 版本的命令行界面进行交互
~ 任务代码及说明: https://github.com/hysic/OMOOC2py/tree/master/_src/om2py4w/4wex0
任务开发记录
Bottle 框架
上下班路上通读Bottle 官网 tutorial, 只是对 bottle 的功能有个大概的印象, 但对本周作业如何实现依然没什么思路.
- 直到我读到了官网上的这个 Tutorial: Todo-List Application以及大妈的这个 Simple-todo Bottle 实现版, 终于有了个模仿对象, 至少可以照葫芦画瓢完成任务了.
- 说起官网文档看不懂的问题, 上次大妈也问过我这个问题. 我觉得是我的需求和官方文档不是一个思路. 我的需求是需要对小白从最基础的概念讲起, 每个概念都最好配上详细实例, 然后层层递进, 直至更复杂的实例. 而 Bottle 官网的 Tutorial 则力求做到面面俱到, 每一点特性都要顾及到, 反而没有什么重点. 对比下面用到的
requests
模块的官方文档, 则比较对我的胃口, 显示 Quickstart, 帮助你快速上手, 然后是 Advanced Usage, 讲一些进阶用法, 适合于不同程度的用户. 所以我目前的看法是, 官方文档不可不看, 但若不对口味, 可以 google 寻找其他对口味的教程, 先入门了再说. - 现在再回头看Bottle 官网 tutorial, 对里面的一些术语有了基本的概念, 所以对里面的内容也有了更多地理解, 所以官方文档即使开始看不懂, 在其他地方入门了之后也一定要回读官方文档.
Bottle 框架的几个函数 ~ 创建网页, 简单地说就是URL地址 + 网页内容(HTML+CSS+JS), 再就是与服务器的数据交互, Bottle 框架有几个函数分别做这几项事情.
route
路由, Bottle 中最重要的一个函数, 将 URL 与一个函数关联, 该函数的返回值则是这个 URL 对应网页的显示内容. 更重要的是, 这个 URL 可以是动态的, 可以用正则表达式涵盖好多类似的 URL 地址.route
还可以指定http 请求方法, 默认是GET
.@route('/diary') def show_diary(): return template("write_diary.tpl", diary_file=filename)
比如这段代码对应的 URL 就是
/diary
, 网页显示的内容就是write_diary.tpl
这个模板里面的内容.template
模板, 将 html 分离成一个单独的文件, 可以多次使用, 可以缓存, 同时还可以传入一些需要修改的参数. Bottle 内置了 Simple Template 引擎, 足够完成本周任务. 大妈推荐的Jinja2
模板引擎, 留待后续使用.<form action='/diary' method="POST"> <input type="text" size="100" maxlength="100" name="new_line" autofocus> <input type="submit" name="save" value="保存"> </form> <div id="diary_content"> %with open(diary_file) as f: %for line in f: <p>{{line[0: -1]}}</p> %end %end </div>
这段代码就是我实现本周任务使用的模板, 注意到最后一个
div
里还有几行以%
开头的 python 代码, 模板是允许这种写法的, 可以在模板内插入if
,for
等语句.request
, 用于服务器端和客户端之间交换数据, 比如new_line = request.POST.get('new_line', '')
用于从网页中名为new_line
的 input 元素中获取客户端的输入内容.run
, 服务器运行, 默认地址是localhost
, 默认端口是8080
. 添加reloader=True
参数可以在在修改代码后不用重启服务器, 对调试代码很有用, 但在上线后一定要删除.debug
, 调试, 可以在网页端直接显示报错信息.
最终实现的网页界面是这样婶的.
CLI 交互
- 本周任务还有一个要求:
同时兼容 3w 的 Net 版本的命令行界面进行交互
- 我开始的想法是, 把3w client 端的代码直接拿来用. 创建一个 TCP socket, 连接
localhost:8080/diary
, 然后recv
数据, 可以毫无动静. 因为我服务器端并没有设置要向客户端send
数据, 一切都是 bottle 封装好的 http 协议. - 看了一下其他同学的代码, 发现 很多都用了
requests
模块, google 之, 很diao.
Requests: HTTP for Humans
- 而且 requests 的文档写的比较符合我的胃口, Quickstart 页面就满足了我的全部要求(读数据, 发送数据), 大赞!
import requests
# get the request data from the server page
r = requests.get("127.0.0.1:8080/diary")
print r.content
# post data to the server
rw = requests.post("127.0.0.1:8080/diary", data = {'new_line': "some_message"})
- 这样输出的是包含 html 标签在内的全部网页内容, 需要进一步去除标签, 找到自己需要的那部分网页内容. google
python html
, 找到 Python Guide 的这个页面, 里面介绍了requests
模块, 还有lxml
模块, 刚好就是我需要的!! 而且,lxml
模块一共介绍了三行代码, 刚好可以完成我的要求, 太赞了!
import requests
from lxml import html
# get the request data from the server page
r = requests.get(server_address)
# parse the page content into a nice tree structure
tree = html.fromstring(r.content)
# use XPath to get to the html section you want
diary_content = tree.xpath('//div[@id="diary_content"]/p/text()')
print diary_content
任务回顾
- 其实我感觉最大的难点不在代码本身, 而在于网站的架构, 需要有几个页面, 每个页面的
get
和post
方法分别对应什么. 虽然最后只用了一个 URL, 但那是因为网站本身不复杂, 要是复杂一点, 比如做一个 todo list 网站, 就需要像大妈那样做 URI 设计)了.
下一步工作
KVDB
RESTful??