VBA代码如下:Sub GetUrlData()
Dim sURL As String, sCode As String, oRegExp As Object, nPage As Long, nPages As Long, nRecords As Long, sResponseText As String
Dim vData As Variant, nI As Long, nJ As Long, oReg As Object, vFill As Variant, nRow As Double, nCol As Long, ws As Worksheet
' 关闭屏幕更新和警告,提高代码执行效率
Application.ScreenUpdating = False
Application.DisplayAlerts = False
' 设置引用到【基金净值】工作表
Set ws = ThisWorkbook.Worksheets("基金净值")
' 获取A1单元格的值,并转换为字符串
sCode = CStr(ws.Range("A1").Value)
' 使用字符串函数Left和String来确保sCode是6位数字
' 如果不足6位,则在前面补0
sCode = String(6 - Len(sCode), "0") & sCode
' 创建正则表达式对象,用于字符串匹配
Set oRegExp = CreateObject("VBSCRIPT.REGEXP")
' 设置正则表达式为全局匹配模式
oRegExp.Global = True
' 清空工作表中的所有单元格内容
Cells.Clear
' 初始化页面计数器
nPage = 1
' 构建基金数据API的URL,其中[Page]是页码占位符
sURL = "http://fund.eastmoney.com/f10/F10DataApi.aspx?type=lsjz&code=" & sCode & "&page=[Page]&per=2000"
' 创建XMLHTTP对象,用于发送网络请求
With CreateObject("msXML2.ServerXMLHttp")
' 循环直到所有页面都被请求和处理
Do While nPage = 1 Or nPage <= nPages
' 发送GET请求,替换URL中的[Page]为当前页码
.Open "GET", Replace(sURL, "[Page]", nPage), True
' 发送请求
.Send
' 等待请求完成
While .ReadyState <> 4
DoEvents
Wend
' 获取响应文本
sResponseText = .ResponseText
' 使用正则表达式解析响应文本
With oRegExp
' 如果还未获取总记录数和总页数,则先进行匹配
If nPages = 0 Then
' 设置正则表达式模式,匹配记录数和页数
.Pattern = "records[^\d]+(\d+)[^\d]+pages[^\d]+(\d+)"
' 执行匹配
Set oReg = .Execute(sResponseText)
' 如果匹配到结果,则提取记录数和页数
If oReg.Count > 0 Then
nRecords = Val(oReg(0).SubMatches(0))
nPages = Val(oReg(0).SubMatches(1))
End If
' 设置正则表达式模式,匹配表头
.Pattern = "<th([^>]+)?>([^<]+)<"
' 执行匹配
Set oReg = .Execute(sResponseText)
' 如果匹配到结果,则初始化数据数组
If oReg.Count > 0 Then
ReDim vFill(1 To nRecords + 1, 1 To oReg.Count + 1)
' 在数据数组的第1行第1列存储基金代码
vFill(1, 1) = sCode
' 遍历匹配到的表头,存储在数据数组的第1行
For nCol = 1 To oReg.Count
vFill(1, nCol + 1) = oReg(nCol - 1).SubMatches(1)
Next
End If
' 初始化列和行计数器
nCol = 8
nRow = 1
' 设置正则表达式模式,匹配表格数据
.Pattern = "<td([^>]+)?>([^<]+)?<"
End If
' 使用正则表达式匹配响应文本中的数据
Set oReg = .Execute(sResponseText)
' 如果匹配到数据
If oReg.Count > 0 Then
' 初始化循环计数器
nI = 0
' 循环遍历匹配到的数据
Do While nI + 1 < oReg.Count
' 获取当前匹配的数据
sCode = oReg(nI).SubMatches(1)
' 检查数据是否是日期格式(假设日期格式为"年-月-日")
If sCode Like "*-*-*" Then
' 如果是日期,则列计数器重置为2,表示日期列
nCol = 2
' 行计数器加1,准备写入下一行的数据
nRow = nRow + 1
' 在数据数组的第1列存储行号(假设第1列用于存储序号)
vFill(nRow, 1) = nRow - 1
Else
' 如果不是日期,则列计数器加1,准备写入下一列的数据
nCol = nCol + 1
End If
' 在数据数组中存储当前匹配的数据
vFill(nRow, nCol) = oReg(nI).SubMatches(1)
' 循环计数器加1
nI = nI + 1
Loop
End If
End With
' 页码计数器加1,准备请求下一页数据
nPage = nPage + 1
Loop
End With
' 将数据数组写入工作表的指定区域
With [A1].Resize(UBound(vFill), UBound(vFill, 2))
' 设置日期列的格式为"年-月-日"
.Offset(, 1).Resize(, 1).NumberFormatLocal = "yyyy-m-d"
' 设置数值列的格式为千分位分隔,保留4位小数
.Offset(, 2).Resize(, 2).NumberFormatLocal = "_ * #,##0.0000_ ;_ * -#,##0.0000_ ;_ * ""-""????_ ;_ @_ "
' 设置百分比列的格式为百分比,保留2位小数
.Offset(, 4).Resize(, 1).NumberFormatLocal = "0.00%"
' 将数据数组的内容写入工作表
.Formula = vFill
' 自动调整列宽以适应内容
.EntireColumn.AutoFit
' 设置水平对齐方式为居中
.HorizontalAlignment = xlCenter
' 设置垂直对齐方式为底部对齐
.VerticalAlignment = xlBottom
End With
' 重新开启屏幕更新和警告
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
|