• python:bottle + eel 模仿 mdict 查英汉词典


    Eel 是一个轻量的 Python 库,用于制作简单的类似于离线 HTML/JS GUI 应用程序,并具有对 Python 功能和库的完全访问权限。

    Eel 托管一个本地 Web 服务器,允许您使用 Python 注释函数(annotate functions),可以从 JavaScript 调用python函数,也可以从python调用JavaScript函数。

    Eel 基于 Bottle 和 gevent 构建,它们提供了类似于 JavaScript 的异步事件循环。

    用chrome 访问 https://www.lfd.uci.edu/~gohlke/pythonlibs/#python-lzo
    下载 python_lzo-1.14-cp38-cp38-win_amd64.whl
    pip install python_lzo-1.14-cp38-cp38-win_amd64.whl

    pip install readmdict ;

    pip install eel

    Eel-0.16.0.tar.gz (24 kB)
    bottle-websocket-0.2.9.tar.gz (2.0 kB)
    whichcraft-0.6.1-py2.py3-none-any.whl (5.2 kB)
    gevent_websocket-0.10.1-py3-none-any.whl (22 kB)
    gevent-23.9.1-cp310-cp310-win_amd64.whl (1.5 MB)
    zope.event-5.0-py3-none-any.whl (6.8 kB)

    编写 mdict_eel.py 如下

    1. # -*- coding: utf-8 -*-
    2. """ web server 用于查询英汉词典 """
    3. import os
    4. import sys
    5. import json
    6. import time
    7. from readmdict import MDX
    8. import bottle
    9. from bottle import route, post, request, static_file
    10. import eel
    11. import win32com.client # TTS
    12. sapi = win32com.client.Dispatch("SAPI.SpVoice")
    13. start_time = time.time()
    14. os.chdir("/mdict")
    15. # 加载.mdx文件
    16. filename = "your.mdx"
    17. mdx = MDX(filename)
    18. headwords = [*mdx] # 单词名列表
    19. items = [*mdx.items()] # 释义html源码列表
    20. n = len(headwords)
    21. m = len(items)
    22. if n == m:
    23. print(f'{filename} 加载成功:共{n}条')
    24. end_time = time.time()
    25. print('cost %f second' % (end_time - start_time))
    26. else:
    27. print(f'ERROR:加载失败 {n}!={m}')
    28. sys.exit(1)
    29. app = bottle.Bottle()
    30. # 静态资源的目录通常称为public或static
    31. @app.route('/')
    32. def server_static(filepath):
    33. return static_file(filepath, root='./')
    34. def eng_han(txt):
    35. """ 英译中 """
    36. if not txt.isascii():
    37. return 'Maybe text is not english'
    38. word = txt.encode()
    39. word1 = txt.capitalize().encode() # 第1个字母变大写
    40. global headwords, items
    41. try: # 查词,返回单词和html文件
    42. if word in headwords:
    43. wordIndex = headwords.index(word)
    44. else:
    45. wordIndex = headwords.index(word1)
    46. word,html = items[wordIndex]
    47. result = html.decode()
    48. if result.startswith('@@@LINK='):
    49. w = result[8:].strip()
    50. result = ''">' +w+ ''
    51. else:
    52. result = result.replace(''
      result = result.replace('"/thumb/', '"data/thumb/')
    53. result = result.replace('entry://', '/trans?txt=')
    54. #result = result.replace('sound://','/data/')
    55. except:
    56. result = f"

      {txt} is not in word_list.

      "
    57. return result
    58. @app.route('/prefix')
    59. def prefix():
    60. """ 前缀匹配 """
    61. try:
    62. txt = request.query.txt
    63. except:
    64. return '1: get txt error'
    65. if len(txt.strip()) ==0:
    66. return 'text is null'
    67. print(txt)
    68. if len(txt) > 1:
    69. alist = []
    70. word = txt.strip().lower() # 字母变小写
    71. for hw in headwords:
    72. hws = hw.decode().lower()
    73. if hws.startswith(word):
    74. hws = hw.decode()
    75. alist.append(hws)
    76. if len(alist) > 0:
    77. result = json.dumps(alist)
    78. else:
    79. result = '["not found"]'
    80. else:
    81. result = '["length too short"]'
    82. return result
    83. @app.route('/trans')
    84. def trans():
    85. """ method=GET 英译中"""
    86. try:
    87. txt = request.query.txt
    88. except:
    89. return '1: get txt error'
    90. if len(txt.strip()) ==0:
    91. return 'text is null'
    92. print(txt)
    93. result = eng_han(txt)
    94. return result
    95. @app.route('/trans', method='POST')
    96. def trans():
    97. """ 英译中 """
    98. try:
    99. #txt = request.forms.get('txt')
    100. txt = request.POST.get('txt')
    101. except:
    102. return '1: get txt error'
    103. if len(txt.strip()) ==0:
    104. return 'text is null'
    105. print(txt)
    106. result = eng_han(txt)
    107. return result
    108. eel.init('.')
    109. @eel.expose # 暴露python函数给js
    110. def py_speak(txt):
    111. """ text TTS """
    112. if txt.strip() !='':
    113. sapi.Speak(txt)
    114. #eel.start('index.html', app=middleware)
    115. eel.start('index5.html', app=app, size=(1000,600))
    116. #eel.start('index5.html', app=app, mode="edge", size=(1000,600))

    编写 index5.html 如下

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="utf-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>查询英汉词典title>
    8. <script src="/eel.js">script>
    9. <script src="jquery-3.2.1.min.js">script>
    10. <style>
    11. /* portrait 判断为竖屏 */
    12. @media only screen and (orientation: portrait){
    13. #lab1 {display:none;}
    14. }
    15. /* landscape 判断为横屏 */
    16. @media only screen and (orientation: landscape){
    17. #lab1 {display: ;}
    18. }
    19. style>
    20. head>
    21. <body>
    22. <form name="form" id="form" action="trans" method="POST" target="iframe">
    23. <label id="lab1">请输入:label>
    24. <input type="text" name="txt" id='txt' size="30" placeholder="请输入 a word">
    25. <input type="submit" name="eng_han" value="英译汉">
    26. <input type="button" name="btn1" id="btn1" value="前缀查询">
    27. <input type="button" name="btn2" id="btn2" value="TTS读音" onclick="tts2();">
    28. form>
    29. <p>p>
    30. <div style="float:left; width:100%;">
    31. <div id="result" style="float:left; width:80%; height:400; border:2px;">
    32. <iframe name="iframe" id="iframe" width="100%" height="400"> iframe>
    33. div>
    34. <div id="alist" style="float:right; width:20%; height:400; border:2px;">
    35. div>
    36. div>
    37. <script type="text/javascript">
    38. $(function(){
    39. $("#btn1").click(function(){
    40. $.getJSON("/prefix?txt="+$("#txt").val(), function(data){
    41. var items = [];
    42. $.each(data, function(i, item){
    43. if (i<=20){
    44. }
    45. });
    46. var a = items.join('\n');
    47. if (a) $('#alist').html(a);
    48. })
    49. })
    50. });
    51. // TTS
    52. function tts() {
    53. var txt = document.getElementById('txt').value;
    54. if (txt.length >1) eel.py_speak(txt);
    55. }
    56. // 屏幕双击取词
    57. function tts2() {
    58. // 获取iframe里的选择内容
    59. var select = window.frames['iframe'].getSelection();
    60. var txt = select.toString();
    61. if (txt.length >1) eel.py_speak(txt);
    62. else tts();
    63. }
    64. // 页面加载添加:监听iframe网页点击事件
    65. $(document).ready(function(){
    66. var listener = window.addEventListener('blur', function(){
    67. if (document.activeElement === document.getElementById('iframe')){
    68. $('iframe').contents().find('a.fayin').click(function(event){
    69. event.preventDefault();
    70. var a = $(this);
    71. if (a){
    72. var addr = a.attr('href');
    73. if (addr.indexOf('sound://')==0){
    74. var url = "/data" + addr.substring(7);
    75. var mp3 = new Audio(url);
    76. mp3.addEventListener("canplaythrough", (event)=> {
    77. mp3.play();
    78. });
    79. } else {
    80. alert('href='+addr);
    81. }
    82. }
    83. })
    84. }
    85. });
    86. });
    87. script>
    88. body>
    89. html>

    运行 python mdict_eel.py 

    个人感觉:bottle + eel 比 pywebview + cef 要好用些。

  • 相关阅读:
    协议-TCP协议-基础概念02-TCP握手被拒绝-内核参数-指数退避原则-TCP窗口-TCP重传
    php快速排序法
    CVE-2023-46227 Apache inlong JDBC URL反序列化漏洞
    算法竞赛进阶指南 捉迷藏
    逆向案例二:关键字密文解密,自定义的加密解密。基于企名片科技的爬取。
    Jetson Xavier NX 试玩 (二)
    (附源码)计算机毕业设计SSM家政信息管理平台
    npm install 报错问题解决合集
    uniapp -- 基础配置篇
    【考研复习】《操作系统原理》孟庆昌等编著课后习题+答案——第三章
  • 原文地址:https://blog.csdn.net/belldeep/article/details/133426837