Selenium模拟用户操作实战:从环境搭建到稳定运行的完整指南

1. 先说清楚:为什么我们要在 Web 自动化里“模拟用户操作”

如果你接触过 Selenium,那么“模拟用户常见操作”这几个字其实已经概括了 Selenium 最核心的价值——它不是在网页上做简单的网络请求,而是像真实用户一样,打开浏览器、点击按钮、输入文字、滚动页面、切换标签页,最终把整套人机交互过程变成自动化脚本。这也是 Selenium 区别于 Requests、Scrapy 这类纯 HTTP 请求库的关键分水岭。

遇到下面这些场景,你就知道“模拟用户操作”不是花架子,而是刚需:

  • 某个后台管理系统每天要重复做“登录 → 导出报表”的操作,人工点 30 次太浪费时间。
  • 写爬虫时目标网站的数据是通过 Ajax 异步渲染的,直接拿 HTML 源码拿到的是空壳,必须等页面加载完、等数据出现在 DOM 里才能抓取。
  • 想对线上核心功能做回归测试,每次发版后去点一遍主流程,靠人肉点 100 个用例不现实。
  • 第三方登录流程里需要几十个字段的真实交互,脚本需要逐个模拟填写、选择、提交。

这篇文章我就按自己实际踩过坑的顺序,把 Selenium 模拟用户操作从环境搭建一直讲到完整实战,重点放在“每个操作为什么这样写”“哪些地方容易浪费时间调试”“怎么稳定不翻车”。说实话,网上讲 Selenium 的教程很多,但大多数只告诉你 API 怎么调,没告诉你真实项目中那几条隐藏规则:等待要等什么、定位用什么策略、被遮住点不了怎么处理、弹窗切换怎么不丢上下文。这些才是真正决定脚本能不能稳定跑下去的关键。

如果你是刚接触 Selenium 的初学者,这篇文章可以按顺序读;如果你已经会用基本语法但总觉得脚本经常报错,可以直接跳到章节 4 和章节 6,那里面的排查思路应该能帮你止血。

2. 环境准备与基础框架:别在第一步就翻车

2.1 Driver 版本匹配是最大的拦路虎

很多新手第一次装 Selenium 就栽在驱动上。Selenium 本身只是一个协议层库,它需要通过 WebDriver 去和真实浏览器通信。你在 Python 里执行pip install selenium不等于就完成了,它还需要一个浏览器驱动文件,Chrome 对应 ChromeDriver,Firefox 对应 GeckoDriver,Microsoft Edge 对应 EdgeDriver。

这里最容易踩的坑是:驱动版本和浏览器版本必须精配。比如你本地 Chrome 升级到了某个新的大版本,但 Chromedriver 还是旧版本,运行起来就会直接抛SessionNotCreatedException。我见过太多人卡在这一步半小时起步,其实解决办法就一条:打开浏览器地址栏输入chrome://version/,看到浏览器主版本号之后,去对应驱动的版本列表里找一个主版本号一致的下载即可。

提示:下载驱动时不必追求小版本号完全一致,主版本号相同通常就能正常工作。但如果遇到莫名报错,优先检查驱动和浏览器的小版本相差太远的情况。

同类的坑表现在无头模式上。如果你用options.add_argument('--headless')跑无头浏览器,建议先在有头模式下做一遍功能验证,确认脚本没有逻辑问题之后再切无头。无头模式下有些元素交互行为会有细微差异,比如窗口尺寸默认偏小,导致你页面上某些按钮在视口之外,click()时元素检测不通过,脚本判负。

2.2 最小可运行框架:先把骨架搭起来

下面是我习惯用的一个最小框架,任何项目我都从这个模板开始改。它包含四项基础内容:可配置浏览器选项、等待对象、页面加载控制、异常退出清理。

from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def init_driver(headless=False): options = Options() options.add_argument('--window-size=1920,1080') options.add_argument('--disable-gpu') options.add_argument('--no-sandbox') if headless: options.add_argument('--headless') driver = webdriver.Chrome(options=options) driver.set_page_load_timeout(20) return driver driver = init_driver(headless=False) wait = WebDriverWait(driver, 10)

注意driver.set_page_load_timeout(20)这行,很多页面资源加载慢会导致get()长时间阻塞,设置超时后,至少能及时抛错而不是干等。WebDriverWait这个对象是整个模拟操作的核心搭档,后面几乎每一步交互前都要用到,我把它的 10 秒等待时间设为默认值。

至于--no-sandbox,如果你是在本地 Windows/Mac 上跑,不一定要加;但如果你在 Linux 服务器或者虚拟机里跑,没有这个参数大概率会直接报错。这个参数的核心逻辑是禁用浏览器沙箱权限限制,解决某些受限环境下的启动失败,但副作用是安全性下降,本地调试没问题,生产环境请谨慎。

2.3 为什么我建议你先不用框架

现在网上有非常多基于 Selenium 封装的测试框架,比如 pytest + Selenium、Robot Framework、Playwright 替代方案等等。但我个人的经验是:第一个模拟操作脚本,不要用框架,直接用原生 Selenium 写流程。

原因很直接:框架的抽象层会把一些问题藏起来,比如显式等待、元素定位策略、页面对象模型,框架自动化掉了这些之后,你以为自己会了,但实际上遇到真实问题连 debug 入口都找不到。先用原生代码把“打开页面 → 找元素 → 操作 → 等待”这个循环亲手写顺,后面再上框架,你才知道每个封装底层在干什么。就好比先学会手动挡开车,再去开自动挡,遇到特殊路况不会慌。

3. 模拟用户操作的常见动作拆解

3.1 打开页面与验证加载完成的正确姿势

模拟用户的第一步一定是打开浏览器访问某个 URL,driver.get(url)一句话就能做到。但“页面打开”和“页面真正能用”是两回事。get()方法返回时,只是等到了浏览器触发了页面 load 事件,不代表异步请求里的数据已经渲染出来。很多时候,接口还在 pending,按钮已经出现在 DOM 里,但点击之后根本没反应。

所以,我的习惯是get()之后去等待一个关键元素出现,而不是立刻开始操作:

driver.get("https://example.com/login") login_btn = wait.until(EC.element_to_be_clickable((By.ID, "login-btn")))

这句话的潜台词是:我等的不只是页面加载,等的是“登录按钮处于可点击状态”。比time.sleep(3)这种方式优雅太多,也稳定太多。

3.2 点击操作的三种写法与一个致命坑

点击是模拟操作里最常用的动作,Selenium 提供了三种写法:

element.click() # 最基本 driver.execute_script("arguments[0].click();", element) # JS 点击 ActionChains(driver).move_to_element(element).click().perform() # 模拟人肉鼠标

平时优先用第一种,但有一种场景需要切到第二种:元素被其他透明层遮挡。比如页面上有浮层、loading 遮罩或者弹窗,目标按钮明明在 DOM 里却不在可视区的最上层,直接调用click()会抛ElementClickInterceptedException。这时候用 JS 点击可以绕过不可见层的拦截。这里要特别说明,第二种方式实际上触发的是 DOM 元素的原生 click 事件,类似于你用脚本直接调用元素的onclick,虽然能完成功能触发,但有些通过透明度渐变实现的动效状态变化无法完全模拟,所以能不用就尽量不用。

第三种ActionChains最常见的用途是模拟真实的移动、双击、右键、拖拽。比如某个验证码把人肉鼠标的移动轨迹也作为校验因子,那么纯element.click()就过于“机械”了,配合鼠标移动反而更自然。再比如拖拽排序类的需求,ActionChains(driver).drag_and_drop(source, target).perform()就是标准解法。

3.3 输入框操作:速度、清空与防失效

输入文字用的是element.send_keys(),这个 API 最基本。但真实项目里有三个细节值得展开:

  • 先清空再输入。有些输入框有默认值或者占位符,直接send_keys()会把内容追加在原有内容后面。我在模拟用户信息修改时就遇到过——原值是“张三”,我在后面 append 了“李四”,提交后数据库存了“张三李四”。所以安全的写法是element.clear()之后再做输入。
  • 不要模拟太快的输入。如果是真机环境的富文本编辑器,或者页面有监听input事件做实时校验的逻辑,send_keys()一次性把一长串字符灌进去可能走不到对应的事件分支。尤其做短信验证码类输入框的模拟时,最好用循环单个字符输入,中间加极短延时,模拟真人敲击节奏。
  • 在输入文本里遇到特殊路径问题。比如上传文件时,很多人直接用driver.find_element(...).send_keys("/path/to/file.jpg"),这其实是上传控件最优雅的解决方式,绕过系统弹窗直接写入文件路径,注意这里不需要点击上传按钮,直接把路径塞给 input 元素即可。

3.4 下拉框选择:原生 Select 与伪下拉框

下拉框是自动化里很烦的一个点。遇到原生的<select>元素,Selenium 给你收好了封装:

from selenium.webdriver.support.ui import Select select = Select(driver.find_element(By.ID, "city")) select.select_by_visible_text("上海") select.select_by_index(2) select.select_by_value("shanghai")

三种方式选哪种?如果界面上用户能看到文案,优先用select_by_visible_text,这样最贴近人肉视角,调试的时候你也好判断预期值是什么。select_by_value适合熟悉后台数据值的场景。select_by_index适合你不关心具体内容、只关心顺序的场景。

麻烦的是那些“伪下拉框”——UI 上是<div>加<ul><li>手写的,或者用了第三方组件库。这种无法用 Select 类操作,只能拆成分步操作:先点击下拉区域展开,再定位选项并点击。模拟用户选择城市时,我需要先wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id='citySelect']"))),展开后再定位li文本精确匹配,点击时相比原生精简版本更容易遇到元素浮动、列表折叠,所以一定要用显式等待。

3.5 滚动页面与懒加载模拟

页面元素不一定在当前视口内,Selenium 对于元素不可见时会自动滚动到可视区再操作,但有两类情况自动滚动搞不定:一是页面滚动区域不在主视口里(比如内嵌了overflow: auto的 div),二是数据是懒加载的,你必须先滚动到底部才能触发加载更多。

我用得最多的是execute_script滚动方案:

driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")

这条命令直接把自己滚到页面最底部,触发布局加载。如果只是想精确滚动到某个元素旁边,可以用arguments[0].scrollIntoView({behavior:'smooth', block:'center'});传入元素对象,体验上非常接近人类滑动。我要特别提醒一句,scrollIntoView与 Selenium 自动滚动有一个差异:自动滚动之后元素可能刚好被固定表头或悬浮框遮住,而手动指定块级对齐方式可以尽量避开这种遮挡。实测中,如果你点击一个在页面下方、但头部有悬浮固定导航的按钮,直接click()可能失败或误触到导航栏元素,这时候手动scrollIntoView加一段 JS 点击兜底,基本都能解决。

4. 等待策略:脚本稳不稳,90% 看这里

4.1 为什么不要乱用 time.sleep

我见过太多人写time.sleep(2)、time.sleep(10),然后指着脚本说“不稳定、跑几次就失败”。这个问题的根源在于:固定等待时间是用一个静态时间去赌一个动态场景。网络快的时候等 10 秒纯浪费,网络慢的时候等 10 秒压根不够,莫名其妙就找不到元素了。

那么time.sleep就该完全禁止吗?也不至于。我一般只会在两种场景用它:

  • 刻意模拟人类思考节奏,比如输入完账号后等待 0.5~1 秒再输入密码,案件的行动轨迹更像真人。
  • 某些 JS 动画的等待场景,比如页面切换时带有 300ms 的过渡动画,此时元素可能已经 DOM 可查但位置还在移动,点击很容易失效。

4.2 显式等待是主角:WebDriverWait + expected_conditions

显式等待的正确思路是:给某个操作设定一个最长等待时间,在这段时间内每隔一段轮询判断某个条件是否成立,成立就立即继续。

wait = WebDriverWait(driver, 10, poll_frequency=0.5) save_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//button[contains(text(),'保存')]"))) save_btn.click()

这里poll_frequency=0.5表示每 500 毫秒检查一次,默认值是 0.5 秒,所以其实可以省略。但我会把它写出来,方便团队里其他人知道这里有轮询机制。

常用的expected_conditions大概有这些:

  • visibility_of_element_located:元素在 DOM 中且可见。
  • presence_of_element_located:元素在 DOM 中存在,不一定可见。
  • element_to_be_clickable:元素在 DOM 中、可见且可点击。
  • element_to_be_selected:如单选框、复选框的状态确认。
  • text_to_be_present_in_element:等待某个文本出现在元素里,比如提示语。

实际项目中选哪个条件很关键。比如点击按钮前必须用element_to_be_clickable,因为它额外检查了“元素是否被遮挡”“是否 disabled”,纯粹等visibility是不够的。再比如等待一个表格渲染完成,我往往等第一个数据单元格的文本出现,而不是等空元素出现。

4.3 隐式等待的坑

隐式等待很多人会在一开始就设置,driver.implicitly_wait(10)。它指的是“在查找元素时,如果没找到,轮询等待一段时间再报错”,全局生效。

我个人的建议是:如果用了显式等待,就不要再设隐式等待,或者把隐式等待时间设置得非常短(比如 2 秒)。为什么?两者混用会影响实际等待时长。之前遇到过一个经典问题:显式等待设置了 10 秒,隐式等待也设置了 10 秒,混合之后实际最坏可能出现 20 秒的异常等待。因为显式等待的内部实现里每轮轮询也会调用find_element,而 Selenium 对单个查找方法有隐式等待超时的限制,两者可能叠加。虽然官方后来对行为做过修整,但为了不引入不可控变量,我的做法是保持“尽量只用一种等待策略”。

注意:隐式等待设置之后全局生效,它无法针对单个元素做复杂条件判断。如果你的脚本里既有“等待元素消失”又有“等待元素可点击”,单靠隐式等待做不到。

5. 完整实操案例:登录、查询、翻页、导出一条龙

5.1 模拟用户流程的脚本设计思路

下面用一条典型流程来串一遍前面讲到的所有知识点。假设我有以下业务背景(虚构来源):某内部数据管理平台,用户需要登录系统,进入“订单管理”页面,按日期范围筛选数据,翻到第二页,点击“导出”按钮生成报表。整个流程是日常重复性最高的操作。

设计脚本时我给自己定了几条规则:

  1. 每个页面操作之间先做显式等待,不做无脑 sleep。
  2. 关键步骤留出日志信息,便于失败时定位,到底断在登录、还是断在筛选、还是断在导出。
  3. 通过可复用函数拆解步骤,避免一个脚本全是平铺代码。

5.2 代码落地:从登录到导出的全流程

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import Select USERNAME = "admin" PASSWORD = "pwd12345" driver = webdriver.Chrome() wait = WebDriverWait(driver, 15) try: # 1. 登录页 driver.get("https://example-platform.com/login") wait.until(EC.element_to_be_clickable((By.ID, "username"))).send_keys(USERNAME) driver.find_element(By.ID, "password").send_keys(PASSWORD) driver.find_element(By.XPATH, "//button[contains(text(),'登录')]").click() # 2. 等待首页加载完成后跳到订单管理 wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".welcome-user"))) driver.get("https://example-platform.com/orders") # 3. 在筛选区设置日期范围 start_date = wait.until(EC.element_to_be_clickable((By.ID, "startDate"))) start_date.clear() start_date.send_keys("2024-01-01") end_date = driver.find_element(By.ID, "endDate") end_date.clear() end_date.send_keys("2024-01-31") # 4. 状态下拉用原生 Select status_select = Select(driver.find_element(By.ID, "orderStatus")) status_select.select_by_visible_text("已支付") # 5. 点击查询按钮 driver.find_element(By.XPATH, "//*[@id='searchArea']/button[contains(text(),'查询')]").click() # 6. 等待表格数据加载,然后翻页 wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, ".table-body"), "订单号")) next_page_btn = driver.find_element(By.XPATH, "//*[@class='pagination']//li[contains(text(),'下一页')]") next_page_btn.click() wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, ".pagination .active"), "2")) # 7. 导出 export_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//button[contains(text(),'导出')]"))) export_btn.click() # 若导出产生文件下载,可以等待某个下载完成标志,或在 UI 上出现“导出成功”提示 wait.until(EC.visibility_of_element_located((By.XPATH, "//*[contains(text(),'导出成功')]"))) print("全流程执行成功") finally: driver.quit()

这个脚本里每一步都是前面讲的技术点合集。请注意,登录按钮的定位用的是//button[contains(text(),'登录')],这种方式比直接的By.ID或硬编码 XPath 更强壮,因为按钮的文字是用户可见的,只要产品文案不改,定位就不会断。

5.3 脚本执行过程中的日志观测技巧

在实际工程中,我从来不会只在末尾打印“执行成功”。我会在每做一步后打一条日志:

logging.info("已进入订单管理页面") logging.info("筛选条件设置完成,点击查询")

这样一旦中间某一步失败,堆栈信息配合最后那条日志,三分钟就能定位问题。这个习惯尤其在跑批量自动化回归、几百个用例开着跑的时候至关重要。否则你只看到红屏,根本不知道刚才执行到哪个环节。

6. 常见问题与定位技巧实录

6.1 定位元素失败的三种场景

场景一:页面里存在多个重复元素。

同一个 class 名用于多个按钮,比如页面上有三个叫“确认”的按钮。这时优先用 XPath 中的索引、父子关系或者contains(text())区分:

driver.find_element(By.XPATH, "(//button[contains(text(),'确认')])[2]") # 或 driver.find_element(By.XPATH, "//div[@class='modal-footer']//button[contains(text(),'确认')]")

我在编写 XPath 时的习惯是:先从肉眼看到的结构出发,利用用户可见文本和容器层级去缩窄范围,少用绝对路径/html/body/div[3]/div[2]/button。绝对路径不仅可读性差,页面结构一改就废。

场景二:元素在 iframe 里。

本质原因是,你当前的上下文不在 iframe 里,自然找不到 iframe 内部的元素。解决办法是切换上下文:

frame = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "iframe#contentFrame"))) driver.switch_to.frame(frame) # 操作 iframe 内的元素 driver.switch_to.default_content() # 回到主页面

这个切换动作必须小心翼翼。一旦在 iframe 环境里做了一个主页面操作,就会报找不到元素。我的做法是:进入 iframe 内操作数据,一旦数据操作完,马上切回默认内容层。反过来也一样,回到默认层后再做主页面的操作。

场景三:元素属性是动态渲染的。

很多前端框架(典型的如现代前端框架)会生成一堆随机属性,比如>def click_with_retry(driver, locator, retries=2): for i in range(retries + 1): try: wait = WebDriverWait(driver, 10) wait.until(EC.element_to_be_clickable(locator)).click() return True except Exception as e: if i == retries: raise e time.sleep(1)

这种方法不能乱用,否则会把真正的问题掩盖掉。一般只在click()这种交互边界上使用,对于数据校验类步骤,失败就应该立刻暴露,不该重试。

7. 我踩过三次以上的坑,再啰嗦几句

到这里,基础操作和案例已经讲完。最后再分享几个这几次实际项目中踩过的、让我印象特别深的细节,每一个都属于“文档里不会写、真实项目里绕不过去”的规则。

第一,账号登录态维护。

自动化脚本跑得多了,目标系统大概率会识别到频繁的“异常登录”,弹出验证码,或者直接踢你下线。解决方案通常有两个方向:一是尽量在脚本里保留 Cookie 或登录态复用,比如第一次登录后把 Cookies 存到本地,下次启动时直接注入;二是适当控制操作的节奏和频率。但如果你用--headless模式跑,部分网站会识别出 WebDriver 特征,即便有 Cookie 也容易失效。这没有银弹,只能根据业务形态做取舍。

第二,页面跳转和窗口句柄切换。

点击某个链接后如果打开了新标签页,driver无法直接操作新页面的元素,必须切换句柄:

handles = driver.window_handles driver.switch_to.window(handles[-1])

操作完新标签页再切回来。这里最容易被忽略的是:窗口句柄的获取时机。如果页面还没完全加载出新窗口时去取window_handles,可能只拿到一个老窗口。用显式等一个窗口出现的 API 才稳。

第三,脚本的“结束动作”。

哪怕脚本只做了一次查询,我也建议在finally里写driver.quit()。如果不主动退出,后台进程里残留的浏览器进程会把内存吃满。尤其是在服务器上跑批量任务,一晚上不清理,第二天一上去发现机器卡到爆,再排查发现是 20 个残留浏览器进程在那挂着一动不动。

另外,如果你把 Selenium 脚本部署到服务器上做定时任务,记得加上异常日志落盘和屏幕截图功能。在except分支里:

driver.save_screenshot("failure.png")

这张截图会在半夜定时任务跑挂的时候给你省下两小时的排查时间,这是我用了很久之后才养成的习惯,强烈建议推给团队里的每个人。

关于 Selenium 模拟用户操作这件事,我自己最大的感受是:它不是一个“会调用 API 就会用”的工具,更多的功夫在于你的工程意识——怎么设计等待、怎么处理异常、怎么让脚本不依赖具体页面结构。你把这一层想清楚之后,再去看什么 Page Object、什么自定义封装,都会感觉到非常顺畅。希望这篇文章里提到的经验和坑,能给你的自动化脚本省下一些不必要的头皮发麻时间。

相关新闻

服装品类趋势与消费者洞察数据分析可视化系统实战解析

服装品类趋势与消费者洞察数据分析可视化系统实战解析

1. 毕设选题定位&#xff1a;这个系统到底解决什么问题第一次听到“服装品类趋势及消费者洞察数据分析可视化系统”这个题目&#xff0c;可能觉得只是把一堆图表凑在一起&#xff0c;加上个前端页面&#xff0c;套个电商数据就算完事。实际上真正动手做起来会发现&#xff0c;这…

2026/10/20 9:08:45 阅读更多 →
从聊天助手到工程干将:Claude Code冠军配置的三大支柱与落地实践

从聊天助手到工程干将:Claude Code冠军配置的三大支柱与落地实践

在终端里用 Claude Code 干过几星期活的人&#xff0c;多半会经历一个落差&#xff1a;它讲起架构设计头头是道&#xff0c;可你真把一个完整需求丢过去&#xff0c;让它从头改到尾&#xff0c;它常常干到一半就卡住——不是停下来问"下一步怎么做"&#xff0c;就是自…

2026/10/20 9:08:45 阅读更多 →
LabVIEW电源自动测试系统:状态机与采样链路设计实战

LabVIEW电源自动测试系统:状态机与采样链路设计实战

很多人对电源测试系统的第一印象是“高大上”&#xff0c;好像必须一堆仪器、一堆屏幕、一堆参数才叫完整。我见过不少同行搭出来的系统&#xff0c;机柜七八个U高&#xff0c;界面密密麻麻&#xff0c;绕线绕得跟圣诞树一样&#xff0c;最后测出来的数据却还要靠人肉核对。真正…

2026/10/20 9:07:44 阅读更多 →

最新新闻

AI课程矩阵实战路线:从提示词工程到API调用与批量部署

AI课程矩阵实战路线:从提示词工程到API调用与批量部署

AI 课程现在不难找&#xff0c;难的是判断一门课在你的成长路径里到底处于哪个位置。市面上大量课程要么只教提示词&#xff0c;要么直接堆 ComfyUI 节点&#xff0c;学完能复现案例&#xff0c;但换个场景就不会用了。“河南元力共生 AI 课程矩阵”这个提法&#xff0c;核心是…

2026/10/20 9:45:00 阅读更多 →
秋招十月下旬还没回音:剩下六周怎么排

秋招十月下旬还没回音:剩下六周怎么排

版权与内容来源声明 本文为原创整理。文中涉及官方文档、开源仓库、论文与公开报道的内容&#xff0c;均在附表 A 中标注来源&#xff1b;引用官方原文保持原样&#xff0c;不作改写。文中命令、版本号与界面截图以本文成文时的实测/核验结果为准&#xff0c;标注「待验证」的部…

2026/10/20 9:45:00 阅读更多 →
Matlab GUI实时均衡器:IIR滤波器零极点与音频信号流协同设计

Matlab GUI实时均衡器:IIR滤波器零极点与音频信号流协同设计

简介&#xff1a;本资源是一份面向数字信号处理初学者与Matlab GUI入门者的实践型教学项目&#xff0c;聚焦音频信号频率响应调节这一典型应用场景&#xff0c;帮助学习者掌握IIR滤波器设计原理与交互式界面开发方法。压缩包共3个文件&#xff08;2个.m主程序与辅助函数、1个.f…

2026/10/20 9:45:00 阅读更多 →
企业网盘选型实测:安全管控与协作效率深度对比

企业网盘选型实测:安全管控与协作效率深度对比

测评类文章最容易犯的毛病&#xff0c;就是把配置参数罗列一通&#xff0c;最后丢一句“按需选择”就完事。这篇不一样&#xff0c;我从企业实际使用的角度出发&#xff0c;把真正影响日常协作和数据安全的关键点都拆开讲清楚&#xff0c;包括那些厂商不会主动告诉你的限制和坑…

2026/10/20 9:45:00 阅读更多 →
AI日报系统设计与实现:从RSS聚合到智能摘要生成

AI日报系统设计与实现:从RSS聚合到智能摘要生成

我无法基于当前输入生成符合要求的博文。原因如下&#xff1a;输入中项目标题为“AI 日报&#xff08;2026年10月10日&#xff09;”&#xff0c;但该标题本身不具备可拆解的实质性项目属性——它是一个时间标记型信息聚合名称&#xff0c;而非具体技术实现、工具开发、系统搭建…

2026/10/20 9:45:00 阅读更多 →
FPGA+AD/DA协同设计:H题信号发生器与频谱分析的时序工程实践

FPGA+AD/DA协同设计:H题信号发生器与频谱分析的时序工程实践

简介&#xff1a;本资源为2024年全国大学生电子设计竞赛H题完整参赛代码工程包&#xff0c;面向电子类、自动化、通信等专业本科生及嵌入式开发初学者&#xff0c;聚焦高实时性、强稳定性嵌入式系统实现场景。压缩包含180个文件&#xff0c;主体为C语言源码&#xff08;c/h&…

2026/10/20 9:43:58 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →