PAYATHON 2026

Excel VBA 调用 Google Places API 返回“#NAME?”

支付阿杰

结论

#NAME? 不是 Google Places API 返回的状态,而是 Excel 无法识别工作表中使用的函数名。这个错误通常出现在请求发送之前,与 200 米范围内有没有公园无关。

这段代码主要需要修正两个地方:

  1. API key 必须用双引号括起来,以字符串形式赋值。
  2. GetNearbyPark 必须放在 Excel VBA 的“标准模块”中,同时确保宏已启用。

如果查询的位置在美国俄勒冈州波特兰附近,经度很可能是 -122.6628821,而不是 122.6628821。

正确设置 API key

下面的写法不正确:

apiKey = MyAPIKey

如果把 MyAPIKey 直接替换为实际密钥,却没有加双引号,VBA 会将它视为变量名或表达式。启用 Option Explicit 后,这通常会引发编译错误。

应将 API key 写成字符串:

apiKey = "AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

不要通过工作表传递或显示 API key,也不要公开包含真实密钥的工作簿。

确保 Excel 能识别自定义函数

代码应放在标准模块中,不能放在 Sheet1、ThisWorkbook 或其他工作表对象的代码窗口里:

  1. 按 Alt + F11 打开 VBA 编辑器。
  2. 选择“插入”→“模块”。
  3. 将完整的 Public Function GetNearbyPark... 粘贴到该模块。
  4. 将工作簿保存为支持宏的 .xlsm 格式。
  5. 重新打开工作簿并启用宏。
  6. 在 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?,但现代请求通常不再需要这个参数。

备注:内容仅供参考。