news 2026/8/24 21:20:32

基于Chrome扩展与Alarms API实现Gmail收件箱定时自动化整理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Chrome扩展与Alarms API实现Gmail收件箱定时自动化整理

在实际工作中,Gmail 收件箱很容易被各种邮件淹没,尤其是订阅邮件、通知和促销信息。手动整理耗时费力,而完全依赖 Gmail 自带的标签和过滤器,又缺乏一种“自动、定时、批量”处理的灵活性。如果你希望每天下班后或某个固定时间,让收件箱自动完成归档、标记已读、删除垃圾邮件等操作,那么一个能够定时运行的 Chrome 扩展会是一个理想的解决方案。

本文将围绕“Lindy Chrome 扩展”这一概念,构建一个能够定时、自动整理 Gmail 收件箱的浏览器扩展。我们将从零开始,理解 Chrome 扩展的核心结构,学习如何与 Gmail 网页版进行交互,实现自动化的邮件处理逻辑,并最终打包成一个可安装的扩展。整个过程不仅涉及扩展开发,还包括对 Gmail 页面 DOM 结构的分析、安全权限的配置以及后台定时任务的调度。无论你是想学习 Chrome 扩展开发,还是希望打造一个属于自己的效率工具,这篇文章都将提供一条清晰的实现路径。

1. 理解 Chrome 扩展与 Gmail 自动化的核心机制

在动手编码之前,必须理清几个关键问题:Chrome 扩展如何工作?它凭什么能操作 Gmail 页面?以及如何安全、可靠地实现定时任务?

1.1 Chrome 扩展的基本构成与权限

一个 Chrome 扩展通常由以下几部分组成:

  • 清单文件 (manifest.json):扩展的“身份证”和“说明书”,定义了扩展的名称、版本、权限、后台脚本、内容脚本等核心信息。
  • 后台脚本 (Background Script):在浏览器后台长期运行的 JavaScript 文件,负责处理事件、管理状态、执行定时任务。它是扩展的“大脑”。
  • 内容脚本 (Content Script):注入到特定网页(如mail.google.com)中的 JavaScript 文件,可以读取和修改该页面的 DOM。它是与目标页面直接交互的“手”。
  • 弹出页面 (Popup):用户点击扩展图标时出现的界面,通常用于提供快捷操作和设置。
  • 选项页面 (Options Page):用于进行更复杂配置的页面。

要让扩展操作 Gmail,必须在manifest.json中声明相应的权限。最重要的两个是:

  • "host_permissions": ["https://mail.google.com/*"]:允许扩展向 Gmail 域名发送请求和注入内容脚本。
  • "permissions": ["storage", "alarms", "scripting"]
    • storage用于保存用户设置(如整理规则、执行时间)。
    • alarms用于创建和管理定时任务。
    • scripting(Manifest V3) 用于动态注入内容脚本。

1.2 与 Gmail 页面交互的策略

Gmail 是一个复杂的单页应用 (SPA),其 DOM 结构会动态变化。我们不能依赖固定的 CSS 选择器,而需要寻找相对稳定的特征。例如,Gmail 为每封邮件渲染的div元素通常包含role="listitem"属性,并且内部有用于标识发件人、主题和标签的特定元素。

内容脚本的策略是:

  1. 等待页面稳定:在 Gmail 页面加载或导航完成后,再执行操作。
  2. 定位邮件列表:通过document.querySelectorAll('div[role="listitem"]')获取当前视图中的所有邮件项。
  3. 解析邮件信息:遍历每个邮件项,提取发件人、主题、是否有特定标签(如“推广”、“社交”)等信息。
  4. 执行操作:根据用户预设的规则(如“来自‘newsletter@example.com’的邮件自动加星标”),模拟点击相应的按钮(如“归档”、“删除”、“标记为已读”的按钮)。

1.3 定时任务的实现:Alarms API

我们不能在内容脚本或后台脚本中使用setInterval来实现跨浏览器会话的精确定时,因为扩展可能会被休眠。Chrome 提供了chrome.alarmsAPI 专门用于此目的。

后台脚本可以创建一个每天在特定时间触发的警报:

// 在后台脚本中设置每天 22:00 执行的定时任务 chrome.alarms.create('nightlyCleanup', { periodInMinutes: 24 * 60, // 每天一次 when: Date.now() + getMillisecondsUntil(22, 0) // 计算到今晚22点的毫秒数 }); chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'nightlyCleanup') { // 触发整理任务 triggerCleanup(); } });

当警报触发时,后台脚本需要通知内容脚本(如果 Gmail 标签页已打开)或先打开一个 Gmail 标签页再注入内容脚本执行任务。

2. 环境准备与项目结构搭建

我们将使用 Manifest V3 进行开发,这是 Chrome 扩展的最新规范,更注重安全性和性能。

2.1 开发环境要求

  • Chrome 浏览器:版本 88 或更高(以支持 Manifest V3)。建议使用最新稳定版。
  • 代码编辑器:VS Code、Sublime Text 或任何你熟悉的编辑器。
  • 基础知识:HTML、CSS 和 JavaScript (ES6+)。
  • 项目目录:创建一个空文件夹作为项目根目录。

2.2 初始化项目结构与清单文件

在项目根目录下,创建以下文件和文件夹:

lindy-gmail-cleaner/ ├── manifest.json # 扩展核心配置文件 ├── background.js # 后台脚本 ├── content.js # 内容脚本(注入Gmail) ├── popup.html # 弹出页面 ├── popup.js # 弹出页面逻辑 ├── options.html # 选项页面 ├── options.js # 选项页面逻辑 └── icons/ # 扩展图标 ├── icon16.png ├── icon48.png └── icon128.png

首先创建最重要的manifest.json文件:

{ "manifest_version": 3, "name": "Lindy Gmail Cleaner", "version": "1.0.0", "description": "在夜间自动整理你的 Gmail 收件箱,基于规则归档、删除或标记邮件。", "permissions": [ "storage", "alarms", "scripting" ], "host_permissions": [ "https://mail.google.com/*" ], "background": { "service_worker": "background.js" }, "content_scripts": [ { "matches": ["https://mail.google.com/*"], "js": ["content.js"], "run_at": "document_idle" } ], "action": { "default_popup": "popup.html", "default_icon": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }, "options_page": "options.html", "icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }

关键配置解释

  • "manifest_version": 3:声明使用 V3 规范。
  • "host_permissions":指定我们的内容脚本可以注入到所有 Gmail 页面。
  • "background.service_worker":V3 中后台脚本以 Service Worker 形式运行,更省资源。
  • "content_scripts.run_at": "document_idle":确保页面基本加载完成后再执行脚本,避免与 Gmail 自身的加载冲突。
  • "action":定义了扩展图标和弹出页面。

2.3 创建基础图标与页面

你可以使用简单的图形工具生成 16x16, 48x48, 128x128 像素的 PNG 图标,放入icons文件夹。对于popup.htmloptions.html,我们先创建最简版本。

popup.html(弹出页面):

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> body { width: 300px; padding: 15px; font-family: sans-serif; } button { margin-top: 10px; padding: 8px 12px; width: 100%; } .status { margin-top: 10px; padding: 8px; background: #f0f0f0; border-radius: 4px; } </style> </head> <body> <h3>Lindy Gmail Cleaner</h3> <p>下次整理时间: <span id="nextCleanupTime">--:--</span></p> <button id="runNowBtn">立即执行一次整理</button> <button id="openOptionsBtn">打开设置</button> <div id="status" class="status"></div> <script src="popup.js"></script> </body> </html>

options.html(选项页面):

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> body { padding: 20px; font-family: sans-serif; max-width: 600px; } .rule { border: 1px solid #ccc; padding: 15px; margin-bottom: 15px; border-radius: 5px; } input, select, button { margin: 5px; padding: 8px; } </style> </head> <body> <h2>整理规则设置</h2> <div id="rulesContainer"> <!-- 规则将通过JS动态添加 --> </div> <button id="addRuleBtn">添加新规则</button> <hr> <h3>定时设置</h3> <label>每日执行时间: </label> <input type="time" id="scheduleTime" value="22:00"> <button id="saveScheduleBtn">保存定时设置</button> <div id="saveStatus"></div> <script src="options.js"></script> </body> </html>

3. 实现后台调度与通信逻辑

后台脚本 (background.js) 是扩展的调度中心,负责管理定时任务和在各个部分之间传递消息。

3.1 初始化与定时任务管理

// background.js // 默认配置 const DEFAULT_CONFIG = { scheduleTime: '22:00', // 默认晚上10点 rules: [ { id: 'rule1', name: '归档促销邮件', condition: { field: 'from', operator: 'contains', value: 'promo' }, action: 'archive', enabled: true }, { id: 'rule2', name: '删除社交通知', condition: { field: 'category', operator: 'equals', value: 'social' }, action: 'delete', enabled: true } ] }; // 安装或更新时初始化配置 chrome.runtime.onInstalled.addListener(() => { chrome.storage.sync.get(['config'], (result) => { if (!result.config) { chrome.storage.sync.set({ config: DEFAULT_CONFIG }); console.log('初始配置已设置。'); } // 设置或更新定时任务 scheduleNextCleanup(); }); }); // 计算到指定时间(HH:MM格式)的毫秒数 function getMillisecondsUntil(timeStr) { const [hours, minutes] = timeStr.split(':').map(Number); const now = new Date(); const target = new Date(now); target.setHours(hours, minutes, 0, 0); if (target <= now) { target.setDate(target.getDate() + 1); // 如果今天时间已过,设定为明天 } return target.getTime() - now.getTime(); } // 安排下一次整理任务 async function scheduleNextCleanup() { const result = await chrome.storage.sync.get(['config']); const config = result.config || DEFAULT_CONFIG; const delayInMinutes = Math.ceil(getMillisecondsUntil(config.scheduleTime) / (1000 * 60)); // 清除旧警报,创建新警报 chrome.alarms.clear('nightlyCleanup'); chrome.alarms.create('nightlyCleanup', { delayInMinutes: delayInMinutes, periodInMinutes: 24 * 60 // 重复周期:每天 }); console.log(`已安排整理任务,将在 ${delayInMinutes} 分钟后(${config.scheduleTime})首次执行。`); } // 监听定时警报 chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'nightlyCleanup') { triggerCleanup(); } }); // 触发整理任务的核心函数 async function triggerCleanup() { console.log('触发夜间整理任务...'); // 1. 获取当前打开的Gmail标签页 const tabs = await chrome.tabs.query({ url: 'https://mail.google.com/*' }); if (tabs.length > 0) { // 2. 如果Gmail已打开,向该标签页的内容脚本发送消息 const gmailTab = tabs[0]; chrome.tabs.sendMessage(gmailTab.id, { action: 'performCleanup' }, (response) => { if (chrome.runtime.lastError) { // 可能内容脚本未加载,尝试先注入再执行 executeCleanupInTab(gmailTab.id); } else { console.log('整理任务通过消息传递执行。'); } }); } else { // 3. 如果Gmail未打开,先打开一个新标签页 const newTab = await chrome.tabs.create({ url: 'https://mail.google.com', active: false }); // 等待页面加载 setTimeout(() => { executeCleanupInTab(newTab.id); }, 3000); } } // 在指定标签页中执行清理(通过动态注入脚本) async function executeCleanupInTab(tabId) { // 首先注入内容脚本(如果尚未注入) await chrome.scripting.executeScript({ target: { tabId: tabId }, files: ['content.js'] }); // 然后发送执行命令 chrome.tabs.sendMessage(tabId, { action: 'performCleanup' }); } // 监听来自弹出页面或选项页面的消息 chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'runCleanupNow') { triggerCleanup(); sendResponse({ status: 'started' }); } else if (request.action === 'updateSchedule') { scheduleNextCleanup(); sendResponse({ status: 'scheduleUpdated' }); } return true; // 保持消息通道开放,用于异步响应 });

3.2 弹出页面逻辑

弹出页面 (popup.js) 提供快捷操作和状态展示。

// popup.js document.addEventListener('DOMContentLoaded', async () => { const nextCleanupTimeEl = document.getElementById('nextCleanupTime'); const runNowBtn = document.getElementById('runNowBtn'); const openOptionsBtn = document.getElementById('openOptionsBtn'); const statusEl = document.getElementById('status'); // 获取并显示下次执行时间 chrome.alarms.get('nightlyCleanup', (alarm) => { if (alarm && alarm.scheduledTime) { const nextTime = new Date(alarm.scheduledTime); nextCleanupTimeEl.textContent = nextTime.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } else { nextCleanupTimeEl.textContent = '未设置'; } }); // “立即执行”按钮 runNowBtn.addEventListener('click', () => { statusEl.textContent = '正在执行整理任务...'; chrome.runtime.sendMessage({ action: 'runCleanupNow' }, (response) => { if (response && response.status === 'started') { statusEl.textContent = '任务已触发,请查看Gmail页面。'; setTimeout(() => { statusEl.textContent = ''; }, 3000); } }); }); // “打开设置”按钮 openOptionsBtn.addEventListener('click', () => { chrome.runtime.openOptionsPage(); }); });

4. 实现 Gmail 页面内容脚本与自动化逻辑

这是最核心的部分,内容脚本 (content.js) 将直接操作 Gmail 的 DOM。

4.1 监听消息与等待页面就绪

// content.js // 监听来自后台脚本的整理命令 chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'performCleanup') { console.log('收到整理指令,开始处理...'); performGmailCleanup().then(result => { sendResponse({ success: true, processed: result.processed }); }).catch(error => { console.error('整理过程出错:', error); sendResponse({ success: false, error: error.message }); }); return true; // 保持消息通道开放以发送异步响应 } }); // 主清理函数 async function performGmailCleanup() { // 1. 确保页面是收件箱且已加载完毕 if (!isGmailInboxReady()) { console.log('Gmail收件箱未就绪,等待或刷新...'); // 可以尝试导航到收件箱或等待 window.location.href = 'https://mail.google.com/mail/u/0/#inbox'; await waitForElement('div[role="main"]', 10000); // 等待最多10秒 } // 2. 从存储中获取用户定义的规则 const config = await getConfigFromStorage(); const rules = config.rules.filter(rule => rule.enabled); if (rules.length === 0) { console.log('没有启用的规则,跳过整理。'); return { processed: 0 }; } // 3. 获取当前视图中的所有邮件 const emailItems = getEmailItems(); console.log(`找到 ${emailItems.length} 封待处理邮件。`); let processedCount = 0; // 4. 遍历每封邮件并应用规则 for (const emailEl of emailItems) { const emailInfo = extractEmailInfo(emailEl); if (!emailInfo) continue; for (const rule of rules) { if (matchesRule(emailInfo, rule.condition)) { console.log(`邮件匹配规则 "${rule.name}": ${emailInfo.subject}`); if (await applyAction(emailEl, rule.action)) { processedCount++; // 一封邮件匹配一个规则并执行后,跳出规则循环,处理下一封 break; } } } // 可选:添加短暂延迟,避免操作过快导致页面反应不过来 await delay(500); } console.log(`整理完成,共处理 ${processedCount} 封邮件。`); return { processed: processedCount }; }

4.2 解析邮件信息与匹配规则

// 辅助函数:提取单封邮件的关键信息 function extractEmailInfo(emailElement) { try { // 这些选择器基于Gmail的DOM结构,未来可能变化 const senderEl = emailElement.querySelector('[email]'); const subjectEl = emailElement.querySelector('[data-legacy-thread-id] span'); const categorySpan = emailElement.querySelector('span[data-category]'); // 用于识别Gmail分类(推广、社交等) const sender = senderEl ? senderEl.getAttribute('email') || senderEl.textContent.trim() : ''; const subject = subjectEl ? subjectEl.textContent.trim() : ''; const category = categorySpan ? categorySpan.getAttribute('data-category') : ''; // 检查邮件是否已读 const isRead = emailElement.getAttribute('aria-read') === 'true' || emailElement.classList.contains('zE'); return { sender, subject, category, isRead, element: emailElement }; } catch (error) { console.warn('解析邮件信息失败:', error); return null; } } // 辅助函数:判断邮件是否匹配某条规则条件 function matchesRule(emailInfo, condition) { const { field, operator, value } = condition; const fieldValue = emailInfo[field] || ''; switch (operator) { case 'contains': return fieldValue.toLowerCase().includes(value.toLowerCase()); case 'equals': return fieldValue.toLowerCase() === value.toLowerCase(); case 'startsWith': return fieldValue.toLowerCase().startsWith(value.toLowerCase()); case 'endsWith': return fieldValue.toLowerCase().endsWith(value.toLowerCase()); default: return false; } } // 辅助函数:对邮件元素执行操作 async function applyAction(emailElement, action) { const actionButtons = { 'archive': 'div[role="button"][title*="归档"], div[role="button"][aria-label*="Archive"]', 'delete': 'div[role="button"][title*="删除"], div[role="button"][aria-label*="Delete"]', 'markRead': 'div[role="button"][title*="标记为已读"], div[role="button"][aria-label*="Mark as read"]', 'addStar': 'div[role="button"][title*="加星标"], div[role="button"][aria-label*="Star"]' }; const selector = actionButtons[action]; if (!selector) { console.warn(`未知操作: ${action}`); return false; } // 首先确保邮件被选中(点击邮件复选框) const checkbox = emailElement.querySelector('div[role="checkbox"]'); if (checkbox) { checkbox.click(); await delay(200); // 等待选中状态更新 } // 查找并点击对应的操作按钮 // 注意:Gmail的工具栏按钮可能在邮件列表上方 const toolbar = document.querySelector('div[role="toolbar"]'); if (toolbar) { const actionButton = toolbar.querySelector(selector); if (actionButton) { actionButton.click(); await delay(300); // 等待操作完成 return true; } } console.warn(`未找到操作按钮: ${action}`); return false; }

4.3 关键工具函数

// 工具函数:等待特定元素出现 function waitForElement(selector, timeout = 5000) { return new Promise((resolve, reject) => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(() => { if (document.querySelector(selector)) { observer.disconnect(); resolve(document.querySelector(selector)); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(() => { observer.disconnect(); reject(new Error(`等待元素超时: ${selector}`)); }, timeout); }); } // 工具函数:获取所有邮件列表项 function getEmailItems() { // 选择收件箱中的邮件项,排除已选择的或系统项 return Array.from(document.querySelectorAll('div[role="listitem"]')).filter(item => { return item.querySelector('div[role="checkbox"]') && item.getAttribute('aria-selected') !== 'true'; }); } // 工具函数:检查Gmail收件箱是否就绪 function isGmailInboxReady() { const url = window.location.href; if (!url.includes('#inbox') && !url.includes('#category/')) { return false; // 不在收件箱或分类视图 } const mainArea = document.querySelector('div[role="main"]'); return !!mainArea && mainArea.querySelector('div[role="listitem"]'); } // 工具函数:从存储中获取配置 function getConfigFromStorage() { return new Promise((resolve) => { chrome.storage.sync.get(['config'], (result) => { resolve(result.config || { rules: [] }); }); }); } // 工具函数:延迟 function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }

5. 实现选项页面与规则管理

选项页面 (options.js) 让用户可以添加、编辑和删除整理规则,并设置执行时间。

// options.js document.addEventListener('DOMContentLoaded', async () => { const rulesContainer = document.getElementById('rulesContainer'); const addRuleBtn = document.getElementById('addRuleBtn'); const scheduleTimeInput = document.getElementById('scheduleTime'); const saveScheduleBtn = document.getElementById('saveScheduleBtn'); const saveStatusEl = document.getElementById('saveStatus'); let currentRules = []; // 加载现有配置 await loadConfig(); // 加载配置 async function loadConfig() { const result = await chrome.storage.sync.get(['config']); const config = result.config || { scheduleTime: '22:00', rules: [] }; currentRules = config.rules; scheduleTimeInput.value = config.scheduleTime; renderRules(); } // 渲染规则列表 function renderRules() { rulesContainer.innerHTML = ''; currentRules.forEach((rule, index) => { const ruleEl = document.createElement('div'); ruleEl.className = 'rule'; ruleEl.innerHTML = ` <h4>规则 ${index + 1}: ${rule.name}</h4> <div> <label>条件字段:</label> <select class="field">问题现象可能原因检查点与解决方案扩展图标不显示或无法点击1.manifest.json语法错误。
2. 图标文件路径错误或格式不对。
3. 未声明actiondefault_popup。1. 打开chrome://extensions/,检查扩展卡片是否有错误提示(红色文字)。
2. 右键点击扩展图标 -> “审查弹出内容”,检查网络请求是否成功加载了popup.html
3. 确认manifest.jsonactionicons路径正确。弹出页面无法加载配置或执行操作1. 弹出页面脚本 (popup.js) 未正确引入或存在语法错误。
2. 与后台脚本 (background.js) 通信失败。
3. 权限未正确声明。1. 在弹出页面右键 -> “检查”,查看控制台是否有 JS 错误。
2. 确认popup.js中使用了正确的 Chrome API (chrome.runtime.sendMessage)。
3. 确认manifest.json中声明了storage权限。内容脚本未注入 Gmail 页面1.host_permissions未包含 Gmail 域名。
2.content_scripts.matches模式错误。
3. Gmail 页面使用了 iframe 或动态加载。1. 确认manifest.jsonhost_permissions包含"https://mail.google.com/*"
2. 在 Gmail 页面按 F12,切换到“Sources”标签,左侧应能看到content.js文件。
3. 在内容脚本开头加console.log('Content script loaded');验证。内容脚本无法找到邮件元素1. Gmail 的 DOM 结构已更新。
2. 脚本执行时机过早,页面未加载完。
3. 选择器过于具体或错误。1. 在 Gmail 页面控制台手动执行document.querySelectorAll('div[role="listitem"]')查看结果。
2. 将content_scripts.run_at改为"document_idle"
3. 使用更通用的选择器,或通过MutationObserver等待元素出现。规则匹配成功但操作未执行1. 操作按钮的选择器失效。
2. 邮件未被正确“选中”。
3. Gmail 的 UI 状态(如选择模式)未切换。1. 在控制台检查applyAction函数中actionButtons的选择器是否能找到元素。
2. 在模拟点击前,手动在控制台执行emailElement.querySelector('div[role="checkbox"]').click()看是否有效。
3. 在操作间增加delay,确保前一个操作完成。定时任务不触发1.alarms权限未声明。
2. 后台脚本 (background.js) 未正确注册或存在错误。
3. Service Worker 被浏览器终止。1. 确认manifest.json中声明了"alarms"权限。
2. 打开chrome://extensions/,点击扩展下的“service worker”链接查看后台脚本控制台。
3. 在background.js开头加console.log('Background script started');验证。保存的设置丢失1. 使用了chrome.storage.sync但未登录 Chrome 账号。
2. 存储空间超出限制(默认 100KB)。1. 使用chrome.storage.local进行测试,它不需要同步。
2. 检查存储的数据大小,避免保存过大对象。

调试核心原则

  1. 分步验证:先确保内容脚本能注入,再验证能否获取邮件列表,最后测试单个操作。
  2. 善用 Console:在background.js,content.js,popup.js中大量使用console.log输出关键变量和流程状态。
  3. 检查 Chrome 扩展管理页面chrome://extensions/页面的错误提示是首要排查点。
  4. 模拟 Gmail 更新:Gmail 的 UI 可能随时变化,选择器需要有一定的容错性。考虑使用更稳定的属性,如>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 21:20:30

backtesting.py 回测提速速查:15 分钟缩到 200ms

backtesting.py 回测提速速查&#xff1a;15 分钟缩到 200ms 【免费下载链接】backtesting.py &#x1f50e; &#x1f4c8; &#x1f40d; &#x1f4b0; Backtest trading strategies in Python. 项目地址: https://gitcode.com/GitHub_Trending/ba/backtesting.py 本…

作者头像 李华
网站建设 2026/8/24 21:19:30

G-Helper 完整使用指南:华硕笔记本轻量调校工具快速上手

G-Helper 完整使用指南&#xff1a;华硕笔记本轻量调校工具快速上手 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook, …

作者头像 李华
网站建设 2026/8/24 21:19:20

MediaCrawler 多平台爬虫教程:5 分钟跑通小红书、抖音等 7 个站点

MediaCrawler 多平台爬虫教程&#xff1a;5 分钟跑通小红书、抖音等 7 个站点 【免费下载链接】MediaCrawler 小红书笔记 | 评论爬虫、抖音视频 | 评论爬虫、快手视频 | 评论爬虫、B 站视频 &#xff5c; 评论爬虫、微博帖子 &#xff5c; 评论爬虫、百度贴吧帖子 &#xff5c;…

作者头像 李华
网站建设 2026/8/24 21:19:08

Minimax Code CLI:本地部署AI智能体,驱动M3 Mac完成自动化技术调研

这次我们来看一个能驱动 M3 芯片 MacBook 跑数小时自主调研的 AI 工具&#xff1a;Minimax Code CLI。它不是普通的代码生成器&#xff0c;而是一个能理解复杂任务、自主规划、执行代码、分析结果并生成报告的智能体&#xff08;Agent&#xff09;。简单说&#xff0c;你给它一…

作者头像 李华
网站建设 2026/8/24 21:18:46

IDM激活脚本使用教程:免费冻结试用期与激活指南

IDM激活脚本使用教程&#xff1a;免费冻结试用期与激活指南 【免费下载链接】IDM-Activation-Script-ZH IDM激活脚本汉化版 项目地址: https://gitcode.com/gh_mirrors/id/IDM-Activation-Script-ZH IDM 的 30 天试用期一到期&#xff0c;注册窗口开始反复弹出&#xff…

作者头像 李华
网站建设 2026/8/24 21:16:19

Windows免虚拟机搭建天龙八部0.85单机服务端完整教程

很多朋友想体验经典游戏《天龙八部》的早期版本&#xff08;如0.85&#xff09;&#xff0c;但一看到需要安装虚拟机、配置Linux系统就望而却步。复杂的虚拟化设置、系统兼容性问题、资源占用大&#xff0c;让不少玩家在第一步就卡住了。本文将分享一套完整的“免虚拟机、免Lin…

作者头像 李华

关于博客

这是一个专注于编程技术分享的极简博客,旨在为开发者提供高质量的技术文章和教程。

订阅更新

输入您的邮箱,获取最新文章更新。

© 2025 极简编程博客. 保留所有权利.