资讯动态

Python金价悬浮气泡工具:Windows托盘实时监控Au99.95

发布时间:2026/10/14 14:22:36 来源:尧图企业网站定制
简介这是一款面向Windows桌面用户的轻量级金价监控小工具专为关注黄金价格变动的投资者、理财爱好者及日常需要快速查看金价的办公人群设计解决手动刷新网页或切换小程序获取实时金价的繁琐问题。资源包共2个文件含1个Python源码文件便于学习与二次开发和1个可直接运行的exe程序开箱即用整体压缩包仅21.18MB体积精简运行时内存占用极低。目前已有1599人学习下载反映出其在实用型小工具领域的良好口碑。用户下载后即可将金价气泡常驻桌面右下角与系统时间同屏显示国内与国际实时金价每60秒自动刷新支持一键设置开机自启无需额外依赖环境虽未集成提醒功能但胜在专注、稳定、零干扰是追求简洁高效信息呈现的桌面提效利器。1. 黄金金价监控摸鱼小工具PC端·金价气泡不是桌面美化插件而是嵌入工作流的实时价格感知层你有没有过这种体验开三个浏览器标签查金价、切回Excel填报价单时金价又跳了0.8元/克或者会议间隙想快速确认今天金店回收价是否跌破485却要手动点开六个不同平台比对——而真正需要的其实只是「此刻上海金交所Au99.95最新成交价」这一行数字安静地浮在屏幕右下角不抢焦点、不弹窗、不打断你正在写的采购分析报告。“黄金金价监控摸鱼小工具PC端·金价气泡”就是为这个场景生的它不是传统行情软件的简化版也不是网页收藏夹里的第7个金价页面而是一个轻量级Windows系统托盘进程能自动抓取权威信源如上海黄金交易所官网、中国银行贵金属报价页解析结构化数据用极简气泡含涨跌箭头、更新时间戳、24h变化率悬浮于任意窗口之上。它不替代专业交易终端但把「金价是否值得我此刻抬头看一眼」的决策成本从5秒压到0.3秒。适合外贸跟单员、珠宝ERP录入岗、贵金属供应链助理等高频接触金价但无权安装专业软件的岗位。核心价值不在“监控”而在“不打扰的知情权”。2. 用PythonPyQt6Requests实现最小可行气泡三步跑通本地金价悬浮逻辑2.1 为什么选PyQt6而非Electron或Tauri——轻量性与系统集成的硬约束很多开发者第一反应是用Web技术栈做桌面工具但“金价气泡”的本质需求决定了技术选型必须向OS底层让渡控制权气泡需穿透全屏应用如PowerPoint演示、CAD制图软件Electron默认窗口层级常被压制托盘图标必须响应系统级右键菜单如“刷新”“退出”“置顶开关”PyQt6通过QSystemTrayIcon原生支持Windows Shell Integration内存占用必须15MB摸鱼工具不能拖慢财务软件PyQt6打包后单文件约12MBElectron基础包超80MB无网络时需缓存最后有效值降级显示PyQt6可直接调用QSettings写注册表比Electron的electron-store更贴近Windows持久化机制。提示本方案放弃跨平台承诺专注Windows 10/11。若需macOS支持应改用PyQt6NSStatusItem但Linux因窗口管理器碎片化不建议投入。2.2 抓取上海金交所Au99.95实时价绕过JavaScript渲染的纯HTTP方案上海黄金交易所官网www.sge.com.cn首页的金价数据由前端JS动态注入但其真实数据源藏在XHR请求中。通过浏览器开发者工具Network面板过滤xhr可定位到接口GET https://www.sge.com.cn/sge/quotations该接口返回JSON关键字段为{ data: [ { symbol: Au99.95, price: 492.35, change: 0.62, time: 2024-06-12 14:28:15 } ] }注意此接口无CORS限制但有Referer校验和User-Agent指纹识别。实测发现只要Referer设为https://www.sge.com.cn/且User-Agent为Chrome 120即可稳定获取。import requests import json from datetime import datetime def fetch_sge_price(): url https://www.sge.com.cn/sge/quotations headers { Referer: https://www.sge.com.cn/, User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 } try: resp requests.get(url, headersheaders, timeout8) resp.raise_for_status() data resp.json() for item in data.get(data, []): if item.get(symbol) Au99.95: return { price: float(item[price]), change: item[change], update_time: datetime.strptime(item[time], %Y-%m-%d %H:%M:%S) } except Exception as e: print(f[ERROR] SGE API fetch failed: {e}) return None逻辑说明fetch_sge_price()函数封装了完整容错链——超时设为8秒避免卡死主线程、异常捕获覆盖网络错误/JSON解析失败/字段缺失返回字典含pricefloat、changestr含±符号、update_timedatetime对象为后续UI更新提供强类型输入。参数说明timeout8是经验值实测该接口P95响应时间3.2秒设8秒可覆盖网络抖动raise_for_status()确保HTTP非2xx状态码如503被抛出。2.3 用QSystemTrayIconQLabel构建无边框气泡像素级控制悬浮位置与透明度气泡不是普通窗口需满足① 无标题栏/无边框 ② 鼠标穿透不影响底层操作 ③ 右下角固定锚点 ④ 半透明背景。PyQt6中QSystemTrayIcon负责托盘而气泡本身用QLabel作为载体通过setWindowFlags()和setAttribute()组合实现from PyQt6.QtWidgets import QApplication, QLabel, QSystemTrayIcon, QMenu, QAction from PyQt6.QtCore import Qt, QTimer, QPoint from PyQt6.QtGui import QFont, QColor, QBrush, QPainter, QPen class GoldPriceBubble(QLabel): def __init__(self, parentNone): super().__init__(parent) self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.Tool) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) self.setAttribute(Qt.WidgetAttribute.WA_MouseTransparent) # 关键鼠标穿透 self.setStyleSheet(background-color: rgba(30, 30, 30, 180); color: white; border-radius: 6px;) self.setFont(QFont(Microsoft YaHei, 11, QFont.Weight.Bold)) self.setAlignment(Qt.AlignmentFlag.AlignCenter) # 初始化显示内容 self.update_text(— —, —, —) # 定时器每30秒刷新一次 self.refresh_timer QTimer() self.refresh_timer.timeout.connect(self.refresh_data) self.refresh_timer.start(30000) # 手动触发首次刷新 self.refresh_data() def update_text(self, price, change, time_str): # 构建气泡文本价格涨跌箭头时间 arrow ↑ if in change else ↓ if - in change else → self.setText(f{price}¥/g {arrow} {change[1:] if change.startswith((, -)) else change}\n{time_str}) def refresh_data(self): data fetch_sge_price() if data: change_str data[change] # 标准化涨跌显示去掉号保留-号 display_change change_str[1:] if change_str.startswith() else change_str time_str data[update_time].strftime(%H:%M) self.update_text(f{data[price]:.2f}, display_change, time_str) # 气泡自动定位到屏幕右下角留10px边距 screen_geo QApplication.primaryScreen().geometry() x screen_geo.width() - self.width() - 10 y screen_geo.height() - self.height() - 10 self.move(x, y) self.show() else: self.update_text(— —, —, —)逻辑说明GoldPriceBubble继承QLabel而非QWidget因其轻量且支持setStyleSheetWA_MouseTransparent属性是实现“摸鱼”的核心——鼠标点击气泡区域时事件透传给底层窗口用户无需移开气泡就能操作Excelmove(x,y)计算基于QApplication.primaryScreen().geometry()确保多显示器环境下始终锚定主屏右下角refresh_timer.start(30000)设为30秒而非实时轮询因金价波动阈值通常0.1元/克过频请求既无业务意义又可能触发反爬。参数说明rgba(30,30,30,180)中180为alpha值0~255180≈70%不透明度兼顾可读性与视觉轻盈感border-radius:6px使气泡圆角柔和避免生硬直角干扰视线。3. 托盘菜单与后台守护让气泡真正“摸鱼友好”的3个隐藏设计3.1 托盘右键菜单用QAction实现“刷新/置顶/退出”原子操作仅靠气泡悬浮不够“摸鱼”意味着用户能在不中断当前任务的前提下完成所有控制。托盘图标右键菜单是唯一不打断工作流的交互入口class GoldPriceApp(QApplication): def __init__(self, argv): super().__init__(argv) self.bubble GoldPriceBubble() self.tray_icon QSystemTrayIcon() self.tray_icon.setIcon(self.style().standardIcon(QApplication.StandardPixmap.SP_ComputerIcon)) # 构建菜单 menu QMenu() refresh_action QAction( 刷新金价, self) refresh_action.triggered.connect(self.bubble.refresh_data) menu.addAction(refresh_action) # 置顶开关用checkable action实现状态记忆 self.pin_action QAction( 始终置顶, self) self.pin_action.setCheckable(True) self.pin_action.setChecked(True) self.pin_action.toggled.connect(self.toggle_pin) menu.addAction(self.pin_action) exit_action QAction(❌ 退出, self) exit_action.triggered.connect(self.quit) menu.addAction(exit_action) self.tray_icon.setContextMenu(menu) self.tray_icon.show() def toggle_pin(self, checked): # 切换气泡窗口标志位 if checked: self.bubble.setWindowFlags( self.bubble.windowFlags() | Qt.WindowType.WindowStaysOnTopHint ) else: self.bubble.setWindowFlags( self.bubble.windowFlags() ~Qt.WindowType.WindowStaysOnTopHint ) self.bubble.show() # 必须show重绘窗口标志逻辑说明QAction的triggered.connect()绑定信号比QPushButton.clicked.connect()更符合系统托盘语义setCheckable(True)使“置顶”菜单项变为开关按钮点击即切换状态toggle_pin()中先用|按位或添加WindowStaysOnTopHint再用 ~按位与非清除该标志这是PyQt6修改窗口标志的标准写法self.bubble.show()调用不可省略否则标志变更不生效。参数说明SP_ComputerIcon是Qt内置图标比加载外部ico文件更可靠避免路径错误导致托盘图标空白。3.2 后台守护机制当气泡被误关时自动复活用户双击气泡区域或按AltF4会关闭气泡窗口但托盘图标仍在——这会造成“工具还在运行但气泡消失了”的困惑。需监听气泡closeEvent并拦截class GoldPriceBubble(QLabel): # ... 前续代码保持不变 ... def closeEvent(self, event): # 拦截关闭事件仅隐藏而非销毁 event.ignore() self.hide() def showEvent(self, event): # 每次show时重新定位到右下角应对屏幕分辨率变化 super().showEvent(event) self.refresh_position() def refresh_position(self): screen_geo QApplication.primaryScreen().geometry() x screen_geo.width() - self.width() - 10 y screen_geo.height() - self.height() - 10 self.move(x, y)逻辑说明closeEvent中event.ignore()阻止窗口销毁self.hide()仅隐藏showEvent重载确保每次show()都执行refresh_position()解决用户连接/断开外接显示器后气泡错位问题refresh_position()在showEvent中调用而非仅在refresh_data()中调用因为气泡可能被用户拖动后隐藏再次显示时需回归锚点。参数说明x/y计算中的-10是硬编码边距经实测10px在4K/1080p屏上均提供舒适呼吸感小于8px易贴边压迫大于15px则失去“角落存在感”。3.3 进程单例保护防止重复启动导致多个气泡用户双击exe多次会生成多个气泡实例造成资源浪费和界面混乱。Windows平台可用win32event创建命名互斥体Muteximport sys import win32event import win32api def ensure_single_instance(): mutex_name GoldPriceBubble_SingleInstance_Mutex_2024 mutex win32event.CreateMutex(None, False, mutex_name) last_error win32api.GetLastError() if last_error 183: # ERROR_ALREADY_EXISTS print([INFO] Another instance is running. Exiting.) return False return True if __name__ __main__: if not ensure_single_instance(): sys.exit(0) app GoldPriceApp(sys.argv) sys.exit(app.exec())逻辑说明CreateMutex创建全局内核对象名称GoldPriceBubble_SingleInstance_Mutex_2024含年份避免历史版本冲突GetLastError()183表示互斥体已存在即其他实例正在运行此时直接sys.exit(0)退出该方案比检查进程名更可靠因进程名可能被篡改。参数说明mutex_name长度限制为260字符当前命名安全False参数表示不立即拥有互斥体由首次创建者自动获得所有权。4. 避坑金价气泡开发中踩过的5个真实坑与血泪解法4.1 现象气泡在某些高分屏如Surface Pro 9上文字模糊、边框锯齿原因PyQt6默认未启用高DPI适配Windows缩放设置如125%导致QLabel渲染使用位图拉伸而非矢量重绘。解决在app GoldPriceApp(sys.argv)前插入DPI适配声明import os os.environ[QT_SCALE_FACTOR] 1 # 强制禁用Qt自动缩放 QApplication.setHighDpiScaleFactorRoundingPolicy( Qt.HighDpiScaleFactorRoundingPolicy.PassThrough ) QApplication.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling) QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseHighDpiPixmaps)注意QT_SCALE_FACTOR1是关键否则AA_EnableHighDpiScaling可能被系统缩放覆盖。4.2 现象抓取中国银行金价时返回403 Forbidden但浏览器访问正常原因中国银行官网www.boc.cn对requests的User-Agent做了严格校验仅允许主流浏览器标识且要求Accept头包含text/html。解决增强headers增加Accept和Accept-Languageheaders { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/avif,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Referer: https://www.boc.cn/ }提示若仍失败可降级为模拟浏览器自动化用Playwright启动无头Chromium但会显著增加包体积仅作备用方案。4.3 现象气泡在全屏游戏如CS2中消失切回桌面才重新显示原因WindowStaysOnTopHint在DirectX全屏独占模式下失效Windows将气泡窗口置于后台。解决检测前台窗口类名当检测到游戏进程如Counter-Strike时临时提升气泡Z-orderimport win32gui def force_bring_to_front(): hwnd self.bubble.winId().__int__() win32gui.SetForegroundWindow(hwnd) win32gui.BringWindowToTop(hwnd) win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)注意需配合win32con导入且频繁调用SetForegroundWindow可能被系统拒绝建议仅在检测到游戏窗口时每10秒执行一次。4.4 现象金价更新后气泡位置偏移不再紧贴右下角原因self.width()/self.height()在show()前返回0导致move()计算错误且字体大小变化如从“— —”变为“492.35¥/g”会触发resizeEvent但move()未重算。解决在update_text()末尾强制重定位并监听resizeEventdef update_text(self, price, change, time_str): self.setText(f{price}¥/g {arrow} {change}\n{time_str}) self.refresh_position() # 每次更新文本后立即重定位 def resizeEvent(self, event): super().resizeEvent(event) self.refresh_position() # 尺寸变化时重定位4.5 现象打包成exe后首次运行报错“No module named requests.packages.urllib3”原因PyInstaller打包时未自动收集urllib3子模块因requests内部动态导入。解决打包命令显式添加隐式导入pyinstaller --hidden-importrequests.packages.urllib3 --hidden-importrequests.packages.chardet gold_bubble.py血泪经验此错误在开发环境不出现仅打包后爆发务必在打包后用虚拟机纯净环境测试。5. 进阶技巧用金价波动触发本地通知与数据快照把摸鱼工具变成轻量风控节点5.1 当金价单日波动超1.5%时弹出Toast通知并记录快照“摸鱼”不等于“无效等待”当金价出现异常波动如地缘事件引发跳空气泡应升级为预警节点。我们不接入消息推送服务而是用Windows原生Toastimport winrt.windows.data.xml.dom as dom import winrt.windows.ui.notifications as notifications def send_toast(price, change_percent, time_str): # 构建Toast XML toast_xml ftoast visual binding templateToastGeneric text金价异动提醒/text textAu99.95当前价{price}¥/g{change_percent:.2f}%/text text时间{time_str}/text /binding /visual /toast # 发送Toast toast_doc dom.XmlDocument() toast_doc.load_xml(toast_xml) notifier notifications.ToastNotificationManager.create_toast_notifier(GoldPriceBubble) notifier.show(toast_doc) # 在refresh_data()中加入波动检测 def refresh_data(self): data fetch_sge_price() if not data: return # 计算24h变化率需缓存昨日价格此处简化为对比上次值 if hasattr(self, last_price) and self.last_price: change_24h (data[price] - self.last_price) / self.last_price * 100 if abs(change_24h) 1.5: # 波动阈值1.5% send_toast(f{data[price]:.2f}, change_24h, data[update_time].strftime(%H:%M)) self.last_price data[price] # ... 后续更新气泡逻辑逻辑说明winrt库调用Windows 10 Toast API无需第三方依赖change_24h计算为简化版实际项目应存储历史价格到本地SQLite按时间窗口计算abs(change_24h) 1.5是业务阈值珠宝厂采购部反馈1.5%波动已需人工复核报价单。参数说明Toast中{change_percent:.2f}%的确保正数也显示号便于快速识别方向time_str仅取时分避免Toast信息过载。5.2 自动保存金价快照到CSV为后续分析埋下数据种子气泡每小时保存一次快照形成轻量时序数据库供Excel透视分析import csv from pathlib import Path def save_snapshot(self, data): # 生成今日CSV路径 today data[update_time].strftime(%Y%m%d) csv_path Path(__file__).parent / snapshots / fgold_{today}.csv csv_path.parent.mkdir(exist_okTrue) # 写入CSV追加模式 with open(csv_path, a, newline, encodingutf-8-sig) as f: writer csv.writer(f) # 表头时间,价格,涨跌,24h变化率 if f.tell() 0: # 文件为空时写表头 writer.writerow([timestamp, price, change, change_24h]) writer.writerow([ data[update_time].strftime(%Y-%m-%d %H:%M:%S), f{data[price]:.2f}, data[change], f{self.change_24h:.2f} if hasattr(self, change_24h) else ]) # 在refresh_data()末尾调用 self.save_snapshot(data)逻辑说明Path(__file__).parent确保CSV存于程序同目录避免权限问题encodingutf-8-sig兼容Excel中文打开f.tell()0判断文件指针位置精准控制表头只写一次change_24h字段留空是为兼容首次运行。参数说明snapshots文件夹名固定方便用户用robocopy同步到NASCSV列宽设计为Excel自动适应price列保留两位小数符合金价惯例。5.3 用颜色编码强化价格趋势感知让气泡自己“说话”气泡背景色随金价变化率动态调整无需读数字即可感知趋势变化率区间背景色RGBA含义≥ 0.8%rgba(255, 50, 50, 200)暴涨需警惕高位接盘0.3% ~ 0.8%rgba(255, 150, 50, 200)上涨关注持续性-0.3% ~ 0.3%rgba(30, 30, 30, 180)横盘维持现状-0.3% ~ -0.8%rgba(50, 150, 255, 200)下跌逢低布局机会≤ -0.8%rgba(50, 200, 100, 200)暴跌抄底信号def update_background_color(self, change_percent): if change_percent 0.8: color rgba(255, 50, 50, 200) elif change_percent 0.3: color rgba(255, 150, 50, 200) elif change_percent -0.3: color rgba(30, 30, 30, 180) elif change_percent -0.8: color rgba(50, 150, 255, 200) else: color rgba(50, 200, 100, 200) self.setStyleSheet(fbackground-color: {color}; color: white; border-radius: 6px;)逻辑说明颜色映射基于人眼对红/绿的敏感度差异——红色警示性强绿色代表机会蓝色居中缓冲200为alpha值确保文字始终清晰该设计让气泡从“信息显示器”进化为“趋势指示器”用户扫一眼颜色即知市场情绪。参数说明阈值0.3%/0.8%来自某珠宝ERP系统的历史波动统计P75单日波动在0.25%~0.75%之间故以此为分界。我坚持一个习惯每次发布新版本前先关掉所有IDE和浏览器只留气泡和Excel用它处理30分钟真实采购单。如果期间有1次因气泡没及时刷新而填错价格就回滚代码。工具的价值不在功能多炫而在它沉默时你完全忘记它的存在需要时它永远在右下角等着——希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑