在VBA圈子里,跟浏览器打交道的需求,十个里有七八个都长一个样:手动开网页、复制数据、回Excel粘贴、再点下一页……一上午下来人就成了人肉读取机。我第一次做这种事的时候,用的还是老掉牙的WebBrowser控件,页面一换新渲染方式就白屏,JavaScript报错防不胜防。后来换个思路,把Selenium这套标准的浏览器自动化框架搬进VB环境,这就是SeleniumBasic的价值所在。
这篇文章会把SeleniumBasic从环境搭建、元素定位、iframe与多窗口处理、等待策略、Excel联动到性能优化完整拆一遍,附上我实际项目中踩过的坑和验证过的写法。适合所有想用VB或VBA做浏览器自动化的人,哪怕你完全没写过自动化脚本,照着抄也能跑起来。
1. SeleniumBasic是什么:在VBA里长出一套标准自动化能力
1.1 为什么轮到VBA来玩浏览器自动化
早期VBA操作浏览器,最常被推荐的就是往窗体上拖一个WebBrowser控件,或者直接用InternetExplorer对象。这套老方案的问题在于:它把控制逻辑绑定在IE内核上,现代网页的异步渲染、CSS动画、Fetch请求全都处理不好。你明明看到页面上有内容,程序却拿不到;好不容易定位到元素,页面一刷新,引用全部失效。
SeleniumBasic本质上是把Selenium的WebDriver协议封装成了COM组件,安装后注册到系统里,VBA代码可以直接调用。它控制的是Chrome或Firefox这类现代浏览器,内核和渲染能力跟正常浏览器完全一致,不存在“页面看得见但自动化拿不到”的问题。更关键的是,它的API设计基本对齐Selenium官方Java/C#版本的语义,只要你会VBA的基本语法,就能写出非常接近标准Selenium风格的代码。
1.2 它和Python版Selenium的差别在哪里
很多朋友会问:既然Python写爬虫那么方便,为什么还要在VBA里做?答案其实很现实:很多办公场景的任务根本不该离开Excel。你的数据源是Excel,结果要写回Excel,中间还夹杂着公司内部系统的登录、页面填表、报表下载,这时候用VBA直接驱动浏览器,是闭环最短、部署成本最低的方案。
| 对比维度 | Python版Selenium | SeleniumBasic |
|---|---|---|
| 安装方式 | pip install selenium,还要配Python环境 | 安装一个MSI包,VBA里勾选引用即可 |
| 开发环境 | PyCharm/VS Code | 直接写在Excel的VBE里 |
| 驱动管理 | 需要手动下载并配置WebDriver | 同样需要手动配置,但可以在VBA里显式指定路径 |
| 代码风格 | 使用Python语法 | 使用VBA语法,方法名和属性几乎一致 |
| 适合人群 | 能折腾Python环境的人 | 只想在Excel里完成目标的人 |
SeleniumBasic对多数VBA用户来说是更自然的选择,因为你的自动化脚本可以直接引用当前工作簿里的单元格数据,跑完结果立刻回填,不需要再折腾文件导出导入。
2. 三步完成环境搭建:最容易卡住的地方其实只有一步
2.1 安装SeleniumBasic并添加类型库引用
第一步很简单:去SeleniumBasic的开源发布页面下载最新的安装包。注意看清版本,推荐用稳定版而不是Beta版,Beta版封装的方法虽然更新,但踩到未知问题的概率也更高。
安装完成后,打开任意Office程序,按Alt+F11进入VBE编辑器,找到菜单栏的“工具-引用”,在弹出的引用对话框里勾选“SeleniumBasic Type Library”。这一步做完,VBA代码里输入driver.的时候就应该能弹出方法补全,说明类型库注册成功。
包里自带两个演示用的BAS模块,一个是快速启动示例,一个是基础定位示例。建议把这两个模块导入到你的工程里先跑一遍,能跑通就说明环境已经OK,后面的问题基本都集中在驱动版本上。
2.2 ChromeDriver版本匹配:新手最容易翻车的第一关
如果只记一条经验,那就是:Chrome浏览器和ChromeDriver驱动的大版本号必须一致。Chrome是126,驱动就必须是126.x,不能用125,也不能用127。这就像拿错钥匙开车,车门都对不上,后面全白搭。
查看浏览器版本的路径是Chrome菜单-帮助-关于Chrome,看到版本号后记住第一个数字。然后到ChromeDriver对应的发布页面下载相同大版本的驱动包,把解压出的chromedriver.exe放到一个固定目录,比如C:\SeleniumBasic\。
SeleniumBasic默认会在几个常见位置自动找驱动,但为了稳妥,我会在创建浏览器对象后立刻用属性指定驱动路径:
Dim driver As New SeleniumBasic.ChromeDriver ' 显式指定驱动所在目录 ' driver.DriverPath = "C:\SeleniumBasic\chromedriver.exe" ' 视版本而定 driver.Get "https://demo.example.com"如果你在启动时碰到“unknown error: cannot find Chrome binary”这类提示,除了驱动路径问题,还要检查Chrome的安装路径是不是非标准位置。SeleniumBasic里可以通过添加--binary启动参数,把chrome.exe的完整路径告诉驱动。
2.3 去掉那条“Chrome正受到自动软件控制”的提示条
新版Chrome在被WebDriver控制时,页面顶部通常出现一条黄色提示,说“Chrome正受到自动软件控制”。这行提示本身不影响运行,但会影响页面布局和截图,让人误以为是页面出了问题。
SeleniumBasic里处理它的方式是通过Profile对象添加启动参数:
Dim driver As New SeleniumBasic.ChromeDriver driver.Profile.AddArgument "--disable-infobars"不过说实话,新版Chrome上这个参数经常不生效。我当时实测下来,最有效的方案是保证每次自动化启动前没有其他手工打开的Chrome窗口占着同一个用户数据目录。多个Chrome实例用同一个Profile容易导致控制信号错乱,也会让提示条反复出现。
3. 第一段自动化脚本:从打开网页到完成一次搜索
3.1 脚本全貌与逐步讲解
先看一个最小的完整脚本,它的流程是:启动浏览器、打开页面、输入关键词、点击搜索、等两秒、输出页面标题、关闭浏览器。
Public Sub Demo_AutoSearch() Dim driver As SeleniumBasic.ChromeDriver Set driver = New SeleniumBasic.ChromeDriver ' 打开一个目标页面 driver.Get "https://demo.example.com/" ' 定位输入框,输入关键词 driver.FindElementById("searchKeyword").SendKeys "SeleniumBasic" ' 定位搜索按钮,模拟点击 driver.FindElementById("searchBtn").Click ' 简单等待页面刷新,用于演示 Application.Wait Now + TimeValue("00:00:02") ' 打印当前页面标题 Debug.Print driver.Title ' 关闭浏览器并释放对象 driver.Quit Set driver = Nothing End Sub这里有个常见的困惑:Set driver = New SeleniumBasic.ChromeDriver执行完,浏览器到底启动了没?在SeleniumBasic中,创建对象的同时就已经拉起一个浏览器窗口了,不需要再调用额外的Start方法。如果创建对象时驱动没找到,会直接报错,这也是检验驱动配置是否正确的快捷方式。
另外提醒一点:自动化脚本跑完一定要调用Quit。只写Set driver = Nothing并不会把浏览器的进程关掉,chrome.exe和chromedriver.exe会继续留在后台。如果是在循环里反复创建driver,内存会被慢慢吃干净,机器越来越卡。
3.2 找不到元素时,先扒开发工具看一下真实结构
新手写完脚本第一跑,最常见的报错就是NoSuchElementException。这时候别急着怀疑SeleniumBasic,先用浏览器自带的开发者工具确认:按F12打开DevTools,切到Elements面板,搜索目标元素的id或class名,确认它确实存在,而且你写的选择器在页面里是唯一的。
比如你写了FindElementById("searchKeyword"),但实际页面中这个元素的id可能叫kw_search,或者这个页面里同时存在多个同名id,那必然出问题。我习惯在写脚本前先用document.querySelector验证一下选择器:
' 验证某个CSS选择器能否唯一命中 Debug.Print driver.ExecuteScript("return typeof document.querySelector('#searchKeyword') !== 'undefined'")如果这个方法返回false,说明选择器写错了,应该回到Elements面板重新拷真实属性。
4. 八大定位器:选对元素才能真正点得动
4.1 一张表看懂所有定位方式
SeleniumBasic支持的定位方式,跟原生Selenium基本一致,下面这张表就是日常最常用的定位方法:
| 定位方式 | SeleniumBasic方法名 | 典型场景 |
|---|---|---|
| ID | FindElementById | 页面唯一元素,优先级最高 |
| Name | FindElementByName | 表单字段,但可能重复 |
| Class名 | FindElementByClassName | CSS类名定位,取第一个匹配 |
| 标签名 | FindElementByTag | 大量同类标签时配合下标使用 |
| 链接全文 | FindElementByLinkText | 精确匹配a标签的可见文本 |
| 链接部分文本 | FindElementByPartialLinkText | 模糊匹配a标签文本 |
| XPath | FindElementByXPath | 最强最灵活,但也最容易写错 |
| CSS选择器 | FindElementByCss | 现代页面首选,性能好 |
4.2 最常用的定位原则:优先ID,动态页面靠XPath
我自己的优先级非常简单:第一个看id,第二个看CSS选择器,实在没有稳定属性才上XPath。id定位速度快、语义清楚,只要目标系统不搞前后端分离那种动态id攻击,基本不会出问题。
动态页面就麻烦很多,比如页面里的id被框架自动渲染成row_1598436214731_5这种带时间戳的字符串,根本没法直接写。这时候XPath的价值就出来了。举个例子:我想点表格第三行的“详情”按钮,可以用相对位置:
//tbody/tr[3]/td[last()]/a再比如,页面上有一个按钮的文本是“确认”,但它的class在不断变化,那可以用:
//button[contains(text(),'确认')]文本匹配是XPath的杀手级能力之一,CSS选择器至今都没有一个干净的“按可见文本匹配”语法。所以碰到按钮文字经常变的情况,别硬用CSS,XPath会是更合适的选择。
4.3 Stale Element问题:页面刷新后元素引用“过期”了
定位一次拿到元素对象后,如果页面发生了局部刷新,你手里的元素引用很可能就“过期”了。再对它执行Click或SendKeys,就会报StaleElementReferenceException。这个错在AJAX场景和Vue、React这类框架下出镜率极高。
解决办法是不要反复使用旧的WebElement变量,每次操作前重新从driver里拿一次:
Dim btn As SeleniumBasic.WebElement Set btn = driver.FindElementByCss("button#btnSubmit") ' 这里页面刷新了…… Set btn = driver.FindElementByCss("button#btnSubmit") ' 重新获取引用 btn.Click这种“重新获取”写成习惯之后,代码的容错率会高出一大截。别省这一行,省了这一行,你能排查半小时。
5. 多窗口、iframe、下拉框和文件上传:高频场景一次讲透
5.1 打开新窗口后,怎么把焦点切过去
登录第三方平台、弹出结果页、下载报表,这些操作经常会打开新标签页或新窗口。SeleniumBasic里,driver.WindowHandles就是当前所有窗口句柄的集合,切换焦点时取最后一个句柄通常就是刚弹出的那个:
Dim handles As Object Set handles = driver.WindowHandles ' 取最后一个窗口句柄,切过去 driver.SwitchToWindow handles(handles.Count - 1)切换完成之后别急着找元素,新窗口里的内容可能需要加载一会儿。稳妥的做法是先加一个轮询等待,等新窗口的标题变成预期值,再往下走:
Dim i As Long For i = 1 To 30 If driver.Title Like "*结果*" Then Exit For Application.Wait (Now + TimeValue("00:00:01")) Next这个过程拜访的是“等待的目标是结果页标题”,而不是“我要找的元素”,因为标题往往是新页面加载完成的标志之一。
5.2 iframe陷阱:明明有元素,就是找不到
页面里嵌着另一个页面的情况太常见了。框架内的元素在DOM树里并不是顶层节点,直接用driver.FindElementById去查,标准答案就是NoSuchElementException。
SeleniumBasic应对iframe的方法是先把上下文切进去:
' 切换到指定name的iframe driver.SwitchToFrame "iframeName" ' 在iframe内部定位元素 driver.FindElementById("innerField").SendKeys "hello" ' 操作完切回主文档 driver.SwitchToDefault这里最容易踩的坑是:切进iframe之后忘记切回来。结果下一个步骤又在找主文档里的元素,报错之后你还以为元素不存在。记住一个原则:切进iframe操作完,马上切回默认,不要让上下文“漂”在框架里。
如果你不知道iframe的name,也可以用索引,但有name或者id的情况下请优先使用,因为页面结构一变,索引很可能就废了。
5.3 下拉框选择:原生Select和自绘控件是两回事
原生HTML的select下拉框,最简单的操作方式就是定位到你想选的option,然后Click:
driver.FindElementByCss("option[value='option_2']").Click但有一些自研框架,比如用了div配合ul列出选项的那种下拉,它根本不是标准select。这时候直接定位option是找不到的,你要模拟真人操作:先点击下拉框展开列表,再点击列表里的目标项。代码上是两个步骤:
' 点击下拉框展开 driver.FindElementById("comboBox").Click ' 点击展开后的具体选项 driver.FindElementByXPath("//ul[@id='comboList']/li[contains(text(),'目标项')]").Click如果页面里面的select做过事件绑定,直接给value赋值而不触发change事件,页面的内部状态不会同步,后续表单提交就会出问题。我那时常用的补救办法是用JavaScript让它自己触发事件:
driver.ExecuteScript "arguments[0].value = 'option_2'; arguments[0].dispatchEvent(new Event('change'));", driver.FindElementById("selectId")5.4 文件上传的稳妥姿势:给input[type=file]直接SendKeys
几乎每次教学现场,都有人认为文件上传要走“模拟点击-弹出Windows对话框-输入文件路径-确认”这条路。这个方向会让你耗费大量精力去调用系统级API,而实际上WebDriver对文件上传有一套特别讨巧的标准办法:直接把本地文件路径发给文件输入框。
driver.FindElementByCss("input[type=file]").SendKeys "D:\test\report.xlsx"这样做的原因是浏览器出于安全考虑,并不会在页面上回填你选择的文件路径,但自动化控件可以通过SendKeys把路径写进input的value里。实测下来,这是最稳的上传方式,我几乎不再处理系统弹出的文件选择窗口。
6. 稳定性技术细节:等待、超时与异常捕获
6.1 隐式等待设置为多少合适
SeleniumBasic默认情况下,查找元素是“找不到就立刻返回错误”。但真实页面不可能瞬间全部加载完,所以一上来就设置隐式等待几乎是必选操作:
driver.Timeouts.ImplicitWait = 5设置成5的意思是,每次FindElement找不到元素时,驱动会轮询等待最多5秒才抛异常。这个数字不宜太大,超过10秒会让脚本的错误反馈变得迟钝:页面确实挂了,你还要等10秒才收到错误,排障效率直线下降。
但隐式等待解决的只是“元素从无到有的过程”。它应对不了网络请求完成后数据才填充到DOM、组件异步渲染又晚了一步这类刁钻情况。那些场景要靠更主动的显式等待。
6.2 显式等待:轮询循环是VBA里最顺手的方案
VBA没有Thread.Sleep那种原生休眠方法,等待页面状态最常用的手段就是轮询加Application.Wait。比如页面有个loading遮罩,要等它消失:
Dim i As Long For i = 1 To 30 If driver.FindElementsByCss(".loading").Count = 0 Then Exit For Application.Wait (Now + TimeValue("00:00:01")) Next i这个循环最多等30秒,每秒检查一次。如果loading消失,立刻退出循环继续往下走。如果用FindElements而不是FindElement,好处是找不到元素时不会抛异常,而是返回一个空集合,配合Count = 0可以非常安全地完成判断。
还有一个更务实的判断:等待某个按钮变成可用状态。
Dim btn As SeleniumBasic.WebElement Do While i < 20 Set btn = driver.FindElementById("btnNext") If btn.Enabled Then Exit Do Application.Wait (Now + TimeValue("00:00:01")) i = i + 1 Loop btn.Click这个写法比固定Sleep两秒更符合真实页面节奏。固定Sleep的问题是,网络快的时候浪费时间,网络慢的时候等不到,只有轮询加条件判断才能两头兼顾。
6.3 现代前端框架下的常见坑:动态ID、懒加载、悬浮菜单
React、Vue这类框架给自动化带来两个头疼点:一是DOM节点可能被复用导致属性变化,二是懒加载导致页面滚到底才把数据渲染出来。
第一个问题的解法是尽量找稳定的自定义属性,很多开发团队会留>driver.FindElementByCss("[data-testid='submitButton']")
第二个问题需要在等待策略里加入“滚动触发加载”这个动作:当FindElements找不到某个元素时,先执行JavaScript滚动到底部再查一次:
driver.ExecuteScript "window.scrollTo(0, document.body.scrollHeight)" Application.Wait (Now + TimeValue("00:00:01")) Set elements = driver.FindElementsByCss(".item-card")悬浮菜单则是另一个经典难题。有些下拉菜单要鼠标悬停到导航项上才会展开,直接用Click可能没反应。我的建议是优先用JavaScript模拟mouseover事件,而不是去花时间精调Actions的鼠标移动坐标:
Set menuItem = driver.FindElementByXPath("//ul[@id='navMenu']/li[1]") driver.ExecuteScript "arguments[0].dispatchEvent(new MouseEvent('mouseover', {bubbles:true}));", menuItem Application.Wait (Now + TimeValue("00:00:01")) driver.FindElementByLinkText("子菜单项").Click7. 把SeleniumBasic和Excel打通的黄金组合:一个脚本解决一天的重复劳动
7.1 从网页表格抓数据回工作表的经典写法
这是一个非常典型的场景:页面上有一张几十行的表格,需要把它完整搬到Excel,而且这个动作每天要重复做。如果人工复制粘贴,十几分钟起步,写个脚本几秒搞定。
核心技巧有两个:一是定位表格行用CSS选择器聚焦tbody tr,二是在Excel侧用数组批量写入而不是逐格赋值。
Public Sub ScrapeTableToSheet() Dim ws As Worksheet Set ws = ThisWorkbook.Worksheets("Sheet1") Dim driver As New SeleniumBasic.ChromeDriver driver.Get "https://demo.example.com/table" Dim rows As SeleniumBasic.WebElements Set rows = driver.FindElementsByCss("table tbody tr") Dim buffer() As String ReDim buffer(1 To rows.Count, 1 To 30) Dim r As Long, c As Long Dim rowElems As SeleniumBasic.WebElements For r = 1 To rows.Count Set rowElems = rows(r).FindElementsByCss("td, th") For c = 1 To rowElems.Count buffer(r, c) = rowElems(c).Text Next c Next r ws.Range("A1").Resize(rows.Count, 30).Value = buffer driver.Quit End Sub这里重点解释一下为什么用buffer数组。Excel单元格逐格赋值在数据量小的时候没什么感知,但几百行、上千行的时候,你会发现状态栏的“计算”反复转圈,直到怀疑人生。把数据先装进二维数组,再用Resize(...).Value = buffer一次性写入,速度至少提升一个数量级,这是我做过多次批量抓取后最深刻的一个优化结论。
7.2 让Excel反过来当脚本控制台
换一个方向:Excel的A列里有一批关键词,你想让自动化去搜索每个关键词,并把搜索结果数量填回到B列。这就是典型的“Excel参数驱动自动化流程”。
一个完整的思路是:读Excel单元格拿到关键词,填写到搜索框,点击搜索,等待结果出现,读取数字写回B列:
Dim ws As Worksheet Set ws = ThisWorkbook.Worksheets("Sheet1") Dim driver As New SeleniumBasic.ChromeDriver driver.Get "https://demo.example.com/search" Dim i As Long Dim keyword As String, resultText As String For i = 1 To 10 keyword = ws.Cells(i, 1).Value If Len(keyword) = 0 Then Exit For driver.FindElementById("searchKeyword").Clear driver.FindElementById("searchKeyword").SendKeys keyword driver.FindElementById("searchBtn").Click ' 等待结果出现,最多15秒 Dim j As Long For j = 1 To 15 If driver.FindElementsByCss("div.resultCount").Count > 0 Then Exit For Application.Wait (Now + TimeValue("00:00:01")) Next j resultText = driver.FindElementByCss("div.resultCount").Text ws.Cells(i, 2).Value = resultText Next i driver.Quit这种循环场景里有一个特别值得养的坏习惯,就是不要每次都重新创建driver。启动浏览器本身是一件非常重的事,一个driver跑完整个列表,胜在稳定和快。另外,每次输入新关键词之前必须Clear,否则旧文本会和新的拼在一起,搜索出来的结果自然就不对。
如果你想进一步加速,可以在循环开始前关掉Excel的自动重算和屏幕刷新:
Application.ScreenUpdating = False Application.Calculation = xlCalculationManual ' 循环结束再恢复 Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True8. 性能优化与常见坑:一次把经验交代清楚
8.1 浏览器进程残留问题必须从机制上解决
脚本运行中途报错,后面的Quit被跳过,chromedriver.exe和chrome.exe就会一直躺在后台。下次再启动自动化,经常报端口被占用或SessionNotCreated异常,这其实并不是SeleniumBasic自己的bug,而是上一轮的残缺进程在那里捣乱。
因此我在所有主流程脚本里都会加一个统一的清理函数,放在On Error保护下执行:
Public Sub CleanupDriver(driver As SeleniumBasic.ChromeDriver) On Error Resume Next If Not driver Is Nothing Then driver.Quit Set driver = Nothing End If On Error GoTo 0 End Sub更彻底的习惯是:在脚本开头就把“清理”步骤写好,哪怕前面已经报错,也务必执行清理。真到卡死没法动弹的时候,再去任务管理器里把chromedriver.exe相关的进程全部结束,注意别把日常正常使用的Chrome窗口也一并杀掉。
8.2 常见报错速查表:看到报错先翻表
| 报错信息 | 常见原因 | 解决动作 |
|---|---|---|
| unknown error: cannot find Chrome binary | Chrome安装路径非标准,或驱动找不到浏览器 | 通过启动参数指定chrome.exe路径 |
| SessionNotCreatedException: This version of ChromeDriver only supports Chrome 版本 | 驱动和浏览器版本不匹配 | 下载与浏览器大版本一致的ChromeDriver |
| NoSuchElementException | 元素不存在、在iframe里、未加载出来、定位器写错 | 用F12检查元素结构,按第4章和第5.2节排查 |
| ElementClickInterceptedException | 有其他元素遮挡目标,比如弹窗遮罩 | 先等待遮挡元素消失,或用JavaScript强制点击 |
| JS execution failed | ExecuteScript传入的参数类型不被支持 | 对象参数使用arguments[0]传引用,不要把VBA对象直接塞进JS字符串 |
对于被覆盖遮挡但确定存在的情况,JavaScript强制点击是绕开遮罩的快捷方案:
Dim elem As SeleniumBasic.WebElement Set elem = driver.FindElementById("targetBtn") driver.ExecuteScript "arguments[0].click();", elem这招要谨慎用,因为它跳过了浏览器的点击事件拦截,有可能触发不了某些元素的真实事件处理。能用人工点击解决的就别用它,它是兜底,不是常规方案。
8.3 批量任务的性能优化实录
跑批量任务时,最容易拖慢速度的不是元素定位,而是不必要的等待和不合理的浏览器操作。我这边实际总结出四条经验:
第一,能用URL参数跳转的就不要反复点击页面。比如翻页操作,有时候找到下一页按钮的URL规律,直接driver.Get下一个地址,比每次定位按钮再点击快得多。
第二,批量抓取时考虑用无头模式。SeleniumBasic里通过添加启动参数--headless可以让浏览器不弹出界面,省下不少渲染资源的开销。但要注意,部分站点检测到无头模式会返回异常数据,这时候要果断切回有头模式。
第三,统一浏览器窗口尺寸。窗口大小变化会影响响应式布局,进而导致元素位置和可见性改变。固定一下viewport尺寸,至少在批量任务运行期间,不会出现莫名其妙的定位失败。
第四,URL里带中文或特殊符号时,要用编码处理。直接在代码里拼中文网址,常常会被浏览器解析成乱码。用ExecuteScript调用JavaScript的编码函数是眼下最省事的方案:
Dim keyword As String keyword = "自动化测试" Dim encoded As String encoded = driver.ExecuteScript("return encodeURIComponent(arguments[0]);", keyword)这个返回值可以直接拼接到地址栏参数里,稳定不翻车。
8.4 中文乱码和输入残留:两个看似不大却很磨人的问题
先聊中文乱码。用SeleniumBasic抓取页面里的中文文本时,在VBA的立即窗口里Debug.Print经常显示成乱码,但这往往只是调试窗口的编码显示问题。直接把取到的字符串写进Excel单元格,通常又恢复正常了,见过太多人卡在这一步,以为抓取的数据废了,又是修系统语言又是换字体,其实只要写进单元格里看看就知道结果对不对。
再看输入残留。有些前端自研输入框,Clear方法清不掉内部的React状态,清了半天旧文本还在。这种情况最朴素的解法是用Ctrl+A全选再覆盖输入:
Dim inputBox As SeleniumBasic.WebElement Set inputBox = driver.FindElementById("searchKeyword") inputBox.SendKeys "^a" ' Ctrl+A 全选 inputBox.SendKeys "新的关键词" ' 直接覆盖这招看着土,实测下来对付各种自研组件效果极佳。
最后再分享一个实用技巧:Cookie复用能让你少登录十几次
很多项目里的自动化任务需要登录之后才能操作。如果每次启动浏览器都要从头走一遍登录流程,不仅慢,而且容易触发账号异常的登录提醒。我的做法是:先把登录流程手动编排成一次自动化脚本,在登录成功后把Cookie保存下来,后续脚本启动后直接写回浏览器,跳过整个登录环节。
SeleniumBasic里Cookie的存取并不复杂,思路是遍历driver.Cookies集合,把键值对序列化到一个本地文本或者Excel单元格里;下次启动时读取回来,再通过driver.Cookies.Add逐一加回去。执行顺序上要注意,先让浏览器打开目标域名,再添加Cookie才会生效。
最后再讲一个贯穿始终的习惯:每个脚本第一行就用On Error Resume Next兜住清理逻辑,每个脚本收尾一定是driver.Quit。这两个小习惯,真真实实帮我省掉了无数回去任务管理器杀进程的时间。希望这篇基于SeleniumBasic的实操指南,能帮你在VBA里真正掌控浏览器自动化,把那些每天重复的网页操作,一步步变成一键搞定的小工具。