如何在VBA中指定国家来计算两个城市之间的距离?

How to calculate the distance between two cities by specifying the country in VBA?

我有一个 VBA 脚本,可以让我计算两个城市之间的距离(以公里为单位)。

此脚本基于站点:http://www.distance2villes.com/

它工作得很好而且很快,因为我有 Excel 个包含数千个城市的文件,因此每次都要计算距离。

问题是有时我的城市名称相同但位于不同的欧洲国家/地区。如下例所示:Brest 它在白俄罗斯找到,而不是在法国找到城市。

Starting city   City of destination Distance Country
Soorts-Hossegor ST PIERRE QUIBERON  668     FR
Soorts-Hossegor ST AUSTELL          1198    GB
Soorts-Hossegor KIEL                1724    DE
Soorts-Hossegor BREST               2612    FR
Soorts-Hossegor WIEN                1850    AT
Soorts-Hossegor CHAMONIX MONT BLANC 948     FR
Soorts-Hossegor CORNWALL            1169    GB
Soorts-Hossegor CORNWALL            1169    GB
Soorts-Hossegor BREST               2612    FR
Soorts-Hossegor ROME                1556    IT
Soorts-Hossegor BOURNEMOUTH         960     GB
Soorts-Hossegor CORNWALL            1169    GB
Soorts-Hossegor ROTTENBURG AM NECKAR 1201   DE
Soorts-Hossegor LA CROIX VALMER      795    FR

在城市多的情况下,能不能指定搜索国家的名称,避免混淆?还是有另一种更快的方法来计算 Excel 中两个城市之间的距离?

Option Explicit

Sub Distance()
    
    Const DIST1 As String = "http://www.distance2villes.com/recherche?source="
    Const DIST2 As String = "&destination="
    Const DIST3 As String = "distanciaRuta"
    Const wsName As String = "Feuil1"
    
    'Dim w As Object: Set w = CreateObject("WINHTTP.WinHTTPRequest.5.1")
    Dim w As Object: Set w = CreateObject("MSXML2.XMLHTTP")
    Dim h As Object: Set h = CreateObject("htmlfile")
    
    Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets(wsName)
    Dim rg As Range
    Set rg = ws.Range("A2", ws.Cells(ws.Rows.Count, "A").End(xlUp).Offset(, 1))
    Dim Data As Variant: Data = rg.Value
    
    Dim isFound As Boolean: isFound = True
    Dim i As Long
    Dim Url As String
    Dim S As String
    
    For i = 1 To UBound(Data, 1)
        If Len(Data(i, 1)) > 0 And Len(Data(i, 2)) > 0 Then
            Url = DIST1 & Data(i, 1) & DIST2 & Data(i, 2)
            w.Open "GET", Url, False
            w.Send
            h.body.innerHTML = w.responseText
            On Error GoTo NotFoundError
            S = h.getElementById(DIST3).innerText
            On Error GoTo 0
            If isFound Then
                Data(i, 1) = Replace(Left(S, Len(S) - 3), ",", "")
            Else
                Data(i, 1) = ""
                isFound = True
            End If
        Else
            Data(i, 1) = ""
        End If
    Next
    rg.Columns(1).Offset(, 2).Value = Data
    
    Exit Sub

NotFoundError:
    isFound = False
    Resume Next

End Sub

是否可以指定国家名称?

是的。

方法一:用Excel

实现此目的的一种方法是在第 5 列中包含城市和国家/地区的组合。

例如: 在单元格 E2 中,输入 =B2&" "&D2 然后向下填充,以使用城市名称和国家/地区代码的组合填充新的第 5 列,中间有一个 space 字符。 (然后您需要编辑您的代码,以便例程使用这个新输出作为查找基础)。

方法二:用VBA

另一种方法是像现在这样从 Excel 中拉出 VBA 中的城市和国家/地区并将其连接到一个查找字符串中,而不是像现在这样先将其连接到 Excel 中以上建议。

例如,您可以尝试替换为:

Url = DIST1 & Data(i, 1) & DIST2 & Data(i, 2)

有了这个:

Url = DIST1 & Data(i, 1) & DIST2 & Data(i, 2) & " " & Data(i, 4)

但是,您可能需要将串联 space 编码为 %20:

Url = DIST1 & Data(i, 1) & DIST2 & Data(i, 2) & "%20" & Data(i, 4)

或者用连字符代替 (-):

Url = DIST1 & Data(i, 1) & DIST2 & Data(i, 2) & "-" & Data(i, 4)

就我个人而言,我会先尝试 %20 的那个。请注意,其中 none 个已经过测试。

无论如何你还需要替​​换这个:

Set rg = ws.Range("A2", ws.Cells(ws.Rows.Count, "A").End(xlUp).Offset(, 1))

有了这个:

Set rg = ws.Range("A2", ws.Cells(ws.Rows.Count, "A").End(xlUp).Offset(, 3))

...还有。

还有其他更快的方法吗?

不确定它是否会更快,但是 Excel 现在可以通过使用地理数据类型在没有 VBA 的情况下本地执行此操作。此解决方案可能需要最新的软件版本。您可能更愿意坚持使用您开发的解决方案,因为您提到它可以工作并且速度足够快。如果有兴趣,您可以在 https://techcommunity.microsoft.com/t5/excel/lambda-examples-distance-between-two-cities/m-p/1952946 查看使用新功能的示例。此示例使用新的 LAMBDA 函数定义计算,但您现在可以忽略此步骤,只需输入示例中显示的完整计算即可。

如果您有权访问所有数据,您可以使用 =CityRange & '-' & CountryCodeRange 等单元格公式创建一个新列,其中 CityRange、CountryCodeRange 是单元格范围,即 $A$2、$C$2。

因此,当您查询某些地点时,您应该将它们称为 CityName & '-' & CountryCode,例如:BREST-FR 而不是 BREST。

但是如果您从网络下载数据,您应该检查您下载的每个页面的两个参数以选择您想要的值。

我看到你的代码有一些下载部分。