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

浏览器自动化技能化实践:从Selenium到模块化流程编排

1. 项目概述从“技能”到“浏览器自动化”的桥梁最近在折腾浏览器自动化的时候发现了一个挺有意思的仓库叫browser-act/skills。乍一看这个名字你可能会有点懵“技能”和“浏览器自动化”有什么关系这其实是一个典型的“以终为始”的工程化思路。我们做自动化无论是爬虫、测试还是RPA机器人流程自动化最终目的都是让浏览器“学会”并“执行”一系列操作。这些操作比如“登录”、“点击”、“填写表单”、“滚动页面”本质上就是一个个独立的“技能”。browser-act/skills这个项目就是把浏览器自动化中那些高频、通用、可复用的操作抽象、封装成一个个标准化的“技能单元”然后像搭积木一样让你可以快速、灵活地组合它们去完成复杂的业务流程。这解决了什么痛点呢回想一下我们写自动化脚本的日常每次新开一个项目都要从零开始写find_element、click、send_keys处理各种等待、异常和反爬。代码重复率高维护起来也头疼。browser-act/skills的思路就是把那些经过千锤百炼的、稳定的操作逻辑沉淀下来形成一套“最佳实践库”。它不仅仅是函数的简单封装更是一种设计模式和工程实践的体现。它适合所有需要与网页进行自动化交互的开发者无论是想快速搭建一个数据采集工具还是为Web应用构建一套健壮的端到端测试甚至是实现一些日常办公的自动化流程都能从这个项目中获得启发和直接的帮助。接下来我就结合自己的实践经验深入拆解一下这个项目的核心设计、具体实现以及那些在文档里不会写的“踩坑”心得。2. 核心设计理念与架构拆解2.1 技能化抽象告别“面条代码”传统的自动化脚本很容易写成“面条代码”——一长串顺序执行的find、click、type命令混杂在一起逻辑纠缠一旦某个页面元素变了或者需要调整流程改起来就非常痛苦。browser-act/skills的第一个核心理念就是“技能化抽象”。它把一次完整的、有意义的浏览器交互定义为一个“技能”。比如“在搜索框输入关键词并点击搜索按钮”这整个流程会被封装成一个SearchSkill。这个技能内部会处理所有细节定位搜索框、清空原有内容、输入文本、定位搜索按钮、点击、等待结果加载。对外它只暴露一个简单的接口比如execute(keyword)。这样做的好处显而易见高内聚一个技能只做一件事并且把所有相关逻辑都封装在内部外部无需关心实现细节。低耦合技能之间通过清晰的接口进行组合修改一个技能的内部实现只要接口不变就不会影响其他技能。可复用封装好的LoginSkill、ExtractTableSkill可以在不同的项目、不同的流程中直接调用极大减少了重复开发。易测试每个技能都可以被独立地进行单元测试确保其行为的正确性。在实际架构上项目通常会定义一个基础的BaseSkill类所有具体技能都继承自它。这个基类会规定一些通用接口比如execute()执行方法、validate()前置条件校验、teardown()后置清理等。这种面向对象的设计让整个技能体系非常规整和易于扩展。2.2 上下文管理与状态传递浏览器自动化不是执行一个个孤立的命令而是一个有状态的连续过程。比如你登录后获得的session cookies或token需要在后续的请求中携带上一个技能提取的数据可能是下一个技能的输入。因此上下文管理是这类框架的第二个核心。browser-act/skills需要一套机制来在技能之间安全、高效地传递状态。常见的做法是引入一个Context或Session对象。这个对象贯穿整个自动化流程的生命周期可以存储诸如浏览器驱动实例如 Selenium 的WebDriver对象。用户会话数据Cookies、Tokens、登录状态等。流程共享变量从页面A提取的数据用于在页面B进行查询。配置信息超时时间、重试策略、代理设置等。每个技能在执行时都能从Context中获取它需要的资源如驱动实例并将产出物如提取的数据写回Context。这样技能本身是无状态的、纯粹的其行为完全由输入参数和当前上下文决定这使得它们更加可靠和可预测。在实现时需要特别注意上下文的线程安全如果是并发执行和生命周期管理何时创建、何时销毁。2.3 流程编排与错误恢复当有了一个个独立的技能后如何将它们串联起来完成一个复杂任务这就是流程编排要解决的问题。browser-act/skills项目通常会提供或兼容一种流程定义方式可能是基于YAML/JSON的声明式配置也可能是通过代码进行链式调用。一个声明式的流程配置可能长这样name: “商品信息抓取流程” steps: - skill: “NavigateSkill” params: url: “https://example.com/login” - skill: “LoginSkill” params: username: “{{USER}}“ password: “{{PASS}}“ - skill: “SearchSkill” params: keyword: “笔记本电脑” save_as: “search_results_page” - skill: “ExtractProductListSkill” params: source: “search_results_page” save_as: “product_links” - skill: “ForEachSkill” params: items: “{{product_links}}“ loop_skill: “ExtractProductDetailSkill”这种配置非常直观易于理解和修改。框架的核心引擎会解析这个配置按顺序实例化并执行各个技能并处理它们之间的数据依赖通过save_as和{{}}变量插值。更关键的是错误恢复。网络不稳定、页面元素加载慢、反爬机制触发都是自动化脚本的“天敌”。一个健壮的技能框架必须内置重试、熔断、降级等机制。例如一个ClickSkill在元素不可点击时不应立即报错退出而应该等待一段时间显式等待。记录日志并尝试重试最多3次。如果重试失败则触发一个预定义的“降级技能”比如记录错误并跳过此步骤或者尝试替代的点击路径。如果错误是致命的如登录失败则优雅地终止整个流程并保存当前状态以便后续排查。这种设计使得自动化流程具备了“韧性”能够在非绝对理想的环境下依然尽可能地完成任务这对于需要长时间运行的无人值守自动化任务至关重要。3. 核心技能详解与实现要点3.1 导航与等待技能稳定的基石NavigateSkill和WaitSkill看似简单却是所有自动化流程稳定性的基石。它们的实现远不止调用driver.get(url)和time.sleep()那么简单。导航技能的核心在于“如何定义导航成功”。是页面document.readyState为complete就够了吗对于现代大量使用JavaScript异步加载的SPA单页应用来说这远远不够。一个健壮的NavigateSkill应该清除残留状态在发起新导航前清除可能影响新页面的alert、modal或意外的WebSocket连接。智能等待导航后等待基础DOM就绪只是第一步。更重要的是等待“关键元素”出现。这需要技能接收一个或多个“等待目标”选择器作为参数。例如导航到登录页后必须等待用户名输入框出现才算成功。处理重定向和弹窗自动处理页面的重定向链并能应对导航过程中可能出现的浏览器原生弹窗如基本认证对话框虽然现代网站较少使用。性能与超时设置合理的页面加载超时时间并在超时后尝试刷新或执行备用方案。等待技能则更加多样化。除了固定的sleep更重要的是各种“条件等待”元素等待等待元素出现、可见、可点击、消失。文本等待等待某段特定文本出现在页面或某个元素内。URL等待等待URL包含或匹配某个特定模式。自定义条件等待等待一个自定义的JavaScript函数返回true。实操心得永远不要使用固定的time.sleep。它效率低下且不可靠。务必使用 Selenium 提供的WebDriverWait结合expected_conditions或者自己封装更灵活的等待条件。将等待逻辑集中到WaitSkill中可以让流程配置更清晰比如明确写出“等待‘提交成功’的提示框出现”而不是把等待时间硬编码在某个点击操作之后。3.2 交互技能模拟真实用户ClickSkill,InputSkill,SelectSkill等属于交互技能。它们的挑战在于如何让交互行为更接近真人以及如何处理复杂的页面结构。点击技能元素定位策略不能只依赖单一的id或xpath。一个健壮的ClickSkill应该支持多定位器备选方案。例如优先用id失败后尝试css selector再失败则尝试包含特定文本的xpath。这能有效应对网站前端微调导致的选择器失效。滚动与可视区域点击前应确保元素滚动到可视区域中心。直接对不可见元素操作可能会被浏览器忽略或导致异常。交互方式除了标准的element.click()有时需要模拟更复杂的交互如ActionChains的链式操作鼠标悬停后再点击或者直接触发JavaScript的click事件以绕过某些前端框架的监听。点击后等待点击操作通常会引发页面状态变化导航、弹窗、局部刷新。ClickSkill应该能配置点击后的“预期结果等待”例如点击提交按钮后等待“提交成功”提示或页面跳转。输入技能模拟真人输入不要一次性send_keys全部文本。可以模拟人的输入节奏将长文本拆分成多个字符并加入随机的小延迟。这对于绕过一些基于输入速度的反爬机制有一定效果。清空操作输入前如何清空原有内容element.clear()并不总是有效特别是对于React/Vue等框架绑定的输入框。有时需要先全选send_keys(Keys.CONTROL “a”)再删除或者直接通过JavaScript设置value属性。处理特殊输入框如富文本编辑器、文件上传、日期选择器等需要特殊的处理逻辑这些都可以封装成更细化的技能变体。3.3 提取技能数据获取的艺术ExtractTextSkill,ExtractAttributeSkill,ExtractTableSkill是价值输出的关键。其核心是选择器的灵活性与数据的结构化。多模式选择器支持和交互技能一样提取技能也应支持多种定位方式并能优雅地处理元素未找到的情况返回None或空值而非抛出异常。数据清洗管道提取到的原始文本往往包含多余空格、换行符、不可见字符或无意义的占位符。一个优秀的提取技能应该内置或可配置数据清洗管道Pipeline例如去除首尾空格、合并连续空格、过滤特定字符、应用正则表达式提取核心部分等。这些清洗规则可以在技能参数中定义。结构化提取对于列表或表格数据ExtractTableSkill需要将table标签或一系列div模拟的列表转化为结构化的数据如列表字典。这里要处理表头可能跨行跨列、单元格合并等复杂情况。有时直接解析HTML不如先获取整个区域的HTML然后用像pandas.read_html这样的库来处理虽然会引入额外依赖。动态内容提取对于由JavaScript动态渲染的内容简单的element.text可能获取不到。需要判断情况有时需要获取innerHTML有时需要执行特定的JS代码来获取数据状态。注意事项提取技能的设计要考虑到下游数据的使用。明确输出数据的格式字符串、数字、列表、字典并保持一致性。对于可能提取失败的情况要有明确的日志记录和错误处理策略比如标记该条数据提取失败但流程继续执行下一条。3.4 高级组合技能实现复杂逻辑基础技能之上需要一些“组合技能”或“控制流技能”来实现复杂逻辑这才是体现框架威力的地方。条件判断技能例如IfSkill。它根据上下文中的某个变量或上一个技能的输出结果决定执行哪一条分支流程。这实现了流程的动态化。循环技能例如ForEachSkill或WhileSkill。用于遍历一个列表如所有商品链接并对每个项执行相同的子流程如提取商品详情。这里要特别注意循环体内的上下文隔离避免迭代间数据污染。序列技能这是一个“技能容器”用于按顺序执行一组子技能并可能管理它们之间的局部上下文。并行技能用于并发执行多个独立的任务以提高效率。但浏览器驱动如WebDriver通常不是线程安全的实现并行需要谨慎通常采用多进程或多浏览器实例的方式这对上下文管理提出了更高要求。这些高级技能将简单的操作序列提升到了“可编程工作流”的层面使得自动化脚本能够应对非常复杂的业务场景。4. 项目实战构建一个商品比价机器人理论说了这么多我们动手用browser-act/skills的思路即使不直接用该库也遵循其理念来构建一个实用的商品比价机器人。这个机器人的目标是在多个电商网站上搜索同一款商品提取其价格、名称、店铺等信息并汇总成表格。4.1 技能定义与封装首先我们定义并封装几个核心技能。这里用Python和Selenium进行示意。1. 通用导航与等待技能class RobustNavigateSkill: def __init__(self, driver): self.driver driver def execute(self, url, wait_for_selectorNone, timeout30): 导航到指定URL并可选地等待某个元素出现 try: self.driver.get(url) if wait_for_selector: WebDriverWait(self.driver, timeout).until( EC.presence_of_element_located((By.CSS_SELECTOR, wait_for_selector)) ) return {“status”: “success”, “url”: self.driver.current_url} except TimeoutException: return {“status”: “error”, “message”: f”等待元素 {wait_for_selector} 超时”} except Exception as e: return {“status”: “error”, “message”: str(e)}2. 智能输入与搜索技能class SmartSearchSkill: def __init__(self, driver): self.driver driver def execute(self, search_box_selector, keyword, search_button_selector, input_delay0.1): 在搜索框模拟人工输入并点击搜索 try: search_box WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, search_box_selector)) ) search_box.clear() # 模拟真人输入 for char in keyword: search_box.send_keys(char) time.sleep(random.uniform(input_delay*0.5, input_delay*1.5)) # 点击搜索按钮 search_button self.driver.find_element(By.CSS_SELECTOR, search_button_selector) self.driver.execute_script(“arguments[0].scrollIntoView({block: ‘center’});”, search_button) time.sleep(0.5) search_button.click() return {“status”: “success”} except Exception as e: return {“status”: “error”, “message”: str(e)}3. 商品列表提取技能class ExtractProductListSkill: def __init__(self, driver): self.driver driver def execute(self, item_container_selector, name_selector, price_selector, link_selector, max_items10): 从列表页提取商品基本信息 products [] containers self.driver.find_elements(By.CSS_SELECTOR, item_container_selector)[:max_items] for container in containers: try: name_elem container.find_element(By.CSS_SELECTOR, name_selector) price_elem container.find_element(By.CSS_SELECTOR, price_selector) link_elem container.find_element(By.CSS_SELECTOR, link_selector) product { “name”: name_elem.text.strip(), “price”: self._clean_price(price_elem.text), “url”: link_elem.get_attribute(“href”) } products.append(product) except Exception as e: print(f”提取单个商品时出错: {e}”) continue return {“status”: “success”, “data”: products} def _clean_price(self, price_text): 清洗价格文本提取数字 import re # 匹配数字和可能的小数点 match re.search(r[\d,]\.?\d*, price_text.replace(‘,’, ‘’)) return float(match.group()) if match else 0.04.2 流程编排与上下文管理我们创建一个简单的Context类和流程执行器。class AutomationContext: def __init__(self): self.driver None # WebDriver实例 self.data {} # 存储流程中的数据如 {“jd_products”: […], “taobao_products”: […]} self.config {“headless”: False, “timeout”: 30} class FlowExecutor: def __init__(self, context): self.ctx context self.skills { “navigate”: RobustNavigateSkill(context.driver), “search”: SmartSearchSkill(context.driver), “extract_list”: ExtractProductListSkill(context.driver), } def run_flow_for_website(self, website_config, keyword): 针对一个特定网站执行比价流程 site website_config[“name”] print(f”开始处理网站: {site}“) # 1. 导航到网站首页 nav_result self.skills[“navigate”].execute(website_config[“url”], website_config[“home_ready_selector”]) if nav_result[“status”] ! “success”: print(f”导航到 {site} 失败: {nav_result.get(‘message’)}“) return # 2. 执行搜索 search_result self.skills[“search”].execute( website_config[“search_box”], keyword, website_config[“search_button”] ) if search_result[“status”] ! “success”: print(f”在 {site} 搜索失败: {search_result.get(‘message’)}“) return time.sleep(2) # 等待结果加载理想情况下应使用更智能的等待技能 # 3. 提取商品列表 extract_result self.skills[“extract_list”].execute( website_config[“item_container”], website_config[“name_selector”], website_config[“price_selector”], website_config[“link_selector”], max_items5 ) if extract_result[“status”] “success”: self.ctx.data[f”{site}_products”] extract_result[“data”] print(f”从 {site} 成功提取 {len(extract_result[‘data’])} 条商品信息”)4.3 配置与执行最后我们通过配置来定义要爬取的网站和对应的选择器然后执行流程。# 网站配置选择器需要根据实际网站结构调整 websites_config [ { “name”: “京东”, “url”: “https://www.jd.com”, “home_ready_selector”: “#key”, “search_box”: “#key”, “search_button”: “.button”, “item_container”: “.gl-item”, “name_selector”: “.p-name a”, “price_selector”: “.p-price i”, “link_selector”: “.p-name a” }, { “name”: “淘宝”, “url”: “https://www.taobao.com”, “home_ready_selector”: “#q”, “search_box”: “#q”, “search_button”: “.btn-search”, “item_container”: “.item.J_MouserOnverReq”, “name_selector”: “.title”, “price_selector”: “.price strong”, “link_selector”: “.pic-link.J_ClickStat.J_ItemPicA” } ] def main(): # 初始化上下文和浏览器 ctx AutomationContext() options webdriver.ChromeOptions() if ctx.config[“headless”]: options.add_argument(“--headless”) ctx.driver webdriver.Chrome(optionsoptions) executor FlowExecutor(ctx) keyword “无线蓝牙耳机” all_results {} try: for site_config in websites_config: executor.run_flow_for_website(site_config, keyword) # 简单汇总 site_name site_config[“name”] if f”{site_name}_products” in ctx.data: all_results[site_name] ctx.data[f”{site_name}_products”] # 打印汇总结果 print(“\n 比价结果汇总 ”) for site, products in all_results.items(): print(f”\n【{site}】”) for p in products: print(f” {p[‘name’][:30]}... - {p[‘price’]}“) finally: ctx.driver.quit() if __name__ “__main__”: main()这个实战案例展示了如何将技能化思想落地。通过将导航、搜索、提取封装成独立的技能并通过一个执行器在统一的上下文中调度它们我们构建了一个结构清晰、易于扩展和维护的比价机器人。要增加一个新网站只需要在配置数组中添加一套新的选择器即可核心流程代码无需改动。5. 避坑指南与性能优化在实际使用这类技能化框架或自行构建时会遇到许多坑。下面是一些常见的“坑点”和优化建议。5.1 元素定位失效动态性与反爬这是最常见的问题。网站改版、前端框架渲染、动态加载都会导致选择器失效。对策1使用相对稳定的选择器优先选择id、name其次是具有明确语义的class或>

相关文章:

浏览器自动化技能化实践:从Selenium到模块化流程编排

1. 项目概述:从“技能”到“浏览器自动化”的桥梁最近在折腾浏览器自动化的时候,发现了一个挺有意思的仓库,叫browser-act/skills。乍一看这个名字,你可能会有点懵:“技能”和“浏览器自动化”有什么关系?这…...

从IDF 2012看英特尔技术十字路口:Haswell能效革命与Atom移动困局

1. 从IDF 2012看英特尔的技术十字路口:Haswell的辉煌与Atom的迷雾 2012年9月的旧金山,空气中弥漫着一股熟悉的、属于硅谷的躁动。英特尔开发者论坛(IDF)即将拉开帷幕,而就在同周,苹果也计划发布新品。对于当…...

Vue3项目里用ArcGIS SDK加载地图,保姆级配置流程(含样式避坑)

Vue3项目集成ArcGIS SDK全流程指南:从配置到样式优化实战 在当今数据驱动的时代,地理信息系统(GIS)已成为现代Web应用不可或缺的一部分。作为行业领先的GIS平台,ArcGIS提供了强大的JavaScript SDK,而Vue3的响应式特性和组合式API则…...

突破OBS音频局限:揭秘如何为直播软件添加专业级VST插件支持

突破OBS音频局限:揭秘如何为直播软件添加专业级VST插件支持 【免费下载链接】obs-vst Use VST plugins in OBS 项目地址: https://gitcode.com/gh_mirrors/ob/obs-vst 想要在OBS Studio中实现专业级的音频处理,却受限于内置的基础滤镜&#xff1f…...

如何高效修复损坏视频:智能MP4修复工具Untrunc实用指南

如何高效修复损坏视频:智能MP4修复工具Untrunc实用指南 【免费下载链接】untrunc Restore a damaged (truncated) mp4, m4v, mov, 3gp video. Provided you have a similar not broken video. 项目地址: https://gitcode.com/gh_mirrors/unt/untrunc 你是否曾…...

地铁站台门控系统集成方案:三菱Q系列PLC以太网通讯与上位机联动实例

一、行业背景与项目概况1.1 行业背景与核心需求轨道交通站台设备管控核心需求聚焦于安全可靠与高效运维:一是实现站台各类设备协同控制,保障屏蔽门与列车联动、应急报警快速响应,杜绝安全隐患;二是支持现场操作与中控室远程管控协…...

如何实现跨平台输入法词库迁移?深蓝词库转换技术架构解析

如何实现跨平台输入法词库迁移?深蓝词库转换技术架构解析 【免费下载链接】imewlconverter ”深蓝词库转换“ 一款开源免费的输入法词库转换程序 项目地址: https://gitcode.com/gh_mirrors/im/imewlconverter 在数字化工作环境中,输入法的个性化…...

搞网络安全的,谁还没几个压箱底绝活?可AI来了以后呢?

前两天跟几个同事在路边摊撸串,聊起今年这波AI浪潮,大家伙儿眼里的光明显暗了不少。以前在圈子里混,手里没几个压箱底的绝活儿根本站不住脚。不管是熬大夜脱个壳,还是手工抠那个Payload,那都是实打实的本事。可现在呢&…...

账户维护、登出与多模态文件独立接口

1&#xff09;登出&#xff1a;Header 或 Query 传 TokenPostMapping("/logout")public Result<Void> logout(RequestHeader(value "Authorization", required false) String authorization,RequestParam(value "token", required fal…...

高盐废水处理:一项成熟技术解析

行业痛点分析2026年&#xff0c;高盐废水处理仍是工业环保领域的核心挑战。数据显示&#xff0c;我国每年产生的高盐废水超过200亿吨&#xff0c;其中食品加工、化工、制药等行业贡献显著。根据《环境工程学报》2024年的一项研究&#xff0c;当盐浓度超过0.2%时&#xff0c;普通…...

发票识别OCR API接入详解:自动提取发票全字段并接入财务系统(附Python/JS/PHP示例)

发票识别OCR API接入详解&#xff1a;自动提取发票全字段并接入财务系统&#xff08;附Python/JS/PHP示例&#xff09; 企业财务场景中有一个长期存在的低效问题&#xff1a;发票信息录入全靠人工——每天处理几十到上百张发票&#xff0c;逐张录入金额、日期、税号等信息&…...

ARM Trace单元架构与异常追踪技术解析

1. ARM Trace单元架构概述在现代处理器设计中&#xff0c;Trace单元作为调试基础设施的核心组件&#xff0c;承担着实时记录指令执行流的重任。与传统的断点调试不同&#xff0c;Trace技术通过非侵入式的方式捕获处理器运行时的完整行为&#xff0c;为系统级问题诊断提供了时间…...

70 岁吕良伟分享科学养生:逆龄状态来自 16+8 轻断食与营养均衡实践

近日&#xff0c;演员吕良伟以 70 岁依然稳健挺拔的身心状态&#xff0c;成为大众关注的健康生活方式标杆。经专业生理年龄评估&#xff0c;其心血管、免疫、内分泌等关键机能均保持青壮年水准&#xff0c;展现出长期科学养生的显著成果。面对外界关注的养生秘诀&#xff0c;吕…...

别再傻傻打全称了!LaTeX/BibTeX用户如何一键搞定IEEE引用格式(含期刊会议缩写库)

LaTeX/BibTeX高效引用&#xff1a;IEEE期刊会议缩写自动化解决方案 引言 每次在LaTeX论文中引用IEEE文献时&#xff0c;你是否都要手动输入完整的期刊会议名称&#xff1f;当参考文献列表中出现格式不统一的缩写时&#xff0c;审稿人会不会皱眉&#xff1f;作为计算机、电子工程…...

下一代物联网基站硬件设计:从异构计算到信号完整性的工程实践

1. 下一代网络基站工程设计的核心挑战与思路拆解十年前&#xff0c;当Lawrence Latif在EE Times上探讨物联网对下一代基站的要求时&#xff0c;他精准地预见了我们今天面临的许多问题。站在一个硬件工程师的角度回看&#xff0c;那篇文章更像是一份精准的“需求预测清单”。如今…...

ProdMan:为AI原生PM打造的结构化工作流与产品记忆框架

1. 项目概述&#xff1a;一个为AI原生产品经理设计的结构化工作流框架如果你正在用Claude Code、Cursor这类AI编码助手来构建产品&#xff0c;那你一定经历过这种循环&#xff1a;每次打开一个新对话&#xff0c;都得把产品背景、用户画像、技术栈限制从头到尾再解释一遍&#…...

静态代码分析中SAT技术的应用与优化

1. 静态代码分析的演进与挑战静态代码分析技术自20世纪70年代诞生以来&#xff0c;已经历了三代技术演进。第一代以Lint工具为代表&#xff0c;主要通过模式匹配检测代码中的可疑构造&#xff0c;但由于其高达10:1的噪声比&#xff08;即每发现1个真实缺陷会产生10条无关警告&a…...

悬空的语言:大语言模型与人类对“理解“的本质差异

大语言模型能说出正确的答案&#xff0c;却不知道自己为什么对。人能感受到苹果的重量&#xff0c;才真正懂得"苹果会落下"。这一行字的距离&#xff0c;是人与机器之间最深的鸿沟。一、从一句话开始"桌上有个苹果。"当你读到这句话&#xff0c;脑海里浮现…...

ZynqMP SD卡启动全记录:从Vivado配置到Linux命令行(基于黑金AXU2CGB板)

ZynqMP SD卡启动实战指南&#xff1a;黑金AXU2CGB开发板全流程解析 当一块崭新的ZynqMP开发板摆在面前&#xff0c;如何快速搭建完整的启动环境往往是开发者面临的第一个挑战。不同于传统嵌入式系统&#xff0c;ZynqMP的异构架构和多重启动阶段让许多初次接触的工程师感到困惑。…...

chrome-devtools mcp使用问题记录

问题描述&#xff1a; 简述&#xff1a;使用chrome-devtools mcp连接已有chrome实例打开网页时&#xff0c;点击允许后&#xff0c;一直卡着 背景&#xff1a; 在cursor中通过 "chrome-devtools": {"command": "npx","args": [&quo…...

告别低效采集!用MaixHub+K210+Mx_yolov3打造端到端物体识别项目(附数据集处理技巧)

从零构建K210端侧AI项目&#xff1a;基于MaixHub与Mx_yolov3的高效开发实战 在嵌入式AI领域&#xff0c;K210芯片凭借其低功耗、高性能的特性&#xff0c;已成为创客和开发者的热门选择。但许多初学者在构建完整物体识别项目时&#xff0c;常陷入数据采集低效、模型转换复杂、部…...

芯片低功耗设计实战:从概念到签核的全流程解析与避坑指南

1. 低功耗设计&#xff1a;一个被营销文案耽误的宝藏作为一名在芯片设计领域摸爬滚打了十几年的工程师&#xff0c;我见过太多“金玉其外&#xff0c;败絮其中”的技术资料&#xff0c;也见过不少“其貌不扬&#xff0c;内藏乾坤”的干货。今天想聊的&#xff0c;就是后者——一…...

【图像处理】基于改进樽海鞘群优化的图像匹配方法附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、程序设计科研仿真。 &#x1f34e;完整代码获取 定制创新 论文复现点击&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &…...

【布局优化】基于改进SLP与遗传算法的梁场布局优化附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、程序设计科研仿真。 &#x1f34e;完整代码获取 定制创新 论文复现点击&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &…...

长期使用Taotoken聚合API对项目月度账单清晰度的感受

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 长期使用Taotoken聚合API对项目月度账单清晰度的感受 1. 项目成本管理的初始挑战 在引入大模型能力到项目开发的早期阶段&#xf…...

S32K3安全机制深度拆解:当CPU、内存、时钟“生病”时,芯片如何自救与报警?

S32K3安全机制深度拆解&#xff1a;当CPU、内存、时钟“生病”时&#xff0c;芯片如何自救与报警&#xff1f; 想象一下&#xff0c;一辆高速行驶的智能汽车突然遭遇CPU运算错误或内存数据损坏——这不是科幻场景&#xff0c;而是汽车电子系统每天需要防范的真实风险。S32K3系列…...

RV1126双摄IMX577驱动移植避坑指南:从RK3588源码到稳定运行的完整流程

RV1126双摄IMX577驱动移植实战&#xff1a;从RK3588源码到稳定运行的避坑全流程 在嵌入式视觉系统开发中&#xff0c;Rockchip RV1126凭借其出色的图像处理能力和低功耗特性&#xff0c;成为智能摄像头、工业检测等场景的热门选择。而索尼IMX577作为一款高性能1200万像素传感器…...

反转课堂从作业开始!PPT内置作业管理工具,课代表扛活、学生自评,老师终于能闲下来啦!

边听边看收获更多&#xff01;作业管理陷入 “老师全包” 困境&#xff1f;三个问题戳中痛点&#xff01;收作业、登名单、改作业、记手册&#xff0c;老师一人包揽所有流程&#xff0c;每天被琐事缠身&#xff0c;根本没精力深耕教学&#xff1f;学生被动交作业、等待老师评价…...

小米Agent岗二面:RAG知识库文档更新,不重建全量就搞不定?

&#x1f454;面试官&#xff1a;你们 RAG 知识库上线之后&#xff0c;文档更新了怎么办&#xff1f;总不能每次改个文档就把整个知识库重建一遍吧。 &#x1f64b;‍♂️我&#xff1a;可以直接找到变了的那个 chunk&#xff0c;更新它的向量就行了。 &#x1f454;面试官&a…...

EDA初创公司CEO更迭背后的技术商业化与生存逻辑

1. 从CEO更迭看EDA初创公司的生存逻辑在半导体设计自动化这个高度专业且竞争激烈的赛道上&#xff0c;一家公司的CEO频繁更迭&#xff0c;往往比财报上的数字更能说明问题。最近&#xff0c;Calypto这家专注于电子系统级设计和功耗优化工具的公司&#xff0c;迎来了其自2002年成…...