前段时间有个老朋友找我,他在公司里维护着一整套基于 VBA 的办公自动化系统,平时处理 Excel 报表、Word 文档批量生成都驾轻就熟。结果前阵子领导丢给他一个需求:每天登录某个业务后台,把当天的新增订单数据抓下来,整理成固定格式的 Excel 报表。活儿不难,但他第一反应是“这得学 Python 了吧”——毕竟现在一搜浏览器自动化,铺天盖地都是 Python 加 Selenium 的教程。我直接拦住了他:先等等,你用的是 VB 和 VBA,有一个叫 SeleniumBasic 的东西,天生就是给 VB 开发者准备的浏览器自动化方案,根本不需要切换技术栈。
SeleniumBasic 说白了就是把官方 Selenium 的功能封装成了一组 COM 组件,让 VB6、VBA 甚至 VBScript 可以直接像操作 Excel 对象模型一样去操作 Chrome、Edge、Firefox。这篇文章我就按自己实际跑通的经验,从环境配置、第一个脚本、元素定位、实战案例到避坑记录,完整写一遍。目标是让你看完之后,5 分钟内写出第一个能跑的自动化脚本。
1. 为什么 VB 开发者做浏览器自动化,首选 SeleniumBasic
1.1 Selenium 官方不支持 VB,但 SeleniumBasic 补上了这个缺口
先聊点背景。Selenium 是目前最主流的浏览器自动化框架,官方提供的语言绑定覆盖了 Java、Python、C#、JavaScript、Ruby 和 Kotlin,但唯独没有 Visual Basic。这对 VB 系开发者来说非常尴尬——明明网页自动化是刚需,却因为语言绑定缺失,要么转学 Python,要么继续用老掉牙的 IE 自动化方案。
SeleniumBasic 这个项目做的事情,就是把这个缺口补上。它把 WebDriver 通信协议封装成了一套符合 VB 使用习惯的 COM 接口,你安装之后,在 VBA 里通过“工具 -> 引用”勾选 Selenium Type Library,就能像使用其他 COM 组件一样调用浏览器。底层依然是 ChromeDriver 和浏览器之间走 WebDriver 协议,稳定性跟 Python 版没有本质区别。
我用个生活化的类比帮你理解:Python 开发者用 Selenium 是“直接说普通话”,VB 开发者用 SeleniumBasic 是“通过一个翻译官说普通话”。翻译官虽然多了一层,但传达的意思完全一致,而且翻译官专门懂 VB 的语法习惯,交流起来反而更顺畅。
1.2 和其他自动化路线的横向对比
在决定用 SeleniumBasic 之前,我和那位朋友把市面上适合 VB 开发者的方案都过了一遍,这里直接给你结论。
| 方案 | 学习成本 | 维护成本 | 浏览器支持 | 适合场景 |
|---|---|---|---|---|
| Python + Selenium | 高(需学新语言) | 中 | Chrome、Firefox、Edge 等全部主流 | 大型爬虫、复杂自动化框架 |
| VBA + IE 自动化 | 低 | 极高 | 仅老版本 IE,微软已停止维护 | 几乎淘汰,不建议投入 |
| SeleniumBasic | 极低(VB 开发者约等于零门槛) | 低 | Chrome、Firefox、Edge | VB6/VBA 项目内的浏览器自动化 |
| 按键精灵类工具 | 低 | 高 | 依赖模拟点击,脆弱 | 没有编程基础的临时场景 |
这个表格里最值得关注的是第二行。很多老项目还在用 IE 自动化,但 IE 已经停止维护,新的网页很多在 IE 内核下渲染都有问题,更别提那些只支持现代浏览器的后台系统。SeleniumBasic 直接操作 Chrome 或 Edge,等于把 VB 自动化项目的生命周期延长了一大截。
选型的时候除了看功能,还得考虑人力成本。公司里现有的 VB 代码、团队技能、维护文档全都不用动,只装一个 SeleniumBasic 就能对接现代浏览器,这是它最大的价值点。
1.3 版本选择和运行环境
SeleniumBasic 有两个大版本需要注意。1.0 系列对应旧版 Selenium,API 风格偏老;2.0 系列开始对齐 Selenium 4 的语法,新增了不少方法,也更好用。我建议新项目直接上 2.0 以上版本,网上大部分教程和博客也是基于 2.0 语法写的。
环境方面其实就三件事:装 SeleniumBasic、装一个 Chrome 浏览器、在 VB 环境里引用 Selenium Type Library。驱动的事情后面会细说,这里先有个概念就行——SeleniumBasic 安装包通常自带对应版本的驱动管理能力,不需要像 Python 那样手工下载 chromedriver 然后设置路径。
注意:不管用什么方案做浏览器自动化,浏览器的自动升级都可能导致驱动版本不匹配。SeleniumBasic 2.0 内建的驱动管理能缓解这个问题,但偶尔还是会出现版本冲突,后面第 5 章我会专门讲怎么排查。
2. 5 分钟跑通第一个脚本:环境准备与基础配置
2.1 下载安装与引用设置
SeleniumBasic 的安装步骤不多,但每一步都有讲究。先说下载,建议去项目的官方发布页面找最新 Release,下载安装包之后直接双击运行,一路默认安装即可。如果你用的是 64 位系统,默认安装路径通常是 Program Files 下的 SeleniumBasic 目录。
装完以后,还需要手动注册一下 DLL 文件,这一步很多人会忘。具体的做法是:以管理员身份打开命令行,切换到 SeleniumBasic 的安装目录,执行 regsvr32 SeleniumBasic.dll。注册成功后系统会弹出一个提示框。如果省略这一步,后面 VBA 里引用类型库时可能找不到组件。
然后是 VBA 或者 VB6 里的引用设置。我以 Excel VBA 为例讲:打开 VBA 编辑器(Alt + F11),菜单栏点“工具 -> 引用”,在弹出的列表里找到 Selenium Type Library,勾选它然后确定。如果列表里没出现,点“浏览”按钮,手动定位到安装目录下的 SeleniumBasic.dll 也可以。
2.2 第一个自动化脚本的逐行拆解
环境齐了,直接上第一个脚本。这个例子演示的是打开一个示例搜索页面,输入关键词,点击搜索按钮,然后读取页面标题弹出来。
Sub Demo_FirstAutomation() ' 创建 ChromeDriver 对象,这一步会自动拉起 Chrome 浏览器 Dim driver As New ChromeDriver ' 打开目标网页 driver.Get "https://example.com/search" ' 通过 id 定位输入框,输入关键词 driver.FindElementById("searchInput").SendKeys "SeleniumBasic" ' 通过 id 定位搜索按钮,模拟点击 driver.FindElementById("searchBtn").Click ' 等待 3 秒,让搜索结果加载完成 Application.Wait Now + TimeValue("00:00:03") ' 读取当前页面标题并弹窗显示 MsgBox driver.Title ' 关闭浏览器并释放对象 driver.Quit Set driver = Nothing End Sub这段代码的逻辑,跟你写 VBA 操作 Excel 其实是一个套路:找到你要操作的对象,然后调用它的方法。Excel 里是 Worksheets("Sheet1").Range("A1").Value,浏览器里是 driver.FindElementById("searchInput").SendKeys——“找到东西,然后做动作”。
几个关键方法先眼熟一下:
- driver.Get:等同于在浏览器地址栏输入网址后回车。
- FindElementById:按 HTML 元素的 id 属性找页面元素,这是最精准的定位方式。
- SendKeys:往输入框里输入文字,等价于键盘打字。
- Click:鼠标点击。
- driver.Quit:关闭浏览器进程。
- driver.Title:读取当前页面的标题文本。
2.3 第一次运行最常见的失败点
这个过程听起来简单,但很多人第一次运行就卡住,我见的坑集中在三个地方。
第一个是浏览器版本冲突。SeleniumBasic 或者底层驱动和本机 Chrome 版本对不上,启动的时候会直接报错,提示 session not created 之类。解决办法是升级 SeleniumBasic 或者把 Chrome 降到兼容版本,后面第 5 章有详细的排查表格。
第二个是弹窗闪退。某些环境下 Excel 的 VBA 运行时会拦截外部进程启动,表现就是代码执行到 New ChromeDriver 那行就没反应了,任务管理器里能看到 Chrome 进程反复启动退出。这个通常跟杀毒软件或者系统策略有关,可以把 Excel 所在目录加入信任区,或者以管理员身份运行 Office。
第三个是引用丢失。今天考完了这个文件,SeleniumBasic 装好了,脚本也能跑。但过几天打开另一个同事发给你的 Excel 文件,发现代码里的 driver 对象全部报错——原因是对方机器上没有安装 SeleniumBasic 或者没注册 DLL。这个不是代码问题,是运行环境的问题,部署脚本到别的机器时一定要把这一步写进操作手册。
3. 元素定位与网页交互的实操要点
3.1 六种定位元素的方式,以及怎么选
脚本能不能跑通,一半取决于你能不能定位到想操作的元素。SeleniumBasic 提供的定位方法跟现代 Selenium 保持一致,常用的我整理成一张表:
| 定位方式 | 方法名 | 适用场景 | 稳定性 |
|---|---|---|---|
| ID | FindElementById | 页面设计规范时优先用 | 最高 |
| Name | FindElementByName | 表单元素常用 | 高 |
| Class Name | FindElementByClassName | 多个元素共用样式时 | 中 |
| XPath | FindElementByXPath | 结构复杂、无 ID 时兜底 | 中(受页面结构调整影响) |
| CSS Selector | FindElementByCssSelector | 结构复杂、无 ID 时兜底 | 中高 |
| Link Text | FindElementByLinkText | 精确定位超链接文本 | 高(仅限 a 标签) |
定位方式的选择有个优先级原则:优先用 ID,没有 ID 用 Name,再不行用固定的 XPath 或者 CSS Selector。为什么?因为页面开发时,ID 和 Name 通常是开发者刻意设计的稳定标识,而 XPath 是跟着页面 DOM 结构走的,只要前端工程师调整了一下嵌套层级,整条 XPath 就废了。
那怎么快速拿到可靠的定位信息?打开 Chrome,按 F12 打开开发者工具,点击左上角的箭头图标,再在页面上点击你要操作的元素,控制台里会自动定位到对应的 HTML 代码。在这段代码上右键,可以选择“Copy -> Copy XPath”或者“Copy -> Copy selector”,拿到的值直接贴进代码里就能用。
不过这里有个提醒:Chrome 自动生成的 XPath 往往是绝对路径,比如 /html/body/div[3]/div[2]/form/input[1],这种路径非常脆弱,前端稍加改动就会失效。更稳的做法是右键 Copy XPath 之后再手动精简成相对路径,或者尽量选带 id 的 XPath 写法,比如 //input[@id='searchInput']。
3.2 输入、点击、下拉框、单选框和弹窗
定位是基础,真正干活靠的是这一组交互操作。我按实际使用频率一个个讲。
输入文本:SendKeys 方法可以往输入框里写内容。需要注意的是,某些页面会自动清理输入框,或者带了输入格式校验,直接 SendKeys 会出问题。保险的做法是先清空再输入:element.Clear,然后 SendKeys。SeleniumBasic 里可以直接连写,也有 Clear 方法。
点击按钮:Click 方法。如果按钮被遮挡或者还没加载出来就点,会报“element is not clickable”错误。这种情况要么加等待,要么用 JavaScript 强制点击。SeleniumBasic 里可以通过 ExecuteScript 调用原生 JavaScript:
driver.ExecuteScript "arguments[0].click();", element这种方式绕过了元素遮挡和可见性检查,基本能解决大部分点击无效的问题。
下拉框选择:处理 select 元素时,直接用 Click 打开下拉列表再 Click 某个 option,在自动化里容易因为选项延迟加载而失败。SeleniumBasic 提供了相对稳定的处理思路,先定位到 select 元素,然后用 SendKeys 输入选项的文本,或者直接通过 JavaScript 设置值。个人经验是,优先用 SelectElement 类封装的方法:
Dim sel As New SelectElement Set sel = driver.FindElementById("province") sel.SelectByValue " Guangdong"单选框和复选框:直接 Click 就行。要注意的是,有的页面组件是用 div 模拟的,不是原生 input,这时 Click 之前最好确认目标元素确实被点击到了——可以通过读取 Click 后的元素状态属性来验证。
弹窗处理:JavaScript 的 alert、confirm、prompt 弹窗出现时,要用 driver.SwitchToAlert 来处理。基本流程是:先判断有没有弹窗(用 driver.SwitchToAlert 之前可以配合错误处理判断),然后调用 Accept 或者 Dismiss。
On Error Resume Next Dim alertObj As Object Set alertObj = driver.SwitchToAlert If Not alertObj Is Nothing Then alertObj.Accept End If On Error GoTo 0这种写法在自动化登录流程里经常用到,很多后台系统登录失败会弹 alert,你不处理它,后续所有操作都卡住。
3.3 等待策略:别再用固定的 Sleep 硬扛
很多初学者写自动化脚本,动不动就是几秒的延时等页面加载。这种做法不是不行,但极不稳定——网络稍慢就超时,页面加载快了又白白浪费时间。正确的做法是使用显式等待,也就是让程序在指定时间内反复尝试某个操作,直到成功或者超时。
SeleniumBasic 里做显式等待比较适合用循环配合错误处理自己实现,也可以用 WebDriverWait。这里分享一个我封装的常用函数:
Public Function WaitForElement(driver As Object, ByVal elementId As String, Optional ByVal timeoutSeconds As Long = 10) As Object Dim startTime As Double startTime = Timer On Error Resume Next Do While Timer < startTime + timeoutSeconds Set WaitForElement = driver.FindElementById(elementId) If Not WaitForElement Is Nothing Then On Error GoTo 0 Exit Function End If Application.Wait Now + TimeValue("00:00:01") Loop On Error GoTo 0 Set WaitForElement = Nothing End Function这个函数的意义在于,把“等多久”从拍脑袋的固定延时,变成了“最多等 N 秒,元素一出现就继续”。脚本整体耗时会大幅下降,稳定性也会提升很多。
经验之谈:凡是要操作页面元素,先问自己一句“这个元素是什么时候出现的?”如果是页面打开就有的,那不用等待;如果是异步加载的,一定要加显式等待,否则就是拿脚本的人品去赌网络速度。
4. 实战项目:自动登录后台系统并抓取数据到 Excel
4.1 案例场景与页面分析
理论过了不少,我们来做一个完整的实战案例。假设你公司的业务后台地址是 https://ops.example.com/login,登录页有一个用户名输入框(id 为 username)、一个密码输入框(id 为 password)、一个登录按钮(id 为 loginBtn)。登录成功后,页面左侧菜单栏有一个“订单管理”链接(文本是“订单管理”),点进去之后页面表格里的数据就是我们要抓取的内容。
这个场景非常典型,几乎覆盖了日常工作中的大部分需求:登录认证、页面跳转、数据抓取、数据落地。先把页面用 F12 打开分析清楚,确认每个目标的 id 或者 XPath,然后再写代码。永远不要没分析页面就开始写脚本,这是我从多次返工里得到的最重要教训。
4.2 登录与数据抓取的核心代码
登录部分,直接看代码:
Sub AutoLoginAndScrape() Dim driver As New ChromeDriver On Error GoTo ErrorHandler ' 打开登录页 driver.Get "https://ops.example.com/login" ' 等待页面加载,找到用户名输入框 driver.FindElementById("username").SendKeys "admin" driver.FindElementById("password").SendKeys "password123" driver.FindElementById("loginBtn").Click ' 等待登录跳转完成,判断是否出现某个登录后才有元素 Dim loggedInElem As Object Set loggedInElem = WaitForElement(driver, "welcomeUser", 10) If loggedInElem Is Nothing Then MsgBox "登录失败,请检查账号密码或网络状态" driver.Quit Exit Sub End If ' 点击“订单管理”菜单 driver.FindElementByLinkText("订单管理").Click ' 等待表格加载 Application.Wait Now + TimeValue("00:00:02") ' 抓取表格第一列的前 20 行数据,写入 Excel Dim i As Long For i = 1 To 20 ' 这里的表格行 XPath 需要根据实际页面结构调整 Dim cellText As String cellText = driver.FindElementByXPath("//table[@id='orderTable']/tbody/tr[" & i & "]/td[2]").Text ThisWorkbook.Sheets("Sheet1").Cells(i, 1).Value = cellText Next i driver.Quit Set driver = Nothing Exit Sub ErrorHandler: MsgBox "执行出错:" & Err.Description If Not driver Is Nothing Then driver.Quit Set driver = Nothing End If End Sub这里要说明几件事。
这个案例里的账号密码是硬编码在代码里的,这样写最简单,但只适合个人本地运行。如果脚本要给同事分发,或者放到服务器上定时跑,凭据管理一定要重视,建议把账号密码读取自一个加密的配置文件,或者从 Excel 表格里读取并做好单元格保护,避免源码泄露导致的问题。
抓取表格数据时,我用了 XPath 遍历 20 行。实际页面上的表格行数可能不固定,更健壮的做法是先统计表格行数:
Dim rowCount As Long rowCount = driver.FindElementByXPath("//table[@id='orderTable']/tbody/tr").CountSeleniumBasic 里查找多个元素要使用 FindElementsByXPath(注意是 Elements),返回的是一个对象集合,然后遍历处理。
4.3 数据落地与定时任务扩展
数据抓下来之后,写入 Excel 只是第一步。我把这个自动化脚本接到 Excel 里定时跑的思路可以分享给你。
Excel 的 Workbook 有个 Open 事件,可以通过 Application.OnTime 设置定时器,在指定时间执行抓取任务。不过 OnTime 只能管一个时间点,要做每日定时最好再配合 Windows 任务计划程序,直接调用一个 VBS 脚本打开 Excel 并触发宏。这样整体方案就是你下班前设置好,第二天早上打开电脑,报表已经在指定文件夹里等着了。
定时任务运行的时候,不能有人等着点击 Excel 里的“启用宏”按钮,所以一定要确保 Excel 的位置设置里把 VBA 宏安全性调成“启用所有宏”,或者给文件做数字签名。这个问题看着小,却在真实环境里坑过我不下三次。
5. 常见问题与排查技巧实录
5.1 高频报错对照表
实践出真知,我把自己和身边朋友跑 SeleniumBasic 遇到过的高频问题整理成了表格。遇到报错先对照查一下,大部分问题都能几分钟定位。
| 报错信息 | 根本原因 | 解决思路 |
|---|---|---|
| session not created | Chrome 版本与驱动版本不匹配 | 升级 SeleniumBasic 或调整 Chrome 版本;检查驱动路径是否有特殊字符 |
| Unable to locate element | 元素定位失败 | 用 F12 确认选择器是否正确;确认元素是否在 iframe 内或影子 DOM 内 |
| Element is not clickable | 元素被遮挡或未完全加载 | 加显式等待;改用 JavaScript 强制执行 click |
| TimeoutException | 等待条件未满足 | 检查网络与页面是否存在反自动化策略;增加等待时间上限 |
| NoSuchWindow | 新标签页或弹窗导致当前窗口失效 | 使用 SwitchToWindow 切换到正确的窗口句柄 |
| Automation object not registered | DLL 未注册 | 以管理员身份运行 regsvr32 SeleniumBasic.dll |
| 脚本运行后 Excel 无响应 | 死循环或对象未释放 | 检查 Do While 循环退出条件;确保错误处理中有 Quit 和 Set Nothing |
这里重点说一个容易误判的问题:Unable to locate element。很多时候不是元素真的不存在,而是这个元素在一个 iframe(内联框架)里。页面结构里,iframe 相当于一个嵌在网页内部的小网页,主页面查找不到子框架里的元素很正常。解决办法是先切入 iframe,操作完再切回来:
driver.SwitchToFrame "frameName" ' 这里再执行元素定位和操作 driver.SwitchToDefaultContent5.2 七个我从实战中总结的避坑心得
第一,永远先确认页面元素真实存在再写定位代码。用 F12 的元素选择器点选目标,确认 ID 或 XPath 能定位到,然后才写进 SeleniumBasic 脚本。不要凭肉眼看到页面上有个按钮就猜 ID,真实的前端页面里 ID 和你想的往往不一样。
第二,中文输入不要直接用 SendKeys。SendKeys 在处理中文字符时在部分系统上会出现乱码或者丢字符的问题。一个稳妥的替代方案是先把文本复制到剪贴板,再用 SendKeys 模拟 Ctrl+V 粘贴。VBA 里可以用 DataObject 配合 Clipboard 实现。
第三,用完的浏览器对象一定要关闭并释放。
If Not driver Is Nothing Then driver.Quit Set driver = Nothing End If这个步骤放进错误处理的统一出口里,可以防止异常中断时浏览器进程残留。残留的 Chrome 进程会吃掉大量内存,还会导致下次启动时端口冲突。
第四,调试脚本期间,建议在关键步骤之间穿插一些 MsgBox 或者立即窗口的输出,确认程序执行到哪一步了。不要指望一次性写出完美的脚本,分步验证永远比整体试错高效。
第五,小心页面自动化和人工操作同时发生。脚本运行期间不要手贱去碰鼠标键盘,尤其不要点页面上的内容,这会导致元素点击失焦或者触发意料之外的事件。建议脚本运行时开一个闲置的显示器,人离开一会儿。
第六,关注无头模式。SeleniumBasic 支持设置浏览器为 Headless 模式,也就是后台运行、不弹出界面。这种模式适合定时任务,占用系统资源更少,而且不受桌面会话影响。但调试阶段不要用无头模式,因为你得看页面才能知道问题在哪。
driver.SetPreference "headless", True第七,脚本里所有页面的网址和元素路径,必须建立在真实运行环境的验证之上。不同环境下网页响应式布局可能会让元素位置变化,但这通常影响点击不报错,而是代码层面上找不到元素。不要盲目相信别人博客里给出的 XPath,一定要结合自己的页面复盘。
5.3 给进阶者的三个实用方向
如果你已经能用 SeleniumBasic 做登录、填表、抓数据,接下来可以考虑三件事。
第一,把重复代码封装成模块级函数。比如 WaitForElement、GetTableData、LogIn 这类,独立成通用的自动化函数库,新的自动化任务就只是把这些函数拼装起来,开发效率和可维护性会明显提升。
第二,处理反自动化检测。某些后台系统会检测自动化特征,你可以尝试设置浏览器的 User-Agent 和其他运行参数来降低识别概率,但具体强度和可行性取决于目标系统的策略,要灵活调整。
第三,对接数据后续处理链。抓下来的数据不要只停留在写入 Excel,可以在 Excel 里结合原有 VBA 代码做数据清洗和格式转换,也可以把数据写入 Access 数据库或者导出为 CSV 供下游系统使用,让浏览器自动化和办公室数据系统真正打通。
写在最后
我个人的体会是,SeleniumBasic 最大的价值不是帮你写出多炫酷的自动化脚本,而是让 VB 系的开发者不需要改变技术栈,就能用自己最熟悉的语言接入现代网页的世界。第一次跑通这个脚本的时候,我是有点激动的——原来以为只有 Python 才能做的浏览器自动化,结果用 VBA 也稳稳地拿下了。
最后再分享一个小技巧:长期维护自动化脚本的时候,一定要在代码里加一段“运行条件检查”,比如确认 Excel 中有两个以上的行数据才继续执行,确认目标页面标题符合预期再进行下一步操作。这种防御式写法看起来很保守,但能让你在凌晨三点收到脚本报错短信的时候,多睡两小时安稳觉。
如果你也是 VB 开发者,手头正好有网页自动化的需求,别犹豫,直接装个 SeleniumBasic 试一下。5 分钟入门是真的,后面能玩出的花样,取决于你的想象力。