Excel VBA运行时错误91无法解决:XML拉取天气数据脚本报错
解决VBA XML拉取天气数据时的运行时错误91(Object variable not set)
我来帮你排查这个问题——虽然你觉得wshape已经设置好了,但运行时错误91的根源其实不在它身上,而是出在XML节点获取失败上。这个错误本质是你尝试访问一个未初始化的对象引用,下面是几个最可能的触发点,以及对应的修复方案:
可能的错误原因
- XML响应加载失败:
resp.LoadXML req.responseText可能没成功加载XML(比如API密钥无效返回错误页面、网络问题导致响应异常),这会让resp.getElementsByTagName("weather")返回空集合,后续访问节点的Text属性自然会报错。 - 节点路径或命名空间问题:有些API返回的XML带有命名空间,直接用
getElementsByTagName或SelectNodes可能找不到目标节点;或者你写的节点名称和实际XML里的结构不一致(比如weatherIconUrl的层级不对,或者拼写错误)。 SelectNodes返回空集合:比如weather.SelectNodes("weatherIconUrl")没找到任何节点,这时Item(0)就是Nothing,访问它的.Text就会直接触发错误91。
修复后的代码(带错误检查)
我给你调整了代码,添加了请求状态验证、XML加载检查、节点存在性判断,还加了旧图标清理的逻辑,避免重复创建形状:
Option Explicit Private Sub btnRefresh_Click() Dim req As New MSXML2.XMLHTTP.6.0 ' 使用新版XMLHTTP提升兼容性 Dim resp As New MSXML2.DOMDocument60 Dim weather As IXMLDOMNode Dim ws As Worksheet: Set ws = ActiveSheet Dim wshape As Shape Dim thiscell As Range Dim i As Integer Dim weatherIconNode As IXMLDOMNode ' 先清理之前生成的天气图标,避免重复堆积 For Each wshape In ws.Shapes If Not Intersect(wshape.TopLeftCell, ws.Range("weatherPicture")) Is Nothing Then wshape.Delete End If Next wshape ' 发送同步请求(显式设置False确保请求完成再执行后续代码) req.Open "GET", "http://api.worldweatheronline.com/premium/v1/weather.ashx?key=myConfidentialToken&q=Baku&format=xml&num_of_days=5", False req.send ' 检查请求是否成功 If req.Status <> 200 Then MsgBox "请求失败,状态码:" & req.Status & vbCrLf & req.responseText Exit Sub End If ' 加载XML并检查是否成功 resp.async = False If Not resp.LoadXML(req.responseText) Then MsgBox "XML解析失败:" & resp.parseError.reason & vbCrLf & resp.parseError.srcText Exit Sub End If ' 遍历每个weather节点 For Each weather In resp.getElementsByTagName("weather") i = i + 1 ' 日期节点检查 If weather.SelectNodes("date").Length > 0 Then ws.Range("theDate").Cells(1, i).Value = weather.SelectNodes("date")(0).Text End If ' 最高温节点检查 If weather.SelectNodes("maxtempC").Length > 0 Then ws.Range("highTemps").Cells(1, i).Value = weather.SelectNodes("maxtempC")(0).Text End If ' 最低温节点检查 If weather.SelectNodes("mintempC").Length > 0 Then ws.Range("lowTemps").Cells(1, i).Value = weather.SelectNodes("mintempC")(0).Text End If ' 天气图标节点检查(这就是你之前报错的关键位置) Set weatherIconNode = weather.SelectNodes("weatherIconUrl").Item(0) If Not weatherIconNode Is Nothing Then Set thiscell = ws.Range("weatherPicture").Cells(1, i) Set wshape = ws.Shapes.AddShape(msoShapeRectangle, thiscell.Left, thiscell.Top, thiscell.Width, thiscell.Height) wshape.Fill.UserPicture weatherIconNode.Text End If Next weather End Sub
额外调试技巧
- 查看API返回的原始内容:在
req.send后添加Debug.Print req.responseText,然后打开VBA的立即窗口(Ctrl+G),就能看到实际返回的XML,确认节点名称和结构是否符合你的预期。 - 验证API密钥:如果密钥无效,API会返回错误信息,通过上面的
MsgBox就能看到具体错误。 - 命名空间处理:如果返回的XML带有命名空间(比如根节点有
xmlns="xxx"),你需要给DOMDocument设置命名空间前缀才能正确获取节点,比如:
之后用resp.SetProperty "SelectionNamespaces", "xmlns:ww='http://api.worldweatheronline.com/premium/v1'"weather.SelectNodes("ww:weatherIconUrl")来获取节点。
内容的提问来源于stack exchange,提问作者Elgin Cahangirov
相关产品推荐
相关产品推荐

