如何通过Excel控制已打开页面并优化Selenium的SKU查询效率?
问题解答
问题1:如何通过Excel控制已打开的网页?
控制已打开的网页有两种实用方案,可根据你的技术栈选择:
方案1:基于Selenium复用已打开的浏览器实例
如果已经在用Selenium(比如你问题2的场景),可通过调试端口复用已有会话:
- 手动启动浏览器并开启调试模式,例如Edge的启动命令:
msedge.exe --remote-debugging-port=9222 - 在Excel VBA中连接到已打开的浏览器:
Dim bot As New WebDriver bot.SetCapability "edgeOptions", {"debuggerAddress": "127.0.0.1:9222"} bot.Start "edge" ' 连接到已打开的浏览器,而非新建窗口 - 之后即可用
bot对象操作目标页面,比如获取元素、执行JS等。
方案2:VBA结合IE对象(仅适用于IE浏览器)
针对IE浏览器,可通过ShellWindows直接获取已打开的窗口:
Dim ie As Object For Each ie In CreateObject("Shell.Application").Windows If InStr(ie.FullName, "iexplore.exe") > 0 Then ' 匹配目标网页URL If ie.LocationURL = "目标网页地址" Then ' 执行页面操作,例如输入文本 ie.Document.getElementById("输入框ID").Value = "内容" Exit For End If End If Next ie
问题2:复用已打开页面批量处理SKU的优化方案
你当前的核心问题是每次处理SKU都重复启动浏览器、登录网站,这是耗时的主要原因。通过拆分代码逻辑,复用同一个浏览器实例,可大幅提升效率。
优化步骤:
- 拆分初始化与登录逻辑,单独完成浏览器启动和网站登录,返回已登录的WebDriver对象。
- 修改SKU查询函数,让它接收已有的WebDriver实例,不再每次新建。
- 替换固定等待为显式等待,减少不必要的等待时间。
优化后的代码示例:
1. 初始化浏览器并登录的过程
Private Function InitAndLogin() As WebDriver Dim bot As New WebDriver Dim userID As String Dim userPword As String Dim keys As New Selenium.keys bot.Start "edge" bot.Get "https://app.shiphero.com/dashboard/product-locations?warehouses=7145&customer=4222" userID = Application.InputBox("Enter User ID") userPword = Application.InputBox("Enter your Password") bot.FindElementByName("email", 1000).SendKeys userID bot.FindElementByName("password", 1000).SendKeys userPword bot.FindElementByName("password", 100).SendKeys keys.Enter ' 等待登录完成,可替换为等待登录后出现的特定元素 bot.Wait 5000 Set InitAndLogin = bot End Function
2. 修改后的SKU查询函数(复用WebDriver)
Private Function GetProductLocation(bot As WebDriver, SKU As String, QtyOrdered As Integer) As clsLineItem Dim elem As WebElement Dim keys As New Selenium.keys Dim table As Selenium.WebElement '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' 搜索SKU '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' bot.FindElementByXPath("//*[@id='search_exact_match_product_locations']").Click ' 清空搜索框,避免残留内容干扰新SKU查询 bot.FindElementByXPath("//*[@id='product_locations_filter']/label/input[1]").Clear bot.FindElementByXPath("//*[@id='product_locations_filter']/label/input[1]").SendKeys SKU bot.FindElementByXPath("//*[@id='product_locations_filter']/label/input[1]").SendKeys keys.Enter ' 等待搜索结果加载 bot.Wait 3000 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' 解析库存表格 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Set table = bot.FindElementById("product_locations") Dim AllRows As Selenium.WebElements Dim SingleRow As Selenium.WebElement Dim AllRowCells As Selenium.WebElements Dim SingleCell As Selenium.WebElement Dim RowNum As Long Dim ColNum As Long Dim LocationIsValid As Boolean Dim Enough As Boolean Dim Expired As Boolean Dim productLocation As clsProductLocation Dim lineItem As clsLineItem Set AllRows = table.FindElementsByTag("tr") Set productLocation = New clsProductLocation Set lineItem = New clsLineItem RowNum = 0 For Each SingleRow In AllRows LocationIsValid = False Enough = False Expired = True RowNum = RowNum + 1 Set AllRowCells = SingleRow.FindElementsByTag("td") If AllRowCells.Count = 0 Then Set AllRowCells = SingleRow.FindElementsByTag("th") End If ColNum = 0 For Each SingleCell In AllRowCells ColNum = ColNum + 1 Select Case ColNum Case 5 ' 位置列 If ValidLocation(SingleCell.Text) Then LocationIsValid = True productLocation.Location = SingleCell.Text End If Case 9 ' 可用数量列 If LocationIsValid Then If CSng(SingleCell.TextAsNumber) >= QtyOrdered Then productLocation.QtyAvailable = SingleCell.TextAsNumber Enough = True End If End If Case 12 ' Lot ID列 If LocationIsValid Then productLocation.LotCode = SingleCell.Text End If Case 15 ' 剩余有效期列 If LocationIsValid Then If CSng(SingleCell.TextAsNumber) >= 285 Then productLocation.DaysUntilExpired = SingleCell.TextAsNumber Expired = False Else Expired = True End If End If End Select If LocationIsValid And Enough And Not Expired Then lineItem.LocationID = productLocation.Location lineItem.QtyAvailable = IIf(productLocation.QtyAvailable > 0, productLocation.QtyAvailable, 0) lineItem.LotID = productLocation.LotCode Set GetProductLocation = lineItem Exit Function End If Next SingleCell Next SingleRow If Enough Then lineItem.LocationID = "OOS-EXP" Else lineItem.LocationID = "OOS" End If Set GetProductLocation = lineItem End Function
3. 批量处理SKU的主过程
Sub BatchProcessSKUs() Dim bot As WebDriver Dim skuList As Variant Dim i As Integer Dim qtyOrdered As Integer Dim result As clsLineItem ' 初始化浏览器并完成登录 Set bot = InitAndLogin() ' 假设SKU列表在Sheet1的A列(A2到A21),对应订单数量在B列 skuList = Sheet1.Range("A2:A21").Value For i = 1 To UBound(skuList) qtyOrdered = Sheet1.Range("B" & i + 1).Value Set result = GetProductLocation(bot, skuList(i, 1), qtyOrdered) ' 将结果写入Sheet1的C、D、E列 Sheet1.Range("C" & i + 1).Value = result.LocationID Sheet1.Range("D" & i + 1).Value = result.QtyAvailable Sheet1.Range("E" & i + 1).Value = result.LotID Next i ' 处理完成后关闭浏览器(可选) bot.Quit Set bot = Nothing End Sub
额外优化建议:
- 将所有固定
bot.Wait替换为显式等待,例如bot.FindElementById("目标元素ID", 10000),元素加载完成后立即执行操作,减少无效等待。 - 检查
ValidLocation函数的执行效率,避免它成为性能瓶颈。 - 如果网站提供开放API,直接调用API获取数据的效率远高于模拟浏览器操作,可优先考虑这种方式。
内容的提问来源于stack exchange,提问作者rwebb
相关产品推荐
相关产品推荐

