V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
NeilWang
V2EX  ›  分享创造

PyWebIO——免 HTML、JS 快速构建简单 Web 应用的 Python 库

  NeilWang · 2021-01-19 16:27:11 +08:00 · 15248 次点击
这是一个创建于 1402 天前的主题,其中的信息可能已经有所发展或是发生改变。

和大家分享一下我过去一年投入主要精力写的一个 Python 库——PyWebIO 。

简单说下背景,我之前开发过一个小程序,后台经常有些管理性的操作(比如发布通知、回复反馈等),最开始是通过 ssh 运行脚本来操作,但感觉不太方便,想做成 Web 页面但又觉得写前后端接口很麻烦。

于是就很希望有一个库,只需要调用一个函数,就可以在浏览器上显示表单,用户提交后函数同步返回表单数据;然后再提供一些函数,可以实时输出各种形式的数据,比如表格、图片、Markdown 等。

这样相当于把浏览器当成了一个富文本终端,编写 Web 服务就像编写控制台程序一样只需要调用输入输出函数就可以完成交互。找来找去,也没找到满意的工具可以实现这种需求,感觉此需求是普遍存在的,就自己开坑写了一个,于是就有了 PyWebIO 。

到现在,除了支持最初设想的输入、输出函数外,PyWebIO 还支持布局、事件绑定、并发、协程、与现有的 Web 应用集成等特性,文档也十分的完善。

总结来说,PyWebIO 能够让你用编写终端程序的逻辑来编写 Web 应用,不需要编写前端页面和后端接口,非常适合在短时间内快速构建对 UI 要求不高的应用(比如自用的 Web 后台、在线小工具等)。PyWebIO 既适合从来没有接触过 Web 开发的程序员来像编写终端程序一样编写 Web 应用,又适合有 Web 开发经验的程序员在自己的 Web 应用中快速实现某些小功能。

关于 PyWebIO 对传统 Web 的优势可以进一步阅读这篇文章:Why PyWebIO

GitHub 和文档放在下面了,欢迎大家体验和提出宝贵意见🙏。

Github: https://github.com/wang0618/PyWebIO
文档: https://pywebio.readthedocs.io/ (文档里的绝大部分代码示例都有在线演示的链接)

下面是一些使用 PyWebIO 编写的 Demo 和应用:

  • 输入演示:演示 PyWebIO 输入模块的用法
  • 输出演示:演示 PyWebIO 输出模块的用法
  • 数据可视化:在 PyWebIO 中使用 bokeh 、plotly 、pyecharts 等库进行数据可视化
  • 聊天室:不到 80 行代码实现的在线聊天室
  • mtag_tool:使用 PyWebIO 编写的用于编辑 MP3 标签的应用

最后贴两个 PyWebIO 输入和输出函数调用效果的动图

output_demo

input_demo

第 1 条附言  ·  2021-01-19 17:17:14 +08:00
类似功能的工具还有 dash 和 streamlit,它们和 PyWebIO 都各有特点。

https://github.com/plotly/dash :可以用来编写全功能的 Web 页面,虽然不需要编写 html,需要先声明布局,且布局声明后无法动态改变。dash 采用“响应式”的程序模型,非常依赖回调。如果只是简单写一个小应用,dash 显得太重,需要的代码量也比 PyWebIO 更多。

https://github.com/streamlit/streamlit :可以称得上神器,功能上和 PyWebIO 很相似,streamlit 更专注于机器学习和数据科学领域。不过 streamlit 应用的编写逻辑还是没有终端程序那么自然,但熟悉之后,编写 Web 服务需要的代码量比 PyWebIO 更少,另外,streamlit 不支持整合到现有的 Web 服务。
139 条回复    2023-11-24 16:50:02 +08:00
1  2  
zh584728
    101
zh584728  
   2021-01-22 10:33:26 +08:00
再次回复,一个版本可以考虑将 echarts 加入进去吗,pyecharts 也可。
Beebird
    102
Beebird  
   2021-01-22 13:46:50 +08:00
楼主厉害!
liqt91
    103
liqt91  
   2021-01-28 10:01:21 +08:00
试了下,集成到 flask,用 gunicorn 启动时一直报错,只能用 app.run(),猜测是和进程绑定了
NeilWang
    104
NeilWang  
OP
   2021-01-29 20:04:33 +08:00
@liqt91 #103 我试了一下,没有发现 gunicorn 报错,可以的话请在 Github 上提一个 issue 。不过由于 PyWebIO 是将会话状态保存在 Server 的进程空间中的,而 PyWebIO 前端与 Flask 又是基于轮询通讯的,如果启用多个 worker,会导致状态错乱(表现就是,显示完内容后还没来得及交互会话就关闭了),目前针对这个问题还没有较好的解决方法。
longchisihai
    105
longchisihai  
   2021-02-01 08:00:13 +08:00
我这启动时候发现了一个问题,ERROR:pywebio.platform.tornado:Open http://localhost:12578 failed. 请问如何解决呢。tornado 版本:6.1 pywebio 版本: 1.0.3 windows 环境
NeilWang
    106
NeilWang  
OP
   2021-02-01 12:41:50 +08:00
@longchisihai #105 这个应该是尝试自动在浏览器中打开地址失败了,可以手动在浏览器中打开这个地址
M4rs
    107
M4rs  
   2021-02-01 13:01:33 +08:00 via iPhone
厉害!看看介绍就非常想用
liqt91
    108
liqt91  
   2021-02-01 13:02:48 +08:00
@NeilWang 对,我更正下我的描述,是启动后访问页面报错。具体情况就是你说的显示完内容就失去交互功能了,点击任何交互组件都报错
hahaha777
    109
hahaha777  
   2021-02-01 13:27:39 +08:00
666,mark 一下
NeilWang
    110
NeilWang  
OP
   2021-02-01 16:09:55 +08:00
@liqt91 #108 应该是会话自然关闭了,需要用 pywebio.session.hold() 来保持会话。参见 https://pywebio.readthedocs.io/zh_CN/latest/FAQ.html#put-buttons
下个版本会认真考虑一下是否要添加自动保持会话的支持, 目前需要使用 hold() 来手动保持会话的考量是保持 server 模式和 script 模式的逻辑一致性。
longchisihai
    111
longchisihai  
   2021-02-01 21:59:23 +08:00
@NeilWang 是的 手动打开浏览器就可以了 为什么自动打开浏览器失败呢? 能否代码层面上修复这个问题呀?我这边也设置了默认浏览器的
NeilWang
    112
NeilWang  
OP
   2021-02-01 23:34:44 +08:00
@longchisihai #111 是因为等待 server 可连通的操作超时了,现在把这个超时时间调大了: https://github.com/wang0618/PyWebIO/commit/65f581de71b4ff2ba1b8c1022f4c76826f98b24e

下个版本就包含这个修复了,在此之前,可以使用 pip3 install -U --force-reinstall https://code.aliyun.com/wang0618/pywebio/repository/archive.zip 安装开发版
NoUltimate
    113
NoUltimate  
   2021-02-02 08:54:37 +08:00
好强,不知道 java 和 go 有没有类似的
v2defy
    114
v2defy  
   2021-02-02 12:42:47 +08:00
太帅了,正是我想要的!
longchisihai
    115
longchisihai  
   2021-02-03 08:30:16 +08:00
@NeilWang #112 我这边定位到的原因是,当把 util.py 中的 wait_host_port 函数中的 try 去掉之后,会报错:
builtins.AttributeError: 'StreamWriter' object has no attribute 'wait_closed'
所以函数返回了 False 不会自动打开浏览器
NeilWang
    116
NeilWang  
OP
   2021-02-03 10:47:00 +08:00
@longchisihai #115 多谢,原来是因为 StreamWriter.wait_closed 是 py3.7 之后才引入的: https://docs.python.org/3/library/asyncio-stream.html#asyncio.StreamWriter.wait_closed

实测了一下,这个 wait_closed 调用看不出有什么影响,所以在 py3.7 之前就不调用了:
https://github.com/wang0618/PyWebIO/commit/9aa75e71e3e578d7e3d85bfe79b6d9588d41fee4
mon6912640
    117
mon6912640  
   2021-02-04 11:15:44 +08:00
有个问题,怎么获取网页连接的状态,就是那个绿色点的状态,有些浏览器(比如 qq )会反转标签页的颜色,导致绿色点是否灰色这个状态看不出来
m0cha
    118
m0cha  
   2021-02-05 02:59:37 +08:00 via iPhone
非常厉害!
fanfpy
    119
fanfpy  
   2021-02-05 13:23:21 +08:00
厉害 star 下
bbbb
    120
bbbb  
   2021-02-05 16:28:06 +08:00 via iPhone
太棒了
woniu127
    121
woniu127  
   2021-02-06 20:38:48 +08:00
厉害
lakechan96
    122
lakechan96  
   2021-02-17 15:14:43 +08:00
nice work,基于你的框架也写了个小玩意跟大家分享一下~
https://v2ex.com/t/753688
coreki
    123
coreki  
   2021-03-18 22:27:49 +08:00 via Android
这个牛逼。
RockShake
    124
RockShake  
   2021-03-19 09:03:42 +08:00
这个想法太酷了,如果有办法原生实现数据修改功能就完美了
asturias
    125
asturias  
   2021-03-19 11:20:14 +08:00
太方便了吧
jinhb
    126
jinhb  
   2021-04-05 20:10:32 +08:00 via iPhone
@liqt91 跟着教程学,到最后。集成。同样没有试试成功!失望,伤心
jinhb
    127
jinhb  
   2021-04-05 21:17:09 +08:00 via iPhone
请问有各位大佬,集成 Django 有没有成功的?
若有求 Django 版本号和 Python 版本号。
NeilWang
    128
NeilWang  
OP
   2021-04-05 22:00:13 +08:00
@jinhb django>=2.2 就可以,集成不成功具体有什么报错吗?

集成方式可以参考文档: https://pywebio.readthedocs.io/zh_CN/latest/guide.html#integration-with-web-framework
liqt91
    129
liqt91  
   2021-04-06 13:08:42 +08:00
@NeilWang 看到这个帖子想起来了,之前集成到 flask,希望写一个通过路径直接载入对应 pywebio 脚本的方式来实现:flask 判断不同的路径,再通过 python 的动态载入来载入路径对应的 pywebio 脚本。达到只需要服务端上传新 pywebio 脚本文件,不重启服务就能访问新 pywebio 应用的目的。后来发现应用是绑定 flask 主进程的,无法通过动态载入脚本的方式来访问。当然也可能是我 flask 用的不熟
NeilWang
    130
NeilWang  
OP
   2021-04-07 00:46:38 +08:00 via Android
@liqt91 #129 新版本的 pywebio 提供了一个 path-deploy 的功能,和你描述的需求是一致的,只不过后端 server 是 tornado,如果不是非得要用 flask 的话,这个可以满足你的需求。自己参照代码实现一个 flask 版本的也不麻烦
NeilWang
    131
NeilWang  
OP
   2021-04-07 10:15:02 +08:00
liqt91
    132
liqt91  
   2021-04-07 15:04:35 +08:00
@NeilWang 谢谢 没用过 tornado,不过这个功能挺需要的,后续看下。昨天看到这个帖子顶起来之后,想去用它实现个小应用:1 用户上传若干图片 2 对上传的图片手动调整顺序 3 合并为 pdf 并供用户下载。现在卡在第二步,因为第二步既是第一步的输出,也是第三步的输入。在 put_button 中回调并调整了图片的顺序,如何及时回显?
NeilWang
    133
NeilWang  
OP
   2021-04-07 16:58:54 +08:00
@liqt91 #132 可以使用 scope 机制来对输出做动态调整:将 3 个图片输出到一个 scope 中,然后在用户调整了顺序之后,清空这个 scope,并以新顺序输出图片到这个 scope 。

文档见: https://pywebio.readthedocs.io/zh_CN/latest/guide.html#output-scope
liqt91
    134
liqt91  
   2021-04-07 17:25:42 +08:00
@NeilWang 可以了,就是每次清空再回显很慢,有点影响使用体验,有局部或者快速刷新的方式吗? 另外老哥是否方便加个微信?
NeilWang
    135
NeilWang  
OP
   2021-04-08 00:15:52 +08:00
@liqt91 #134 可以用 start_server() 的 static_dir 参数设置静态文件路径,然后上传图片后先把图片保存到 static_dir 文件夹下,这样就能获取到图片的 url,使用 url 来输出图片这样浏览器就可以缓存了( put_image 支持传入图片 url 来显示图片)

我建了一个交流微信群,有问题需要即时沟通可以加群交流 https://github.com/wang0618/PyWebIO/discussions/63
jinhb
    136
jinhb  
   2021-04-10 00:27:24 +08:00 via iPhone
安装 DJ2.2 没有报错。view 页写 pywrbio 的代码就行啦。
没有安装例子方式集成
huangxin888
    137
huangxin888  
   2022-03-23 17:33:33 +08:00
来晚了!工作需要,试了 streamlit ,反应太慢不跟手,大神的 pywebio 反应快很多!
oakcdrom
    138
oakcdrom  
   2022-04-07 13:58:17 +08:00
大哥,你为什么不建个群呢,我现在遇到个问题,我读取 txt 内容,截取了部分内容,添加到 list 里。。 在 put_table 里,没法多行输出,请问是为什么呢,能给个联系方式吗。。。
jfds
    139
jfds  
   363 天前
太酷了,写小工具超级好用
1  2  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   987 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 26ms · UTC 21:16 · PVG 05:16 · LAX 13:16 · JFK 16:16
Developed with CodeLauncher
♥ Do have faith in what you're doing.