soarli博客 - Python
type: channel
link: https://blog.soarli.top/tag/Python/
items: 使用Python将EPUB文件转换为TXT文件
items: 记录一次迁移MySQL大体积数据表的实践
items: Python3.8如何解决pygame显示欢迎的问题
items: Ubuntu flask后台静默运行
items: 更新Ubuntu上的Python 3
items: 记录一款好用的基于Windows系统的OCR工具
items: 使用python来操作redis用法详解
items: 记录一次开发Typecho检索图片中文字功能的实战
items: Flask上线部署解除测试环境警告
items: Python多线程学习笔记

使用Python将EPUB文件转换为TXT文件
type: item
date: 2023-09-21T19:51:00+08:00
description: 1. 安装依赖项首先，在开始编写代码之前，我们需要确保安装了必要的依赖项。我们需要安装的主要依赖项是ebooklib和beautifulsoup4。可以使用如下命令安装它们：pip install ebooklib beautifulsoup42. 示例脚本下面是一个简单的Python脚本，实现了将EPUB文件转换为TXT文件的功能。我们将函数划分为两部分，epub_to_txt() 负责将EPUB文件内容提取为文本，save_to_txt() 则负责将提取到的文本内容保存到一个TXT文件。import os import sys from ebooklib import epub from bs4 import BeautifulSoup def epub_to_txt(epub_path): book = epub.read_epub(epub_path) output_txt = "" for item in book.get_items(): if item.media_type == 'application/xhtml+xml': content = item.get_content() soup = BeautifulSoup(content, features="html.parser") text = soup.get_text() output_txt += text + "\n" return output_txt def save_to_txt(file_path, content): with open(file_path, 'w', encoding='utf-8') as txt_file: txt_file.write(content) if __name__ == '__main__': # epub文件路径和输出txt文件路径 epub_file = sys.argv[1] txt_file = sys.argv[2] # 从epub文件中提取文本 txt_content = epub_to_txt(epub_file) # 将文本保存到txt文件 save_to_txt(txt_file, txt_content) 3. 如何使用要使用上述脚本，您只需将其保存为.py文件，例如epub_to_txt.py。然后在命令行界面运行以下命令：python epub_to_txt.py <input_epub_file> <output_txt_file>将<input_epub_file>替换为要转换的EPUB文件的路径，<output_txt_file>替换为要生成的TXT文件的路径。之后，脚本将会将EPUB文件转换为TXT文件，并将结果保存在指定的输出文件中。4. 总结这篇博客提供了一个简单、轻量级的解决方案，使用Python和第三方库EbookLib快速将EPUB文件转换为TXT文件。

记录一次迁移MySQL大体积数据表的实践
type: item
date: 2023-08-29T02:21:00+08:00
description: 近期学习实践数据库的笔记，文章内容和代码均系原创（部分知识概述型文本由soarchat 1.4和gpt4提供成文支持），转载请注明来源！前言近期因某线上场景特殊需要，得对一张6.19GB的MySQL数据表进行数据库环境的迁移，首先考虑到的方法当然是通过手头Navicat自带的导入/导出/转储功能来快速实现。但是经过半天的尝试，不管通过什么样的文件结构作为媒介，在导入的过程中总会发生一些错误问题（最好的一次还丢失了300多条数据）。在按照这种思路折腾的过程中，还发生了几次电脑的内存溢出而不得不重启OwO...于是尝试在网上搜寻关于这种问题的解决方案，谁料网上也是一片哀鸿遍野。个别能解决的，要么是让把文件导入到Linux系统中，通过Linux独有的split命令先分割再进行操作完后再取出，亦或是修改MySQL的类似于max_allowed_packet的各种配置（亲测无效），再或者就是换了其他的数据库管理工具（mysqldump之类的）。见到此状，想到了一句名言“自己动手，丰衣足食”，说干就干，在充分考虑读取大文件对内存的需求的基础上，对程序进行了严格的内存优化。最终的结果是一次执行通过，零错误零丢失，同时也没有发生内存泄漏！兴奋之余决定把总体的设计思路和程序开源到这篇文章里面，供后续有需求的人进行参考或修改/优化。如有大佬有更好的思路或优化建议，还望不吝赐教！！ ::twemoji:prayer::思路导出数据正常走Navicat的转储流程没啥问题，得到一个体积超大的sql文件之后，如何把它执行到一个新的数据库里是接下来讨论的重点问题。STEP1：拆分splitsql.py本程序的主要目标是高效地将大型SQL文件拆分成更小的文件。核心原理在于使用带缓冲区的文件读写操作，通过计数器和指定的行数限制将源文件逐行划分为多个小文件。关键步骤：1.逐行读取输入文件2.将每一行内容添加到一个临时缓存列表中，直到达到预先设定的行数限制3.新建一个带有编号的输出文件，将缓存的数据写入该文件。重复这个过程，直到遍历完整个输入文件。4.程序最后会判断是否还有剩余未处理的数据，若有，则将剩余数据写入一个新的输出文件。意义：提供了一种简洁高效的方法来处理大型SQL文件，尤其在数据库结构复杂、资源有限的场景下格外实用。此外，通过自定义行数限制和文件名前缀，用户可以根据实际需求对程序进行定制。总之，这是一个有助于简化大型数据库的维护和管理的工具。input_file_path = "table_testdata.sql" num_lines_per_file = 500 output_file_prefix = "" def split_sql_file(): with open(input_file_path, "r", encoding="utf-8", errors="ignore", buffering=8192) as input_file: file_count = 1 line_counter = 0 data = [] for line in input_file: if line_counter < num_lines_per_file: data.append(line) line_counter += 1 else: with open(f"{output_file_prefix}{file_count}.sql", "w", encoding="utf-8", buffering=8192) as output_file: output_file.writelines(data) file_count += 1 line_counter = 1 data = [line] if data: with open(f"{output_file_prefix}{file_count}.sql", "w", encoding="utf-8", buffering=8192) as output_file: output_file.writelines(data) if __name__ == '__main__': split_sql_file() STEP2：重组importsql.py程序主要功能是自动执行指定目录下的所有SQL文件。程序的核心原理在于通过连接到MySQL数据库，然后顺序执行目录中按文件名排序的SQL文件。程序首先通过配置信息创建一个数据库连接，并处理可能出现的错误。之后，它会遍历目录下所有以“.sql”为扩展名的文件，将其内容逐个加载并划分为SQL语句。为了优化批量执行效率，它将SQL语句分组成批次，并在执行过程中定时检查数据库连接是否仍然可用。该程序实现了以下功能：通过设置可配置参数及错误处理，确保连接及执行过程更为…

Python3.8如何解决pygame显示欢迎的问题
type: item
date: 2023-08-04T00:29:50+08:00
description: 问题描述：import pygame后每次运行py都会输出以下提示信息：pygame 2.4.0 (SDL 2.26.4, Python 3.8.6) Hello from the pygame community. https://www.pygame.org/contribute.html解决方案：参考资料：Python3.7如何解决Pygame显示欢迎的问题_注释pygame的欢迎_tiantian520_tt的博客-CSDN博客

Ubuntu flask后台静默运行
type: item
date: 2023-06-12T22:06:00+08:00
description: 本文由 soarAI 1.1 驱动，转载请注明来源。Ubuntu flask后台静默运行您可以使用以下命令在Ubuntu上使用Flask应用程序进行后台静默运行：nohup python3 your_flask_app.py > /dev/null 2>&1 &其中，your_flask_app.py是您的Flask应用程序的文件名。此命令将在后台启动Flask应用程序，并将输出重定向到/dev/null以避免在终端中显示输出。如果您想要停止Flask应用程序，请使用以下命令：ps aux | grep your_flask_app.py找到Flask应用程序的进程ID，然后使用以下命令杀死进程：kill -9 <process_id>其中，<process_id>是Flask应用程序的进程ID。

更新Ubuntu上的Python 3
type: item
date: 2023-06-12T21:31:00+08:00
description: 本文由 soarAI 1.1 驱动，转载请注明来源。ubuntu 更新python3您可以使用以下命令来更新Ubuntu上的Python 3：sudo apt-get update sudo apt-get install python3这将会更新您的系统上的Python 3版本到最新。如果您想要安装特定版本的Python 3，可以使用以下命令：sudo apt-get install python3.x其中，x代表您想要安装的Python 3版本号。例如，如果您想要安装Python 3.8，可以使用以下命令：sudo apt-get install python3.8sudo apt-get install python3.8执行后python3 -v仍然是3.6如果您已经安装了Python 3.8，但是在运行python3 -V时仍然显示版本为3.6，可能是因为系统中存在多个Python版本，并且3.6是默认版本。您可以尝试使用以下命令来更改默认Python版本：sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1这将会将Python 3.8设置为默认版本。然后，您可以再次运行python3 -V来验证版本是否已经更改。

记录一款好用的基于Windows系统的OCR工具
type: item
date: 2022-12-08T18:55:00+08:00
description: 前言今天无意间在网上发现了一款Windows系统可用、开源、面向普通用户、基于PaddleOCR的本地文本识别工具。经过对它的一系列配置，将本地的配置文件导出并记录在这里，方便日后在其他电脑上进行快速部署。PaddleOCR是一款基于PaddlePaddle的轻量级开源文本识别模型库，今年年初为满足毕设中证件智能识别模块开发需求做过一些研究（这里是当时对PaddleOCR的配置使用笔记）。没想到竟然能在今年年末发现有大佬从今年3月底开始同样基于这款模型库开发并开源了一款面向用户的，方便快捷的文本识别工具！相信很多人和我一样，经常会有在电脑上进行OCR操作的需求。从几年前开始我陆续使用过很多第三方的工具（如：天若OCR、QQ截图OCR等），但是它们终究都没能很好的满足我在体验方面的需求。于是自己开发了一个基于Web异步请求和百度高精接口的轻量级应用，使用范围也局限于自己和身边的个别人。毕竟使用别人的在线接口，还是会有很多不稳定性因素在里面的。原本打算年底在自己服务器上基于PaddleOCR server端模型对该应用进行重构，现在看来已经必要性不大了。Umi-OCR简介按照官方的介绍，这是一款免费，开源，可批量的离线OCR软件：兼容性系统支持 Win10 x64 及以上版本。CPU必须具有AVX指令集。出现初始化引擎失败等问题时请参考 问题排除 。地址Github地址Github Release v1.3.2地址官方提供的蓝奏云地址soarli备用地址更新日志（截至12.8）v1.3.2 2022.12.1 新功能：创建开机启动项时，可选不显示主窗口。 新功能：OCR结果输出到每个图片同名的单独txt文件。 新功能：增加独立的设置语言窗口，可在多处点开，便于切换语言。 新功能：合并段落添加合并自然段-西文模式，可在英文段落换行时补充空格。 新功能：快捷识图可选自动清空面板，只显示本次识别结果，且隐藏时间信息。 修复了一些BUG。 v1.3.1 2022.11.4 修Bug：快捷键模块重写，引入pynput库，舍弃keyboard库，解决几率失效、录制不正确等Bug。 新功能：添加开机自启，桌面快捷方式，开始菜单快捷方式。 新功能：多开软件时提示。 新功能：截图时隐藏窗口。 调整UI：使用频率极低的设置项设为隐藏的高级选项。 优化：检查引擎组件是否存在。 优化：横排-合并多行-自然段 优化逻辑，支持0~2全角空格首行缩进。 v1.3.0 2022.9.29 新功能：框选截屏。 新功能：系统托盘图标。 新功能：引擎进程常驻。 新功能：文本块后处理模块。 新功能：自定义主输出栏字体。 新功能：设置窗口弹出模式（保持置顶）。 调整UI：自适应Win风格组件。 修正了Bug：系统语言兼容性问题 issue #16 。 修正了Bug：微信图片粘贴问题 issue #22 。 更新PaddleOCR-json模块至v1.2.1，提供剪贴板支持。快捷识图通过剪贴板中转，无需再保存临时文件到硬盘。 v1.2.6 2022.9.1 更新PaddleOCR-json模块至v1.2.0，提高识别速度、准确度。 调整UI：更方便地用下拉框切换识别语言。 调整UI：可以从主窗口任意位置/任意选项卡拖入图片。 修正了Bug：提高程序健壮性，增加启动子进程时的更多异常处理情况。 修正了Bug：彻底解决了对边缘过窄的图片，识别结果不准确的问题 issue #7 。 优化适配PP-OCRv3模型，彻底解决了v3版模型比v2慢、不准的问题 issue #4 。 v1.2.5 2022.7.22 新功能：计划任务。识图完成后执行自动关机等任务。 新功能：可选拖入文件夹时递归导入子文件夹中所有图片。 调整UI：添加一些配置文件的快捷入口。 v1.2.4 2022.6.4 新功能：可选识别剪贴板图片后自动复制识别的文本。 补充功能：快捷键调用剪贴板识图时，若程序窗口被最小化，则恢复前台状态并挪到最前位置。 v1.2.3 2022.5.31 新功能：读取剪贴板图片。配置全局快捷键调用该功能。 v1.2.2 2022.4.30 新功能：可选任务完成后自动打开输出文件或目录。 v1.2.1 2022.4.16 更新PaddleOCR-json模块至v1.1.1，修正了可能得到错误包围盒的漏洞。 v1.2.0 2022.4.8 可选生成图文链接.md文件，作为索引使用有更佳的观感。 修改设置面板的样式，改为滚动面板以容纳更多设置选项。 用户修改配置项后可自动保存。 v1.1.1 2022.3.30 修正了Bug：退出忽略区域窗口时，OCR子进程未关闭。 v1.1.0 2022.3.30 新功能：忽略区域窗口以虚线框 展示识别出的文字块。 v1.0.0 2022.3.28 “梦开始…

使用python来操作redis用法详解
type: item
date: 2022-06-26T17:06:00+08:00
description: 本文转载自互联网，已在文末注明来源。1、redis连接redis提供两个类Redis和StrictRedis用于实现Redis的命令，StrictRedis用于实现大部分官方的命令，并使用官方的语法和命令，Redis是StrictRedis的子类，用于向后兼容旧版本的redis-py。redis连接实例是线程安全的，可以直接将redis连接实例设置为一个全局变量，直接使用。如果需要另一个Redis实例（or Redis数据库）时，就需要重新创建redis连接实例来获取一个新的连接。同理，python的redis没有实现select命令。安装redispip install redis连接redis，加上decode_responses=True，写入的键值对中的value为str类型，不加这个参数写入的则为字节类型。import redis # 导入redis模块，通过python操作redis 也可以直接在redis主机的服务端操作缓存数据库 r = redis.Redis(host='localhost', port=6379, decode_responses=True) # host是redis主机，需要redis服务端和客户端都启动 redis默认端口是6379 r.set('name', 'junxi') # key是"foo" value是"bar" 将键值对存入redis缓存 print(r['name']) print(r.get('name')) # 取出键name对应的值 print(type(r.get('name')))2、连接池redis-py使用connection pool来管理对一个redis server的所有连接，避免每次建立、释放连接的开销。默认，每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池，然后作为参数Redis，这样就可以实现多个Redis实例共享一个连接池连接池import redis # 导入redis模块，通过python操作redis 也可以直接在redis主机的服务端操作缓存数据库 pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True) # host是redis主机，需要redis服务端和客户端都起着 redis默认端口是6379 r = redis.Redis(connection_pool=pool) r.set('gender', 'male') # key是"gender" value是"male" 将键值对存入redis缓存 print(r.get('gender')) # gender 取出键male对应的值3、redis基本命令 Stringset(name, value, ex=None, px=None, nx=False, xx=False)在Redis中设置值，默认，不存在则创建，存在则修改参数：ex，过期时间（秒）px，过期时间（毫秒）nx，如果设置为True，则只有name不存在时，当前set操作才执行xx，如果设置为True，则只有name存在时，当前set操作才执行1.ex，过期时间（秒） 这里过期时间是3秒，3秒后p，键food的值就变成Noneimport redis pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True) r = redis.Redis(connection_pool=pool) r.set('food', 'mutton', ex=3) # key是"food" value是"mutton" 将键值对存入redis缓存 print(r.get('food')) # mutton 取出键food对应的值2.px，过期时间（豪秒） 这里过期时间是3豪秒，3毫秒后，键foo的值就变成Noneimport redis pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True) r = redis.Redis(connection_pool=pool) r.set('food', 'beef', px=3) print(r.get('food'))3.nx，如果设置为True，则只有name不存在时，当前set操作才执行 （新建）import redis pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=Tru…

记录一次开发Typecho检索图片中文字功能的实战
type: item
date: 2022-04-07T02:08:00+08:00
description: 配置Typecho文本识别能力项目实战笔记，内容原创，转载请注明来源！前言早在去年参与苹果iOS 15内测中体验其在全局融入的文字识别能力以及相册场景文本搜索功能时，我就想给自己的博客也实现搜索图片中所含文本的功能。受限于当时的时间和技术条件，这个想法一直处于“挂起”状态。恰好上个月微信在其新版本也发布了聊天内容中的图片文本搜索功能。刚好寒假期间对PaddlePaddle深度学习框架做了些许研究并在本地部署了OCR项目。择日不如撞日，昨天晚上一口气把这套“前端”逻辑以Python脚本的形式实现了出来。程序代码已公开，可能存在不足之处与优化空间，希望各位大佬能在看过本文后不吝赐教。配置新增Typecho数据表字段：ALTER TABLE `typecho_contents` ADD `ocr` TEXT NULL AFTER `views`;修改Typecho搜索逻辑（1189行）：安装用到的Python包pip3 install pymysql -i https://pypi.tuna.tsinghua.edu.cn/simple pip3 install requests -i https://pypi.tuna.tsinghua.edu.cn/simple代码其中xxxxx应换为自己的对应信息：# -*- coding: utf-8 -*- # @Author : soarli # @Date : 2021/4/6 from datetime import datetime import os import time import requests import re import pymysql # <功能选项> # 是否更新所有信息的OCR结果(False则仅对未OCR的文章执行OCR操作) updateAll = False # 处理每张图片请求后的冷却时间(秒，防止因频次限制导致漏掉部分图片) cool = 5 # <数据库及网站配置相关信息> # 数据库地址 host = 'xxxxx' # 数据库用户名 user = 'xxxxx' # 数据库密码 password = 'xxxxx' # 数据库名 database = 'xxxxx' # 博客域名 target = 'https://xxxxx.xxxxx.xxx/' # <全局变量> # OCR接口地址 url = "https://xxxxx.xxx/xxxxx" # 全局请求头 headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36','referer':target} upload_data = {"name": "1.jpg", "type": "image/jpeg"} # 维护数据库连接状态 def keepAlive(): cur = conn.cursor() sql = "SELECT ocr FROM `typecho_contents` WHERE cid=1" cur.execute(sql) # 输入markdown文本，输出其中引用图片中的文字结果 def getPageOCRText(text): pic_list = re.findall(r"\!\[.*\]\((.+)\)",text) this_text = '' for i in pic_list: try: img = {'file':requests.get(i,headers=headers).content} img_text = requests.post(url, upload_data, files=img) this_text += img_text.text time.sleep(cool) # 维护数据库连接状态 keepAlive() # print(this_text) except Exception as e: print('Error msg: ' + str(e)) ocrtext = this_text.replace("\n","").replace('\'','\\\'').replace('\"','\\\"').replace('-','\-') if(ocrtext == ''): ocrtext = 'none!' return ocrtext # 返回需要进行ocr操作的cid(直接传入下一个函数) def getUnOCRedCid(): cur = conn.cursor() if(updateAll): …

Flask上线部署解除测试环境警告
type: item
date: 2022-04-04T05:33:00+08:00
description: 前言最近发现Flask项目在运行时会报[WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead警告，意思是不要在生产环境使用这种方案启动程序：解决使用WSGI启动服务即可解决问题（中间可能需要pip3 install gevent）原版代码：from paddleocr import PaddleOCR from flask import Flask, request import cv2 import numpy app = Flask(__name__) ocr = PaddleOCR(det_model_dir='./inference/small/ch_PP-OCRv2_det_infer/', rec_model_dir='./inference/small/ch_PP-OCRv2_rec_infer/',cls_model_dir='./inference/small/ch_ppocr_mobile_v2.0_cls_infer/',use_angle_cls=True,use_space_char=True, use_gpu=False) @app.route('/xxxxxx/', methods=['get', 'POST']) def xxxxxx(): img_path = request.args.get("fname") result = ocr.ocr(img_path) ret = '' for line in result: ret += str(line[1][0]) + "\n" return str(ret) if __name__ == '__main__': app.run(host='0.0.0.0') 新版代码：from paddleocr import PaddleOCR from flask import Flask, request import cv2 import numpy from gevent import pywsgi app = Flask(__name__) ocr = PaddleOCR(det_model_dir='./inference/small/ch_PP-OCRv2_det_infer/', rec_model_dir='./inference/small/ch_PP-OCRv2_rec_infer/',cls_model_dir='./inference/small/ch_ppocr_mobile_v2.0_cls_infer/',use_angle_cls=True,use_space_char=True, use_gpu=False) @app.route('/xxxxxx/', methods=['get', 'POST']) def xxxxxx(): img_path = request.args.get("fname") result = ocr.ocr(img_path) ret = '' for line in result: ret += str(line[1][0]) + "\n" return str(ret) if __name__ == '__main__': server = pywsgi.WSGIServer(('0.0.0.0', 5000), app) server.serve_forever() 解决问题！参考资料：https://blog.csdn.net/weixin_43642491/article/details/114916769https://www.cnblogs.com/mlp1234/p/13743254.html

Python多线程学习笔记
type: item
date: 2022-04-03T21:54:00+08:00
description: 前言之前做过Python多线程的应用，但是一直没有系统学习，加之最近有了相关需求且发现其在Linux上的执行效率是真的高便决定简单学习并做个记录。基本用法import threading def thread_job(): print('This is an added Thread, number is %s' %threading.current_thread()) def main(): # 输出激活状态的线程数 # 1 print(threading.active_count()) # 输出当前激活状态线程的详细信息 # [<_MainThread(MainThread, started 14940)>] print(threading.enumerate()) # 输出正在运行的线程是哪一个 # <_MainThread(MainThread, started 14940)> print(threading.current_thread()) # 新建一个线程 # This is an added Thread, number is <Thread(Thread-1, started 9948)> added_thread = threading.Thread(target=thread_job) added_thread.start() if __name__ == '__main__': main()join方法默认情况下，多线程任务中子线程的运行并不会阻塞主线程，使用join方法即可对主线程进行阻塞。import threading from time import sleep def thread_job(): print('T1 start\n') for i in range(10): sleep(0.1) print('T1 finish\n') def main(): added_thread = threading.Thread(target=thread_job, name="T1") added_thread.start() print('all done\n') if __name__ == '__main__': main()输出顺序：T1 start all done T1 finish阻塞状态：import threading from time import sleep def thread_job(): print('T1 start\n') for i in range(10): sleep(0.1) print('T1 finish\n') def main(): added_thread = threading.Thread(target=thread_job, name="T1") added_thread.start() added_thread.join() # 随后的语句将被阻塞 print('all done\n') if __name__ == '__main__': main()输出顺序：T1 start T1 finish all done双线程模型：import threading from time import sleep def thread_job(): print('T1 start\n') for i in range(10): sleep(0.1) print('T1 finish\n') # 一个执行较快的函数 def T2_job(): print('T2 start\n') print('T2 finish\n') def main(): added_thread = threading.Thread(target=thread_job, name="T1") thread_2 = threading.Thread(target=T2_job, name="T2") added_thread.start() thread_2.start() added_thread.join() # 随后的语句将被阻塞 print('all done\n') if __name__ == '__main__': main()输出结果：T1 start T2 start T2 finish T1 finish all done即便是运行较快的线程，只要不阻塞，其优先级也会低于主线程：import threading from time import sleep def thread_job(): print('T1 start\n') for i in range(10): sleep(0.1) print('T1 finish\n') # 一个执行较快的函…