pip配置代理
pip config set global.proxy http://{host}:{port}
pip config set global.proxy http://{host}:{port}
开发和打包成二进制都没问题,打包mac独立app onefile不显示窗口
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("icons/icon.png")) # 确保 "icon.png" 路径正确,可以是绝对路径或相对路径
from PyQt5.QtCore import Qt
QApplication.setAttribute(Qt.AA_DontUseNativeMenuBar, True)
# 设置全局日志回调(使得代理模块调用 log() 时同时能写入 UI)
def gui_log(msg):
window.log(msg)
LOG_CALLBACK = gui_log
window = MainWindow()
window.setWindowTitle("代理")
window.resize(600, 600)
window.show()
sys.exit(app.exec_())开发,打包二进制没问题,打包mac应用不显示窗口
注释掉python window.resize(600, 600)就好了
def resource_path(relative_path):
"""获取打包后的资源文件路径"""
if hasattr(sys, '_MEIPASS'):
# 打包后的路径
base_path = sys._MEIPASS
else:
# 开发阶段的路径
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
# 使用示例
icon_path = resource_path("icons/icon.png")
打包参数
pyinstaller --windowed --noconfirm --add-data "icons:icons" -F main.py import logging
import os.path
from logging import StreamHandler, FileHandler
from colorama import Fore, Style
from datetime import datetime
def notice(self, message, args, *kwargs):
if self.isEnabledFor(NOTICE_LEVEL):
self._log(NOTICE_LEVEL, message, args, **kwargs)
logging.Logger.notice = notice
NOTICE_LEVEL = 19 # < NOTICE(19) < INFO(20) < WARNING(30)
logging.addLevelName(NOTICE_LEVEL, "NOTICE")
class ColorFormatter(logging.Formatter):
"""日志格式化,支持不同级别的颜色"""
COLOR_MAP = {
logging.DEBUG: Fore.CYAN,
logging.INFO: Fore.GREEN,
logging.WARNING: Fore.YELLOW,
NOTICE_LEVEL: Fore.BLUE, # NOTICE 级别使用蓝色
logging.ERROR: Fore.RED,
logging.CRITICAL: Fore.MAGENTA + Style.BRIGHT,
}
RESET = Style.RESET_ALL
def format(self, record):
log_color = self.COLOR_MAP.get(record.levelno, "")
log_fmt = f"{log_color}[%(asctime)s] [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s{self.RESET}"
formatter = logging.Formatter(log_fmt, datefmt="%Y-%m-%d %H:%M:%S")
return formatter.format(record)
def notice(self, message, args, *kwargs):
if self.isEnabledFor(NOTICE_LEVEL):
self._log(NOTICE_LEVEL, message, args, **kwargs)
logging.Logger.notice = notice # 绑定到 Logger
def log_handler(log_file, level):
today = datetime.today().strftime('%Y-%m-%d')
file_format = logging.Formatter(f"[%(asctime)s] [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S")
file_handler = FileHandler(f"{log_file}_{today}_{level}.log", mode="a", encoding="utf-8")
if level == 'info':
file_handler.setLevel(logging.INFO)
elif level == 'debug':
file_handler.setLevel(logging.DEBUG)
elif level == 'notice':
file_handler.setLevel(NOTICE_LEVEL)
elif level == 'warning':
file_handler.setLevel(logging.WARNING)
else:
file_handler.setLevel(logging.NOTSET)
file_handler.setFormatter(file_format)
return file_handler
def setup_logger(log_dir = 'logs', log_file='app', task_id=0, uuid=None):
"""
设置全局 logger,支持:
1. 控制台日志(带颜色)
2. 文件日志(info, error)
3. 远程服务器日志上报(仅 NOTICE 级别)
"""
global logger, _task_id, _uuid
if task_id:
_task_id = task_id
if uuid:
_uuid = uuid
log_file = os.path.join(log_dir,log_file)
new_logger = logging.getLogger("custom_logger")
new_logger.setLevel(logging.DEBUG) # 设置最低日志级别
# 清除旧的处理器
if new_logger.handlers:
for handler in new_logger.handlers[:]:
new_logger.removeHandler(handler)
# 控制台处理器
console_handler = StreamHandler()
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(ColorFormatter())
new_logger.addHandler(console_handler)
if log_file:
new_logger.addHandler(log_handler(log_file, 'debug'))
new_logger.addHandler(log_handler(log_file, 'error'))
new_logger.addHandler(log_handler(log_file, 'info'))
new_logger.addHandler(log_handler(log_file, 'notice'))
# ✅ 替换 `logger` 的内容,而不改变 `logger` 的引用
logger.__dict__.update(new_logger.__dict__)
logger: logging.Logger
setup_logger()
import sys
from pathlib import Path
# 设置一个跨平台的统一路径
def get_playwright_browsers_path():
# 获取用户主目录
home_dir = Path.home()
# 在主目录下创建一个固定的 Playwright 浏览器路径
playwright_path = home_dir / ".playwright_browsers"
# 确保路径存在
playwright_path.mkdir(parents=True, exist_ok=True)
return str(playwright_path)
# 动态设置浏览器路径
os.environ["PLAYWRIGHT_BROWSERS_PATH"] = get_playwright_browsers_path()
def ensure_browser_installed():
try:
from playwright.__main__ import main as playwright_main
playwright_main() # 自动安装 Chromium
except Exception as e:
print(f"Error during Playwright installation: {e}")
if __name__ == "__main__":
# check args
args = sys.argv
if len(args)>1 and args[1] == 'install':
ensure_browser_installed()
app = QApplication(sys.argv)
main_window = URLFetcherApp()
main_window.show()
sys.exit(app.exec_())main.exe install