当前位置: 首页 > news >正文

[Python自动化办公]--从网页登录网易邮箱进行邮件搜索并下载邮件附件

[Python自动化办公]–从网页登录网易邮箱进行邮件搜索并下载邮件附件

使用说明

​ 本文使用Python的selenium库进行操作邮箱登录、固定名称搜索邮件并下载附件,Python版本:3.9.16, selenium版本:4.19.0,EdgeBrowser版本:126.0.2592.87。

准备工作

安装Python及selenium不多赘述,可自行搜索安装,除了具备基本的Python编程知识外还需要了解网页知识。
安装Edge浏览器驱动:
查看当前使用的Edge浏览器版本:设置 -->关于 即可查看

在这里插入图片描述

驱动下载地址

下载并解压缩。记住文件路径,后面会用到。(浏览器会定期更新的话需要及时更新驱动)

编写代码

首先给出一段完整的代码,再来分步骤讲解。

完整demo
from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from datetime import datetime, timedelta
import timedef input_info():'''用于生成文件名称字符如果你需要自动下载的邮件名称是每天根据日期变化的可以参考此函数进行适当修改'''# 获取当天日期today = datetime.now().date()# 获取当天日期减去2天的日期target_date = today - timedelta(days=2)# 格式化日期为“4月6日”的形式formatted_date = target_date.strftime("%m月%d日").lstrip("0").replace("月0", "月")# 拼接字符串res = formatted_date + "你要的邮件"return resdriver_path = r"C:\Users\JA043204\Desktop\getMail\edgedriver_win64\msedgedriver.exe"
edge_options = Options()
edge_options.use_chromium = True  # 如果正在使用新的基于 Chromium 的 Edge,设置为 True
service = Service(executable_path=driver_path)driver = webdriver.Edge(service=service, options=edge_options)# 打开登录页面
driver.get("https://mailh.qiye.163.com/")# 填写用户名和密码
usrname = "yourusrname" # 需替换为自己的用户名
pwd = "yourpwd" # 需替换为自己的密码try:# 在 Selenium 4 中,推荐使用 find_element 方法代替 find_element_by_* 方法driver.find_element("id", "account_name").send_keys(usrname)driver.find_element("id", "password").send_keys(pwd)# 点击登录按钮driver.find_element("id", "submit-btn").click()# 等待一段时间,确保登录成功后的页面加载完成time.sleep(5)# 执行登录后的操作,比如获取用户信息等# 比如,获取登录后的页面标题print(driver.title)# 找到搜索的input框,并输入"质量部基础数据"input_box = driver.find_element(By.XPATH,'//input[@placeholder="搜索邮件"]')input_box.send_keys(input_info())# 发送回车键操作,触发搜索或相应的动作input_box.send_keys(Keys.RETURN)time.sleep(2)# 使用显式等待尝试定位元素target_div = WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.XPATH, ('//span[@class="summary-content summary-content-maxwidth"]'))))target_div.click() # 点击打开邮件time.sleep(2)# 找到邮件后定位到打包下载邮件附件相关元素tar_a = WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.XPATH, '//span[@class="save-all"]')))driver.execute_script("arguments[0].click();", tar_a)finally:# 关闭浏览器if input("是否关闭浏览器? (y/n): ").lower().startswith('y'):driver.quit()
导入必要包
  1. from selenium import webdriver:
    • 导入 Selenium 的 WebDriver 类,用于启动浏览器和执行操作。
  2. from selenium.webdriver.edge.service import Service:
    • 导入 Edge 浏览器的 Service 类,用于配置和启动 Edge 浏览器的 WebDriver 服务。
  3. from selenium.webdriver.edge.options import Options:
    • 导入 Edge 浏览器的 Options 类,用于设置 Edge 浏览器的选项,如设置浏览器启动参数。
  4. from selenium.webdriver.support.ui import WebDriverWait:
    • 导入 WebDriverWait 类,用于显式等待页面元素加载并设定等待条件。
  5. from selenium.webdriver.common.by import By:
    • 导入 By 类,用于指定查找元素的方法,例如通过 ID、Class Name、XPath 等。
  6. from selenium.webdriver.support import expected_conditions as EC:
    • 导入 expected_conditions 模块,这是 WebDriverWait 的一部分,包含了预期条件,如元素可见、元素存在、元素包含文本等。
配置浏览器驱动
driver_path = r"C:\Users\JA043204\Desktop\getMail\edgedriver_win64\msedgedriver.exe" # 替换为准备工作中的路径
edge_options = Options()
edge_options.use_chromium = True  # 如果正在使用新的基于 Chromium 的 Edge,设置为 True
service = Service(executable_path=driver_path)driver = webdriver.Edge(service=service, options=edge_options)
打开网页

使用 driver.get()方法,传入参数为登录界面url。

从浏览器中定位元素
  1. 从浏览器打开登录界面,然后 按下F12 打开开发工具。
    在这里插入图片描述

  2. 使用检查元素来定位网页内容
    在这里插入图片描述

    先点击检查元素工具图标,然后点击用户名输入框
    在这里插入图片描述

这样就能快速找到该元素网页源码的位置

使用selenium定位元素
  1. 通过元素 ID 定位:
    使用 find_element_by_id 方法可以通过元素的 ID 属性来定位元素。例如:

    element = driver.find_element_by_id("element_id")
    
  2. 通过元素名称定位:
    使用 find_element_by_name 方法可以通过元素的名称属性来定位元素。例如:

    element = driver.find_element_by_name("element_name")
    
  3. 通过类名定位:
    使用 find_element_by_class_name 方法可以通过元素的类名来定位元素。注意,如果有多个元素具有相同的类名,它会返回第一个匹配的元素。例如:

    element = driver.find_element_by_class_name("element_class")
    
  4. 通过标签名定位:
    使用 find_element_by_tag_name 方法可以通过元素的标签名来定位元素。例如:

    element = driver.find_element_by_tag_name("tag_name")
    
  5. 通过链接文本定位:
    使用 find_element_by_link_text 方法可以通过链接的文本内容来定位元素。例如:

    element = driver.find_element_by_link_text("Link Text")
    
  6. 通过部分链接文本定位:
    使用 find_element_by_partial_link_text 方法可以通过链接的部分文本内容来定位元素。例如:

    element = driver.find_element_by_partial_link_text("Partial Link Text")
    
  7. 通过 XPath 表达式定位:
    使用 find_element_by_xpath 方法可以通过 XPath 表达式来定位元素。XPath 是一种强大的定位方式,可以根据元素的层次结构、属性等来精确定位元素。例如:

    element = driver.find_element_by_xpath("//div[@id='example']/p[1]")
    
  8. 通过 CSS 选择器定位:
    使用 find_element_by_css_selector 方法可以通过 CSS 选择器来定位元素。CSS 选择器也是一种强大的定位方式,可以根据元素的样式、层次结构等来定位元素。例如:

    element = driver.find_element_by_css_selector("div#example > p:first-child")
    

在完整demo代码中只用到了元素ID定位和XPath定位,以上是不同的定位方式,可根据个人喜好选择使用,下面再介绍一下啊XPath表达式定位:XPath 是一种用于在 XML 文档中定位和选择元素的查询语言。它同样适用于 HTML 文档,因为 HTML 也可以被视为一种 XML 变体。以下是 XPath 的基本写法和一些常用的表达式:

  1. 选择元素
    • 绝对路径:从根节点开始的路径,以斜杠 / 开头。例如:/html/body/div
    • 相对路径:相对于当前节点的路径,以双斜杠 // 开头。例如://div/p
  2. 谓语(Predicate):用于过滤元素的附加条件,放在方括号内。
    • 例如://div[@class='content'] 选择 class 属性为 ‘content’ 的 div 元素。
  3. 选取节点
    • nodename:选择所有指定节点名的元素。例如://div 选择所有 div 元素。
    • *:选择当前节点的所有子元素。
    • @attribute:选择当前节点的指定属性。例如://@href 选择所有 href 属性。
    • text():选择当前节点的文本内容。
  4. 逻辑运算符
    • and, or, not:用于组合多个条件。
  5. (Axis):用于指定相对于当前节点的节点集合。
    • ancestor, parent, child, following-sibling, preceding-sibling 等。
  6. 通配符
    • *:匹配任何元素节点。
    • @*:匹配任何属性节点。
  7. 函数
    • name():获取当前节点的名称。
    • contains():检查一个字符串是否包含另一个字符串。
    • text():获取当前节点的文本内容。

例如,以下是一些示例 XPath 表达式:

  • //div[@id='content']:选择 id 属性为 ‘content’ 的所有 div 元素。
  • //a[@href='https://example.com']:选择所有 href 属性为 ‘https://example.com’ 的 a 元素。
  • //div[@class='main']//p:选择 class 属性为 ‘main’ 的 div 元素下的所有 p 元素

比如现在我需要定位用户名输入框,那么根据网页源码可以写Xpath表达式为: //input[@id='account_name']

然后再网页元素界面按下 Ctrl+F会跳出查找框,输入你写好的的XPath表达式后按下回车
在这里插入图片描述

可以看到查询结果之后在搜索框右侧有 1 of 1 字样表示当前是符合表达的结果中的唯一一个,定位的位置和刚才查找的网页源码一致,说明是我们想要的结果。

对网页元素进行操作

下面是操作详解:

  1. 定位元素:为了在网页上进行任何操作,Selenium需要首先找到需要操作的元素。定位元素通常通过选择器来完成,如ID、class、tag name、name、link text、partial link text、css selector或XPath。例如,driver.find_element_by_id("username")会找到ID为username的元素。
  2. 操作输入框:可以通过send_keys方法向输入框(通常是<input>标签)发送输入,如用户名或密码。例如,username_field.send_keys("myusername")
  3. 点击按钮:使用click()方法可以点击按钮或链接。例如,submit_button.click()会点击ID为submit_button的按钮。
  4. 提交表单:通过点击<form>标签上的提交按钮,或者直接调用submit()方法可以在表单提交时触发动作。例如,form.submit()会提交表单。
  5. 获取和设置元素属性:可以通过get_attribute()方法获取元素的属性值,还可以利用set_attribute()方法设置属性值。例如,element.get_attribute("class")会获取元素的class属性值。
  6. 执行JavaScript:Selenium提供了一个execute_script()方法,可以用来执行任何JavaScript代码。这意味着可以通过JavaScript与DOM交互来完成操作。
  7. 处理下拉框:可以使用select_by_visible_text()select_by_index()select_by_value()等方法来选择下拉框中的选项。这些方法位于Select类中。例如,dropdown.select_by_visible_text("option2")会选择下拉框中的可见文本为option2的选项。
  8. 处理弹出框:Selenium提供了的方法来处理JavaScript警告、确认框和提示框。例如,alert.accept()会确认一个警告框。
  9. 切换窗口:当网页上打开新窗口时,Selenium提供的方法switch_to.window可以用来切换到另一个窗口或标签页。例如,`driver.switch_to.window

对于登录界面我们要做的是,输入用户名和密码然后按下登录按钮也就是用到了 send_keys()click()方法

但是网页中的某些元素被JavaScript或css限制不可见或者不可点击,那么无法使用使用 click(),这时候需要通过execute_script()来完成点击操作。

比如完整demo中的 driver.execute_script("arguments[0].click();", tar_a)

然后解释一下下面这段代码

tar_a = WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.XPATH, '//span[@class="save-all"]')))
  1. WebDriverWait(driver, 5):
    • WebDriverWait 是 Selenium 提供的等待方式,它会在指定的时间内等待某个条件成立后继续执行下面的代码。
    • driver 是你创建的 WebDriver 实例,用于控制浏览器的操作。
    • 5 是最长等待时间,即最多等待5秒。
  2. .until() 方法:
    • until() 方法是 WebDriverWait 的一个函数,它接受一个条件(Expected Condition,EC)作为参数,并且会不断地调用这个条件,直到返回 True 或者超过最长等待时间为止。
  3. EC.presence_of_element_located((By.XPATH, '//span[@class="save-all"]')):
    • EC.presence_of_element_located 是预定义的一个条件,表示等待直到页面上至少出现一个满足条件的元素。
    • (By.XPATH, '//span[@class="save-all"]') 是定位元素的方式,指定了使用 XPath 来找到页面上 class 属性为 "save-all"span 元素。
  4. tar_a = ...:
    • 最后将等待到的元素赋值给变量 tar_a,这样就可以进一步操作这个元素了。

综上所述,这段代码的作用是等待页面中的一个 span 元素,该元素的 class 属性为 "save-all",等待时间最多为5秒。一旦找到该元素,就将它赋值给变量 tar_a,以便后续对该元素进行操作,比如点击或者获取其文本内容等。

an[@class=“save-all”]')是定位元素的方式,指定了使用 XPath 来找到页面上class属性为"save-all"span元素。 4. tar_a = …: - 最后将等待到的元素赋值给变量 tar_a`,这样就可以进一步操作这个元素了。

综上所述,这段代码的作用是等待页面中的一个 span 元素,该元素的 class 属性为 "save-all",等待时间最多为5秒。一旦找到该元素,就将它赋值给变量 tar_a,以便后续对该元素进行操作,比如点击或者获取其文本内容等。

最后,对于网页验证这一步骤在这个示例中不涉及,可以从代码中启动网页,填写信息登录后获取手机验证码并填写,之后一段时间网站cookie会保留登录信息。

相关文章:

[Python自动化办公]--从网页登录网易邮箱进行邮件搜索并下载邮件附件

[Python自动化办公]–从网页登录网易邮箱进行邮件搜索并下载邮件附件 使用说明 ​ 本文使用Python的selenium库进行操作邮箱登录、固定名称搜索邮件并下载附件&#xff0c;Python版本&#xff1a;3.9.16, selenium版本&#xff1a;4.19.0&#xff0c;EdgeBrowser版本:126.0.2…...

mysql8多值索引

MySQL8新出了一个多值索引&#xff0c;我还没体验过呢&#xff0c;今天试一试。 建表 我先建个表试一试多值索引的效果。我粗略地看了下多值索引的介绍&#xff0c;发现是只适用于数组类型的。所以我建一个含有数组字段的表试一试。语法还是挺麻烦的&#xff1a; create tabl…...

MT3055 交换排列

1.思路 若数对为&#xff08;1&#xff0c;4&#xff09;和&#xff08;4&#xff0c;7&#xff09;&#xff0c;则说明14可以互换&#xff0c;47可以互换&#xff0c;并且17也可以互换。所以把可以交换的元素放到一个集合中。 例如样例1&#xff1a;有三个集合&#xff0c;…...

Zkeys三方登录模块支持QQ、支付宝登录

1&#xff0c;覆盖到根目录&#xff0c;并导入update.sql数据库文件到Zkeys数据库里 2. 后台系统权限管理&#xff0c;配置管理员权限-系统类别-找到云外科技&#xff0c;全部打勾 3&#xff0c;后台系统设置找到云外快捷登录模块填写相应的插件授权配置和登录权限配置&#x…...

数字探秘:用神经网络解密MNIST数据集中的数字!

用神经网络解密MNIST数据集中的数字&#xff01; 一. 介绍1.1 MNIST数据集简介1.2 MLP&#xff08;多层感知器&#xff09;模型介绍1.3 目标&#xff1a;使用MLP模型对MNIST数据集中的0-9数字进行分类 二.数据预处理2.1 数据集的获取与加载2.2 数据集的探索性分析&#xff08;E…...

11个IT运维领域必考证书,每一个都含金量极高

这几年&#xff0c;网络方向里&#xff0c;IT运维其实还是挺吃香的。 运维人员的职责不仅仅是确保系统的正常运行&#xff0c;还需要应对突发事件、优化性能以及保障信息安全。 面对如此复杂的工作环境&#xff0c;拥有专业认证不仅是对自身技能的肯定&#xff0c;更是提升职业…...

VScode 常用插件

基础开发插件 Chinese (Simplified)&#xff08;简体中文语言包&#xff09;&#xff1a;这是适用于VS Code的中文&#xff08;简体&#xff09;语言包&#xff0c;适用于英语不太流利的用户。Auto Rename Tag&#xff1a;这个插件可以同步修改HTML/XML标签&#xff0c;当用户修…...

299k stars利用Public APIs提升开发效率:探索APILayer提供的开源资源

299k stars利用Public APIs提升开发效率&#xff1a;探索APILayer提供的开源资源 在现代软件开发中&#xff0c;API&#xff08;应用程序接口&#xff09;是实现应用间通信和功能扩展的关键工具。公共API&#xff08;Public APIs&#xff09;则为开发者提供了宝贵的资源&#…...

在目标检测数据集上微调Florence-2

Florence-2是由微软开源的轻量级视觉-语言模型,采用MIT许可。该模型在任务如图像描述、目标检测、定位和分割中展示了强大的零样本和微调能力。 图1。图示展示了每个任务所表达的空间层次和语义细粒度水平。来源:Florence-2:推进多种视觉任务的统一表示。 该模型将图…...

AI提示词:AI辅导「数学作业」

辅导孩子作业对许多家长来说可能是一件头疼的事&#xff0c;但这部分工作可以在一定程度上交给AI来完成。 打开ChatGPT4,输入以下内容&#xff1a; # Role 数学辅导专家## Profile - author: 姜小尘 - version: 02 - LLM: Kimi - language: 中文 - description: 专门为小学生…...

odoo文档的安装

步骤 1: 安装必要的软件 确保你已经安装了Git和Python 3.6、3.7或3.8之一。 步骤 2: 克隆 Odoo 文档存储库 打开终端&#xff0c;然后使用Git克隆Odoo的文档存储库。 git clone https://github.com/odoo/documentation.git cd documentation步骤 3: 安装 Python 依赖项 …...

02STM32软件安装新建工程

STM32软件安装&新建工程 1.软件安装&#xff1a;1.1Keil5 MDK安装1.2安装器件支持包离线安装支持包在线安装支持包 1.3软件注册&#xff1a;1.4安装驱动STLINK驱动JLink驱动在此文件夹下USB转串口 2.新建工程2.1STM32开发方式&#xff1a;1.寄存器2.标准库3.HAL库 固件库压…...

社区6月月报 | Apache DolphinScheduler重要修复和优化记录

各位热爱Apache DolphinScheduler的小伙伴们&#xff0c;社区6月月报更新啦&#xff01;这里将记录Apache DolphinScheduler社区每月的重要更新&#xff0c;欢迎关注。 月度Merge Stars 感谢以下小伙伴上个月为Apache DolphinScheduler所做的精彩贡献&#xff08;排名不分先后…...

Docker 使用基础(2)—镜像

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;秒針を噛む—ずっと真夜中でいいのに。 0:34━━━━━━️&#x1f49f;──────── 4:20 &#x1f504; ◀️ ⏸ …...

Docker学习笔记(三)Dockerfile

一、什么是Dockerfile Dockerfile 是一个用于自动化构建 Docker 镜像的文本文件&#xff0c;其中包含了从一个基础镜像开始&#xff0c;到最终形成所需定制镜像的所有指令集。这个文件中的每一条指令都对应着构建镜像过程中的一个步骤或一层&#xff0c;指导 Docker 如何安装软…...

学懂C#编程:C# 索引器(Indexer)的概念及用法

C#中的索引器&#xff08;Indexer&#xff09;是一种特殊的成员&#xff0c;它允许类或结构的实例像数组那样通过索引来访问其内部的数据。索引器提供了一种灵活的方式来暴露集合或数组类型的内部数据&#xff0c;使得客户端代码可以使用类似于数组下标的语法来访问类的成员&am…...

汇川CodeSysPLC教程03-2-14 与HMI通信

硬件连接 PLC与HMI连接采用何种连接方式&#xff0c;通常是参考双方支持哪些接口。PLC&#xff08;可编程逻辑控制器&#xff09;与HMI&#xff08;人机界面&#xff09;之间的通讯方式主要有以下几种&#xff1a; 串行通讯&#xff08;Serial Communication&#xff09;&…...

centos部署jar包

第一步&#xff1a; 将IDEA中的项目打包为jar,将这个jar文件放到centos服务器上的目录里&#xff0c;我在opt新建api目录&#xff0c;将jar文件放入&#xff0c;如下图&#xff1a; 第二步&#xff1a; 将需要读取的配置文件也放入此目录(其他目录也可以&#xff0c;和脚本中…...

CSS相对定位和绝对定位的区别

CSS相对定位和绝对定位的区别 区别1&#xff1a;相对的对象不同 相对定位是相对于自己绝对定位是相对于离自己最近的有定位的祖先 区别2:是否会脱离文档流 相对定位不会脱离文档流&#xff0c;不会影响其他元素的位置绝对定位会脱离文档流&#xff0c;会影响其他元素的布局 代…...

SpringCloud之nacos共享配置文件实现多数据源灵活切换

目录 前言 1.引入Springboot相关的aop切面依赖 2.创建自定义注解DataSourceKey 3.创建对ThreadLocal类 4.创建aop切面 5.创建动态数据源类 6.创建多数据库连接配置类 7.关键代码讲解 8.nacos主要配置 前言 通过Spring AOP&#xff08;面向切面编程&#xff09;的功能来动…...

TI C2000 DSP入门新姿势:Simulink硬件支持包安装与CCS v10.1.0联调实战记录

TI C2000 DSP开发环境搭建&#xff1a;从Simulink支持包到CCS联调全指南 当第一次打开Matlab准备为C2000 DSP开发算法时&#xff0c;很多人会惊讶地发现&#xff1a;明明安装了CCS和Matlab&#xff0c;却无法直接在Simulink中找到C2000的硬件支持。这不是个例——根据TI官方论坛…...

问卷设计对比实测:手工瞎编≠通用 AI≠学术专用!虎贲等考 AI 重新定义可发表级问卷

在毕业论文、课程论文、期刊实证研究中&#xff0c;问卷是决定数据是否有效、模型能否跑通、论文能否过关的核心一环。但 90% 的学生都在用错误方式做问卷&#xff1a;手工凭感觉出题、网上随便抄量表、用通用 AI 随意生成…… 结果要么信效度不达标&#xff0c;要么数据无法分…...

Human Skill Tree:基于认知科学的AI学习操作系统,重塑AI时代学习方式

1. 项目概述最近在折腾AI工具的时候&#xff0c;我一直在想一个问题&#xff1a;AI现在能通过Skill和MCP&#xff08;模型上下文协议&#xff09;调用各种工具&#xff0c;几乎无所不能&#xff0c;但我们人类的学习方式却还停留在“问一句&#xff0c;答一句”的原始阶段。这就…...

独立开发者实战:AI编程的泥泞战壕与生存指南

1. 从“氛围编程”到真实战场&#xff1a;一个独立开发者的自白如果你最近也在关注独立开发或者AI编程工具&#xff0c;那你一定听过“氛围编程”这个词。它听起来很酷&#xff0c;对吧&#xff1f;仿佛你只需要对着AI描述一下心中的“氛围感”&#xff0c;一个完美的应用就能应…...

【职业发展】程序员成长路径:从初级到架构师的进阶指南

【职业发展】程序员成长路径&#xff1a;从初级到架构师的进阶指南 引言 程序员的职业发展是一个持续学习和成长的过程。从初级程序员成长为技术架构师&#xff0c;需要经历多个阶段的积累和蜕变。本文将详细分析程序员成长的各个阶段&#xff0c;帮助你规划职业发展路径。 …...

DRAM计算内存的电源传输网络优化策略

1. DRAM计算内存中的电源传输网络挑战与优化在数据密集型应用爆炸式增长的今天&#xff0c;传统冯诺依曼架构面临严峻的"内存墙"挑战。计算内存&#xff08;Compute-in-Memory, CIM&#xff09;技术通过在内存内部执行计算任务&#xff0c;从根本上改变了数据处理范式…...

稀疏记忆微调技术:解决LLM持续学习中的灾难性遗忘

1. 稀疏记忆微调技术解析 1.1 持续学习的核心挑战 在大型语言模型&#xff08;LLM&#xff09;的实际应用中&#xff0c;灾难性遗忘&#xff08;Catastrophic Forgetting&#xff09;是持续学习面临的最大障碍。想象一下&#xff0c;当你教会一个学生新知识时&#xff0c;他却…...

基于DGX OpenClaw Stack构建本地AI智能体:从硬件调优到生产部署

1. 项目概述&#xff1a;一站式本地AI智能体栈如果你和我一样&#xff0c;对把大语言模型&#xff08;LLM&#xff09;真正“养”在自己的硬件上&#xff0c;构建一个功能完整、数据私有的智能助手有执念&#xff0c;那么你很可能已经踩过不少坑了。从选模型、搭服务、配工具链…...

别再只玩开发板了!用吃灰的STM32核心板DIY一个专属游戏手柄,实战HID协议

从零构建STM32游戏手柄&#xff1a;深入解析HID协议与实战开发 你是否曾盯着抽屉里积灰的STM32核心板思考它能做什么&#xff1f;与其重复点亮LED的基础实验&#xff0c;不如挑战一个既实用又有趣的项目——打造专属游戏手柄。这不仅能让硬件资源重获新生&#xff0c;更是深入理…...

告别IDEA编译警告:深入解析JDK版本过时问题与多维度解决方案

1. 当IDEA开始"抱怨"&#xff1a;那些烦人的编译警告从哪来&#xff1f; 每次打开老项目&#xff0c;总能看到那个熟悉的黄色警告&#xff1a;"Warning:java: 源值1.5已过时&#xff0c;将在未来所有发行版中删除"。这个提示就像个唠叨的老朋友&#xff0c…...