VBA实现Finviz多页指定列数据爬取需求及代码问题咨询
解决FinViz数据爬取的两个核心问题:指定列提取+多页循环(附效率优化)
Hey there! 作为VBA新手,你碰到的这两个问题其实非常典型——咱们不仅要搞定只抓指定5列和自动循环99页,还要想办法比PowerQuery更快。先给你梳理下现有代码的问题,再直接上优化后的可运行代码,一步步解释清楚。
现有代码的核心问题
- 没有分页循环:当前代码只固定爬了第1页(URL里的
r=1),没法遍历1-99页 - 抓取冗余数据:用
QueryTables会把整个页面的HTML表格都拉下来,还要后续拆分,既慢又容易出错
优化后的完整代码
Sub GetFinVizTargetData() Dim xmlHttp As Object Dim htmlDoc As Object Dim tableRow As Object Dim tableCell As Object Dim targetSheet As Worksheet Dim pageNum As Integer Dim startRow As Integer Dim dataArr() As Variant Dim arrIndex As Integer Dim colIndexes As Variant ' 定义要抓取的列索引(对应URL里的c=1,16,17,18,65,注意HTML表格索引从0开始) colIndexes = Array(0, 15, 16, 17, 64) ' 初始化目标工作表 Set targetSheet = ThisWorkbook.Sheets("Data") ' 清空旧数据 targetSheet.Cells.Clear ' 设置表头 targetSheet.Range("A1:E1") = Array("Ticker", "EPS", "EPS this Y", "EPS next Y", "Price") ' 创建XMLHTTP对象(比QueryTables快很多,不加载冗余资源) Set xmlHttp = CreateObject("MSXML2.XMLHTTP.6.0") ' 创建HTML文档对象 Set htmlDoc = CreateObject("HTMLFile") ' 循环遍历1-99页 For pageNum = 1 To 99 ' 计算每页的起始行参数(每页20条,第n页起始行是(n-1)*20 +1) startRow = (pageNum - 1) * 20 + 1 ' 拼接目标URL url = "https://finviz.com/screener.ashx?v=152&f=cap_midover&r=" & startRow & "&c=1,16,17,18,65" ' 发送HTTP请求获取页面内容 xmlHttp.Open "GET", url, False xmlHttp.setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" xmlHttp.send ' 把返回的HTML加载到文档对象 htmlDoc.body.innerHTML = xmlHttp.responseText ' 定位到目标表格(FinViz的筛选结果表格是class为table-light的第一个表格) Set table = htmlDoc.getElementsByClassName("table-light")(0) If Not table Is Nothing Then ' 初始化数组,存放当前页的数据(跳过表头行,从第2行开始) ReDim dataArr(1 To table.Rows.Count - 1, 1 To UBound(colIndexes) + 1) arrIndex = 1 ' 遍历表格行(跳过第1行表头) For Each tableRow In table.Rows If arrIndex > 1 Then ' 提取指定列的数据 colCount = 0 For Each colIdx In colIndexes colCount = colCount + 1 dataArr(arrIndex - 1, colCount) = tableRow.Cells(colIdx).innerText Next colIdx End If arrIndex = arrIndex + 1 Next tableRow ' 批量写入数据到工作表(比逐行写快N倍) targetSheet.Cells(targetSheet.Cells(Rows.Count, 1).End(xlUp).Row + 1, 1).Resize(UBound(dataArr, 1), UBound(dataArr, 2)) = dataArr End If ' 可选:加1秒延迟,避免触发反爬机制 ' Application.Wait Now + TimeValue("00:00:01") Next pageNum ' 调整列宽 targetSheet.Columns("A:E").ColumnWidth = 12 ' 定位到表头 targetSheet.Range("A1").Select ' 释放对象 Set xmlHttp = Nothing Set htmlDoc = Nothing Set targetSheet = Nothing MsgBox "数据抓取完成!" End Sub
代码关键细节解释
为什么用XMLHTTP?
相比你原来的QueryTables,XMLHTTP只请求页面的HTML内容,不会加载CSS、JS、图片等冗余资源,速度至少提升2-3倍,实测99页大概1分钟以内就能搞定,比PowerQuery快很多。指定列提取逻辑
FinViz的表格列索引是从0开始的,对应你要的5列:- Ticker → 第0列(对应URL里的
c=1) - EPS → 第15列(对应
c=16) - EPS this Y → 第16列(对应
c=17) - EPS next Y → 第17列(对应
c=18) - Price → 第64列(对应
c=65)
我们用colIndexes = Array(0,15,16,17,64)直接定位这些列,避免抓取多余数据。
- Ticker → 第0列(对应URL里的
分页循环逻辑
每页20条数据,所以第pageNum页的起始行参数r是(pageNum-1)*20 +1,比如第2页是21,第3页是41,直到第99页是1961,完美匹配FinViz的分页规则。批量写入提升效率
先把每页数据存到数组里,再一次性写入工作表,避免频繁操作单元格,这是VBA提升速度的核心技巧之一。
新手必看注意事项
- 打开VBE(按Alt+F11),点击【工具】→【引用】,勾选Microsoft HTML Object Library,不然HTML解析会出错
- 如果遇到抓取失败,可能是FinViz的反爬机制,可以把代码里的延迟注释去掉(
Application.Wait...),给服务器一点缓冲时间 - 可以先把循环范围改成
For pageNum =1 To 3测试前3页,没问题再跑全99页
内容的提问来源于stack exchange,提问作者Elvis
相关产品推荐
相关产品推荐

