Excel VBA 调用 Google Places API 返回“#NAME?”
结论
#NAME? 不是 Google Places API 返回的状态,而是 Excel 无法识别工作表中使用的函数名。这个错误通常出现在请求发送之前,与 200 米范围内有没有公园无关。
这段代码主要需要修正两个地方:
- API key 必须用双引号括起来,以字符串形式赋值。
GetNearbyPark必须放在 Excel VBA 的“标准模块”中,同时确保宏已启用。
如果查询的位置在美国俄勒冈州波特兰附近,经度很可能是 -122.6628821,而不是 122.6628821。
正确设置 API key
下面的写法不正确:
apiKey = MyAPIKey
如果把 MyAPIKey 直接替换为实际密钥,却没有加双引号,VBA 会将它视为变量名或表达式。启用 Option Explicit 后,这通常会引发编译错误。
应将 API key 写成字符串:
apiKey = "AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
不要通过工作表传递或显示 API key,也不要公开包含真实密钥的工作簿。
确保 Excel 能识别自定义函数
代码应放在标准模块中,不能放在 Sheet1、ThisWorkbook 或其他工作表对象的代码窗口里:
- 按
Alt + F11打开 VBA 编辑器。 - 选择“插入”→“模块”。
- 将完整的
Public Function GetNearbyPark...粘贴到该模块。 - 将工作簿保存为支持宏的
.xlsm格式。 - 重新打开工作簿并启用宏。
- 在 VBA 编辑器中选择“调试”→“编译 VBAProject”,检查并排除编译错误。
然后在工作表单元格中输入:
=GetNearbyPark(45.5662453,-122.6628821,200)
部分地区的 Excel 使用分号分隔参数,此时应写成:
=GetNearbyPark(45.5662453;-122.6628821;200)
如果仍然出现 #NAME?,说明 Excel 还没有加载这个 VBA 函数。需要继续检查代码所在的模块、宏安全设置、工作簿格式,以及 VBA 工程中是否存在编译错误。
坐标中的经度符号
代码使用的坐标顺序没有问题:
location=latitude,longitude
对应的参数是:
location=45.5662453,-122.6628821
但题目给出的经度是正数:
122.6628821
经度的正负号会指向完全不同的位置。查询波特兰附近时,应检查经度是否漏写了负号:
longitude = -122.6628821
即使经度写错,通常也会收到 API 状态或无结果响应,不会导致 Excel 显示 #NAME?。因此,需要分别处理经度错误和函数无法识别的问题。
建议修改后的函数
下面的版本修正了 API key 的字符串写法,并加入 HTTP、XML 和空节点检查,避免 API 返回异常内容时直接报错:
Option Explicit
Public Function GetNearbyPark( _
ByVal latitude As Double, _
ByVal longitude As Double, _
ByVal radius As Long) As String
Dim apiKey As String
Dim requestUrl As String
Dim xmlhttpRequest As Object
Dim xmlDoc As Object
Dim xmlStatusNode As Object
Dim xmlNearbyParkNameNode As Object
Dim apiStatus As String
On Error GoTo errorHandler
apiKey = "YOUR_API_KEY"
If apiKey = vbNullString Or apiKey = "YOUR_API_KEY" Then
GetNearbyPark = "Empty or invalid API Key"
Exit Function
End If
requestUrl = _
"https://maps.googleapis.com/maps/api/place/nearbysearch/xml?" & _
"location=" & Replace(CStr(latitude), ",", ".") & "," & _
Replace(CStr(longitude), ",", ".") & _
"&radius=" & CStr(radius) & _
"&type=park" & _
"&key=" & apiKey
Set xmlhttpRequest = CreateObject("MSXML2.ServerXMLHTTP.6.0")
xmlhttpRequest.Open "GET", requestUrl, False
xmlhttpRequest.send
If xmlhttpRequest.Status <> 200 Then
GetNearbyPark = "HTTP error: " & CStr(xmlhttpRequest.Status)
GoTo cleanUp
End If
Set xmlDoc = CreateObject("MSXML2.DOMDocument.6.0")
xmlDoc.async = False
If Not xmlDoc.LoadXML(xmlhttpRequest.responseText) Then
GetNearbyPark = "Invalid XML response"
GoTo cleanUp
End If
Set xmlStatusNode = xmlDoc.SelectSingleNode( _
"/PlaceSearchResponse/status")
If xmlStatusNode Is Nothing Then
GetNearbyPark = "API response does not contain a status"
GoTo cleanUp
End If
apiStatus = UCase$(xmlStatusNode.Text)
Select Case apiStatus
Case "OK"
Set xmlNearbyParkNameNode = xmlDoc.SelectSingleNode( _
"/PlaceSearchResponse/result[1]/name")
If xmlNearbyParkNameNode Is Nothing Then
GetNearbyPark = "No park name was returned"
Else
GetNearbyPark = xmlNearbyParkNameNode.Text
End If
Case "ZERO_RESULTS"
GetNearbyPark = _
"No park exists within the radius of the defined coordinates"
Case "OVER_DAILY_LIMIT"
GetNearbyPark = "Billing, payment, or API key problem"
Case "OVER_QUERY_LIMIT"
GetNearbyPark = "Quota limit exceeded"
Case "REQUEST_DENIED"
GetNearbyPark = "Server denied the request"
Case "INVALID_REQUEST"
GetNearbyPark = "Request was empty or malformed"
Case "UNKNOWN_ERROR"
GetNearbyPark = "Unknown API error"
Case Else
GetNearbyPark = "API status: " & apiStatus
End Select
cleanUp:
Set xmlNearbyParkNameNode = Nothing
Set xmlStatusNode = Nothing
Set xmlDoc = Nothing
Set xmlhttpRequest = Nothing
Exit Function
errorHandler:
GetNearbyPark = "VBA error " & CStr(Err.Number) & ": " & Err.Description
Resume cleanUp
End Function
Replace(CStr(...), ",", ".") 可以避免某些区域设置将小数格式化为逗号,从而造成 URL 中的坐标无效。
还需要检查的 API 配置
Excel 能够正确识别函数后,如果返回 REQUEST_DENIED、配额错误或计费错误,再检查以下项目:
- Google Cloud 项目是否启用了相应的 Places API。
- 项目是否满足当前的结算要求。
- API key 的应用限制和 API 限制是否允许这项请求。
- API key 是否完整,前后是否带有多余空格。
- 坐标是否正确,尤其是经度的正负号。
原代码中的 sensor=False 是旧式参数,建议删除。它不会引发 #NAME?,但现代请求通常不再需要这个参数。
备注:内容仅供参考。
