【问题标题】:Extract data from a web page that may not be formatted as a table从可能未格式化为表格的网页中提取数据
【发布时间】:2016-05-14 04:15:39
【问题描述】:

对于初学者来说,我绝不是 VBA 专家。只要知道足够危险 8)。

我开始搜索如何从网页中提取表格,发现很多人都问过同样的问题。不幸的是,我读到的大部分内容都超出了我的想象。我读到的一篇文章将我指向了 Siddharth Rout 的 detailed article,但是除了 Internet Explorer 或其他一些方法之外,我无法理解正在发生的事情。因为我只安装了 IE11 和 MS Office,所以我更愿意走 IE 路线。

我过去曾多次遇到此问题,并且总是放弃项目或手动完成。今天我想我会尝试学习如何做到这一点,并希望让我未来的生活更轻松一些。因此,我将使用来自游戏网站的数据,因为它模仿了我过去遇到的其他事情。

所以今天的(本周..不,本月..我是一个乐观主义者!)项目是建立一个参加锦标赛的每支球队的名单,并将他们的结果复制到 Excel 中。这类似于拉板球、曲棍球、棒球、足球或足球数据。我尝试使用 Excel 内置的从 Web 获取数据流程,但它无法识别网页上的表格。

网页地址为:http://worldoftanks.com/en/tournaments/1000000017/

在下图中

所以基础知识和我的出发点是简单地从 1 个组中提取团队列表并将其粘贴到没有格式的 Excel 页面中。基本上是上图中的黄色区域。图片无法放满整个页面,但该组实际上有 10 个团队。但是我想让它变得可变,因为有时你可能在一个小组中拥有多于或少于 10 个团队。在这一点上,我将假设行数是一个小问题。

一旦我弄清楚了那部分,我希望切换到下一个组会相对容易,获取团队和结果的列表并将它们添加到我在 excel 中构建的列表的末尾。在网页上,这将通过选择蓝色区域来完成。

现在,一旦我弄清楚了这两件事,我需要根据绿色锦标赛区域的阶段从头开始重新构建列表,并将该列表放在新页面上。我对如何实现这一点有一些想法,但这实际上取决于前两个步骤的样子。

我自己也有一个额外的任务,那就是拉出小组中每个团队的时间表,看看他们在与其他不同团队的比赛中表现如何。谁打败了谁类型的交易。我希望我能根据从上述任务中学到的信息弄清楚那部分。

所以我很确定还有其他语言/prgs 更适合手头的任务,但我想坚持我所拥有的......以及到目前为止我所知道的很少。所以我尝试了一些 VBA 代码并评论了我需要实现的目标。到目前为止,我想我已经打开了网页!并在 cmets 中构建了一些关于如何做一些事情的思考过程。

Sub GetTeamData()
Dim IE As Object
Dim roundcounter As Integer
Dim groupcounter As Integer
Dim TeamList As Variant
Dim WebAddress As String
Dim Number_of_rounds as Integer
Dim Number_of_Groups as Integer

'set webaddress of site to link to
WebAddress = "http://worldoftanks.com/en/tournaments/1000000017/"

Set IE = CreateObject("InternetExplorer.Application")

With IE
    .Visible = True
    .navigate (WebAddress)
End With

'What does this chunk of code do?  Wait for webpage to finish loading?
While IE.readyState <> 4
    DoEvents
Wend

'set initial parameters for loops.  I am ok with hardcoding this for now.
Number_of_groups = 125
Number_of_rounds = 5

'start pulling teamdata

'For roundcounter = 1 To number_of_rounds
    'select roundcounter on webpage
    'for groupcounter = 1 to number_of_groups
        'select groupcounter on webpage
        'grab table of 6-10 teams (position, team name, battles, wins, losses, ties, and points)
        'add table to TeamList
    'next groupcounter
    'paste TeamList to sheet roundcounter cell A1
    'clear TeamList
'next roundcounter


'Next task
'based on results on how to pull group table date, pull individual team schedule results to build matrix result

Set IE = Nothing

End Sub

我正在考虑的一件事是,与其使用带有计数器的 for next 循环,不如将其设置为执行循环,直到发生错误(例如超过组数或轮数)会更容易。现在我在闲逛。

无论如何,如果有人能让我开始了解如何从上面的图片中拉出黄色区域,那将不胜感激!请温柔一点!我确实意识到这个问题已经被问过很多次了......我只是不明白我在读什么。另外,如果这不可能或很难做到,请告诉我。提前感谢您在教育我方面的帮助。

更新 16/03/19 0900

所以今天早上我再次尝试了从 Web 获取数据过程,运气好一点……但并不多。

在出现 1 个错误窗口后,我单击“是”以加载网页

我在页面的左上角出现了一次黄色小箭头。所以我试了一下,它确实提取了信息。

但我确实注意到我想要的桌子旁边没有黄色框,这让我怀疑它是否不是桌子。

当我确实提取信息时,这不是我正在寻找的信息。当我扫描结果时,我可以看到我要查找的数据应该在哪里,但是所有结果都丢失了,只有表格列标题出现在大约 263 行左右。

然后我尝试从网页上执行复制和粘贴方法,使用全选作为网页上的副本。对于粘贴,我尝试了不同的方法。保持源格式没有任何结果。保持目的地格式引入信息。我尝试粘贴特殊(html、Unicode 和文本)HTML 使事情看起来很漂亮,另外两个将所有内容放在一个列中。更重要的是,结果在表格中。

现在,如果我只需要第 1 轮第 1 组的团队列表和结果,我可以使用它。只需删除表格上方和下方的所有行,瞧!然而,由于每个组和每一轮的网址都是相同的,我不知道如何“点击”蓝色或绿色区域来更新信息。如果我知道这一点,我可以通过复制和粘贴每一页来自动化该过程,然后将结果编辑到表格中,然后将表格移动到最后结果下方的另一张表中。

对我来说似乎应该有更好的方法。

16/03/19 1600

<!-- ko if: visibleBracketType() === ROUND_ROBIN -->
<table class="tournament-table tournament-table__indent" cellpadding="0" cellspacing="0">
  <tr class="tournament-table_tr">
    <th class="tournament-table_th tournament-table_th__numb">#</th>
    <th class="tournament-table_th">
      <div class="tournament-table_ico-holder">
        <span class="ico-team">Team</span>
      </div>
      <div class="tournament-table_heading-text">
        Team
      </div>
    </th>
    <th class="tournament-table_th">
      <div class="tournament-table_ico-holder">
        <span class="ico-battles">Battles</span>
      </div>
      <div class="tournament-table_heading-text">
        Battles
      </div>
    </th>
    <th class="tournament-table_th">
      <div class="tournament-table_ico-holder">
        <span class="ico-victory">Victories</span>
      </div>
      <div class="tournament-table_heading-text">
        Victories
      </div>
    </th>
    <th class="tournament-table_th tournament-table_th__mobile-hide">
      <div class="tournament-table_ico-holder">
        <span class="ico-flag">Defeats</span>
      </div>
      <div class="tournament-table_heading-text">
        Defeats
      </div>
    </th>
    <th class="tournament-table_th tournament-table_th__mobile-hide">
      <div class="tournament-table_ico-holder">
        <span class="ico-division">Draws</span>
      </div>
      <div class="tournament-table_heading-text">
        Draws
      </div>
    </th>
    <th class="tournament-table_th">
      <div class="tournament-table_ico-holder">
        <span class="ico-points">Points</span>
      </div>
      <div class="tournament-table_heading-text">
        Points
      </div>
    </th>
  </tr>
  <!-- ko foreach: {data: rrBrackets().teams, as: 'team' } -->
  <tr class="tournament-table_tr" data-bind="css: {'tournament-table_tr__my-team': team.team_id === $root.currentUserTeamIdInCurrentGroup()}">
    <td class="tournament-table_td" data-bind="text: team.position"></td>
    <td class="tournament-table_td" data-bind="css: {'tournament-table_td__my-team': team.team_id === $root.currentUserTeamIdInCurrentGroup()}">
      <a class="tournament-table_team tournament-table_team__big" target="_blank" data-bind="text: team.team_title, attr: {href: $root.getTournamentTeamUrl(team.team_id)}"></a>
    </td>
    <td class="tournament-table_td" data-bind="text: team.battle_played"></td>
    <td class="tournament-table_td" data-bind="text: team.wins"></td>
    <td class="tournament-table_td tournament-table_td__mobile-hide" data-bind="text: team.losses"></td>
    <td class="tournament-table_td tournament-table_td__mobile-hide" data-bind="text: team.draws"></td>
    <td class="tournament-table_td" data-bind="text: team.extra_statistics.points"></td>
  </tr>
  <!-- /ko -->
</table>​

好的,根据我从阅读的各种帖子和观看的视频中收集到的信息,我需要在网页编码中找到一些关键的“标签”,然后我最终可以开始提取数据.我在 IE 上按 F12 以查看代码,然后在代码区域中搜索了我正在查找的区域中的一些显示文本,并找到了上面的“代码”块。有了很多猜测,我希望我抓住了正确的部分。现在要弄清楚那个关键标签是什么以及如何使用它。顺便问一下,那个网页是什么代码?

【问题讨论】:

  • 我也尝试按照example查看网页的源代码,但我无法对源代码进行正面或反面。
  • 在您包含的代码 sn-p 中,它仍然是 HTML:&lt;tr&gt;&lt;\tr&gt; 用于表行,&lt;th&gt;&lt;\th&gt; 用于表头,&lt;td&gt;&lt;\td&gt; 用于表数据/列。问题将是提取实际数据,因为它们是绑定的,您只能“读取”HTML 源代码。如果可以从页面的“查看源代码”中看到实际数据,则可以使用VBA读取数据。
  • 谢谢罗文。这将有助于缩小我对使用 excel VBA 8 抓取 HTML 页面的数据的搜索范围。现在只有几千页要读!不过说真的,谢谢你,因为当我把标签放在 HTML 上时我才猜到它。
  • 所以我不确定,如果我理解正确,但缺少的部分是单击正确的按钮?
  • 不,我的代码正下方的粗线部分。如果我分解我想做的事情,这是主要关注点。这是从第一个屏幕截图中拉出黄色区域(数字和名称)。一旦我可以在人们的帮助下弄清楚该部分,次要部分将是单击以更改数据显示,以便我可以重复黄色区域的数据提取。如果我无法提取数据,那么点击就没有意义。这有助于澄清吗?

标签: html vba excel


【解决方案1】:

虽然可以使用 VBA 自动从网页中提取数据(见下文),但您提供的具体示例网页存在一些障碍:

此网页一次仅加载和显示一小部分所需数据。这可能是出于性能原因,因为整个 Teams 表将包含数千个条目。 仅加载当前显示的回合和当前显示的组的团队。 如果您单击另一个组,则会启动一个 JavaScript 程序(在您的浏览器中运行)连接到服务器,获取该组的团队并替换网页中的数据。如果您按 F12 并观察列出对服务器的所有请求的“网络”选项卡,您可以自己验证这一点。

因此,该网页在任何时候都不会提供完整的团队列表。你必须解决这个问题:

  1. 让您的程序自动点击每一轮,然后点击每个组,最后提取该组的 9 个团队,然后将所有内容合并在一起。
  2. 挂钩加载每个组的团队的 JavaScript 代码并在循环中调用它,或者对该代码发出的请求进行反向工程并尝试在 VBA 中重新创建它们。尽管这可能是一个优雅的解决方案,但许多网站所有者不喜欢以他们不希望的方式使用他们的 API。 滥用可能会造成巨大的服务器负载。如果 API 是为此目的而设计的,我只会推荐这种方法(某些网站会这样做,例如 Twitter 或 Steam)。

下面将只关注从给定页面中提取内容,即检索当前加载的 Group 的 Teams。我不会使用上面提到的任何解决方法。

程序基本上由这三个部分组成:

打开网页

以下是打开网页并返回包含网页内容的对象的辅助函数。 它需要引用的库 Microsoft Internet ControlsMicrosoft HTML 对象库 (see here for instructions)。

' return the document containg the DOM of the page strWebAddress
' returns Nothing if the timeout lngTimeoutInSeconds was reached
Public Function GetIEDocument(ByVal strWebAddress As String, Optional ByVal lngTimeoutInSeconds As Long = 15) As MSHTML.HTMLDocument
    Dim IE As SHDocVw.InternetExplorer
    Dim IEDocument As MSHTML.HTMLDocument
    Dim dateNow As Date

    ' create an IE application, representing a tab
    Set IE = New SHDocVw.InternetExplorer

    ' optionally make the application visible, though it will work perfectly fine in the background otherwise
    IE.Visible = True

    ' open a webpage in the tab represented by IE and wait until the main request successfully finished
    ' times out after lngTimeoutInSeconds with a warning
    IE.Navigate strWebAddress
    dateNow = Now
    Do While IE.Busy
        If Now > DateAdd("s", lngTimeoutInSeconds, dateNow) Then Exit Function
    Loop

    ' retrieve the webpage's content (that is, the HTML DOM) and wait until everything is loaded (images, etc.)
    ' times out after lngTimeoutInSeconds with a warning
    Set IEDocument = IE.Document
    dateNow = Now
    Do While IEDocument.ReadyState <> "complete"
        If Now > DateAdd("s", lngTimeoutInSeconds, dateNow) Then Exit Function
    Loop

    Set GetIEDocument = IEDocument
End Function

提取信息

您现在可以使用Set IEDocument = GetIEDocument("http://worldoftanks.com/en/tournaments/1000000017/") 加载网页。然后对象IEDocument 包含提取所需数据所需的一切。

首先,您需要找到要提取的部分(关键的“标签”,正如您所说的那样)。 由于网页内容表示为 HTML 标签树,因此您需要找到包含您感兴趣的所有其他标签的表格标签。您已经在 16/03/19 1600 em>更新。 &lt;table&gt; 标签包含两个&lt;tr&gt; 标签(table row),第一个是用&lt;th&gt; 标签填充的标题行(table header) 表示单个列的标题。 第二行是一个虚拟行,代表一个团队的条目。

前面的行&lt;!-- ko foreach: {data: rrBrackets().teams, as: 'team' } --&gt;Knockout Framwork 的一部分,Knockout Framwork 是网站使用的一个 JavaScript 库,用于用内容动态填充裸 HTML 标记。这就是为什么 HTML 源代码中只有一行,但在呈现的页面中您看到九行的原因: 加载页面后,JavaScript 代码循环遍历团队列表并为每个团队创建一个新行,填充他们各自的数据。

然而,这并不需要我们关心:IEDocument 包含 HTML DOM 的最终版本,在所有加载完成后(另见底部的编辑)。第一行实际上是这样的(按 F12 并亲自查看 DOM Explorer 选项卡):

<tr class="tournament-table_tr" data-bind="css: {'tournament-table_tr__my-team': team.team_id === $root.currentUserTeamIdInCurrentGroup()}">
    <td class="tournament-table_td" data-bind="text: team.position">1</td>
    <td class="tournament-table_td" data-bind="css: {'tournament-table_td__my-team': team.team_id === $root.currentUserTeamIdInCurrentGroup()}">
        <a class="tournament-table_team tournament-table_team__big" href="/en/tournaments/1000000017/team/1000006728/" target="_blank" data-bind="text: team.team_title, attr: {href: $root.getTournamentTeamUrl(team.team_id)}">Pubbies</a>
    </td>
    <td class="tournament-table_td" data-bind="text: team.battle_played">8</td>
    <td class="tournament-table_td" data-bind="text: team.wins">7</td>
    <td class="tournament-table_td tournament-table_td__mobile-hide" data-bind="text: team.losses">1</td>
    <td class="tournament-table_td tournament-table_td__mobile-hide" data-bind="text: team.draws">0</td>
    <td class="tournament-table_td" data-bind="text: team.extra_statistics.points">21</td>
</tr>

然而,首先以编程方式查找标记有点复杂。通常结构上重要的标签具有唯一的id 属性。在这种情况下,我们可以简单地使用IEDocument.getElementById("id_of_table_tag") 找到它。 在这种情况下,我们最好的选择可能是搜索标题锦标赛括号

<div class="wrapper">
    <h2 class="tournament-heading">Tournament brackets</h2>
</div>

如果您检查以下 HTML 标签树,要到达我们的 &lt;table&gt; 标签,我们需要在层次结构中上一层,跳过接下来的两个标签,然后从那里开始,将第一个子标签用于下一个两个标签:

' retrieve anchor element
For Each objH2 In IEDocument.getElementsByTagName("h2")
    If objH2.innerText = "Tournament brackets" Then Exit For
Next objH2

' traverse HTML tree to desired table element
' * move up one element in the hierarchy
' * skip two elements to proceed to the third (interjected each time with whitespace that is interpreted as an element of its own)
' * move down two elements n the hierarchy
' this may fail if the JavaScript code has not already populated the table
Set objTable = objH2.parentElement _
                    .nextSibling.nextSibling _
                    .nextSibling.nextSibling _
                    .nextSibling.nextSibling _
                    .children(0) _
                    .children(0)

你可以想象,这不是很健壮,如果网页的布局发生变化,必然会随时中断。还有其他可能的方法可以遍历 HTML 标签树以最终到达您寻找的标签。 请参阅documentation of the Document object 了解更多信息。

我们现在需要做的就是循环遍历objTableRows 并输出它的每个Cells

输出到 Excel

至于输出,在这个例子中,我们尽量保持简单。 结合上面的代码,下面的代码只是将表格输出到Excel中的当前工作表中:

Public Sub GetTeamData()
    Dim strWebAddress As String
    Dim strH2AnchorContent As String
    Dim IEDocument As MSHTML.HTMLDocument
    Dim objH2 As MSHTML.HTMLHeaderElement
    Dim objTable As MSHTML.HTMLTable
    Dim objRow As MSHTML.HTMLTableRow
    Dim objCell As MSHTML.HTMLTableCell
    Dim lngRow As Long
    Dim lngColumn As Long

    ' initialize some variables that should probably better be passed as paramaters or defined as constants
    strWebAddress = "http://worldoftanks.com/en/tournaments/1000000017/"
    strH2AnchorContent = "Tournament brackets"

    ' open page
    Set IEDocument = GetIEDocument(strWebAddress)
    If IEDocument Is Nothing Then
        MsgBox "Timeout reached opening this address:" & vbNewLine & strWebAddress, vbCritical
        Exit Sub
    End If

    ' retrieve anchor element
    For Each objH2 In IEDocument.getElementsByTagName("h2")
        If objH2.innerText = strH2AnchorContent Then Exit For
    Next objH2
    If objH2 Is Nothing Then
        MsgBox "Could not find """ & strH2AnchorContent & """ in DOM!", vbCritical
        Exit Sub
    End If

    ' traverse HTML tree to desired table element
    ' * move up one element in the hierarchy
    ' * skip two elements to proceed to the third (interjected each time with whitespace that is interpreted as an element of its own)
    ' * move down two elements n the hierarchy
    Set objTable = objH2.parentElement _
                        .nextSibling.nextSibling _
                        .nextSibling.nextSibling _
                        .nextSibling.nextSibling _
                        .children(0) _
                        .children(0)

    ' iterate over the table and output its contents
    lngRow = 1
    For Each objRow In objTable.rows
        lngColumn = 1
        For Each objCell In objRow.cells
            Cells(lngRow, lngColumn) = objCell.innerText
            lngColumn = lngColumn + 1
        Next objCell
        lngRow = lngRow + 1
    Next
End Sub

虽然这只是您当前问题的部分解决方案,但它为如何使用 VBA 以编程方式从网站提取数据提供了通用解决方案。 正如您所说,您经常会遇到此类问题,但是这可能对您有所帮助。


编辑

  1. 在他的回答中,Doktor OSwaldo 正确地将对象声明为它们的本来面目 - 与我之前的版本相比,所有内容都是 Object 类型。我不知道Microsoft HTML 对象库。谢谢@Doktor OSwaldo。 :) 我在上面的代码中加入了该库的使用。
  2. 您应该知道,在设置objTable 的那一刻,该元素可能还不存在于DOM 中,因为JavaScript 尚未完全填充所有数据。您可以围绕此语句循环检查objTable 是否确实已成功设置: On Error Resume Next Do Err.Clear Set objTable = ... Loop While Err On Error GoTo 0 您可能应该包含一个超时选项,如函数GetIEDocument() 中所示。最好将所有这些移到一个单独的函数中,该函数还可以单击“回合”和“分组”按钮,如 Doktor OSwaldo 的回答中所示。
  3. 您可能已经注意到,标题列输出两次。这实际上是正确的,因为图标显示在标题文本之前的方式。 您可以使用objCell.tagName = "TH" And objCell.children.length = 2 来识别这一点,在这种情况下,您应该使用objCell.children(1).innerText 而不是objCell.innerText 来输出到Excel。

【讨论】:

  • 我还在读这个。您在格式化和解释事情发生的原因方面做得非常出色。
  • 我不认为我自己会得到你代码的 Set objTable 部分。输出到电子表格我可以做但获取数据的命令。有趣的是,当您在单行中调用这棵树时,您是如何遍历树的。这对我来说是明确的基石。
  • 真的很干净,很好的解决方案,但我认为如果不在 IE 中打开页面就无法单击按钮
【解决方案2】:

所以如果写了一个小子,我认为如果我理解正确的话应该可以解决你的问题。当然你会投入一些工作,因为它现在只读取一个阶段。但它会从每个组中读取数据:

Option Explicit

Private Sub CommandButton1_Click()

'make sure you add references to Microsoft Internet Controls (shdocvw.dll) and
 'Microsoft HTML object Library.
 'Code will NOT run otherwise.

Dim objIE As SHDocVw.InternetExplorer 'microsoft internet controls (shdocvw.dll)
Dim htmlDoc As MSHTML.HTMLDocument 'Microsoft HTML Object Library
Dim htmlInput As MSHTML.HTMLInputElement
Dim htmlColl As MSHTML.IHTMLElementCollection

Set objIE = New SHDocVw.InternetExplorer

Dim htmlCurrentDoc As MSHTML.HTMLDocument 'Microsoft HTML Object Library

Dim RowNumber As Integer
            RowNumber = 1

With objIE
    .Navigate "http://worldoftanks.com/en/tournaments/1000000017/" ' Main page
    .Visible = 0
    Do While .READYSTATE <> 4: DoEvents: Loop
        Application.Wait (Now + TimeValue("0:00:01"))


        Set htmlDoc = .document

        Dim ButtonRoundData As Variant
        Set ButtonRoundData = htmlDoc.getElementsByClassName("group-stage_link")

        Dim ButtonData As Variant
        Set ButtonData = htmlDoc.getElementsByClassName("groups_link")



        Dim button As HTMLLinkElement
        For Each button In ButtonData

           Debug.Print button.nodeName

            button.Click

               Application.Wait (Now + TimeValue("0:00:02")) ' This is to prevent double entryies but it is not clean. you should definitly check if the table is still the same and wait then

            Set htmlCurrentDoc = .document
            Dim RawData As HTMLTable
            Set RawData = htmlCurrentDoc.getElementsByClassName("tournament-table tournament-table__indent")(0)



            Dim ColumnNumber As Integer
            ColumnNumber = 1

            Dim hRow As HTMLTableRow
            Dim hCell As HTMLTableCell
            For Each hRow In RawData.Rows

                For Each hCell In hRow.Cells
                    Cells(RowNumber, ColumnNumber).Value = hCell.innerText
                    ColumnNumber = ColumnNumber + 1
                Next hCell
                ColumnNumber = 1
                RowNumber = RowNumber + 1
            Next hRow

            RowNumber = RowNumber + 3
        Next button
    End With

End Sub

它的作用是启动一个不可见的 IE,读取数据,点击按钮,读取下一个等等......

对于调试,我建议将 .Visible 设置为 1,以便您了解会发生什么。

编辑 1:如果您遇到调试错误,请尝试中止并再次运行它,如果网站未正确加载,它肯定需要一些错误处理。

编辑 2: 让它更稳定一点,你真的应该注意,因为网页需要一些时间来加载,你必须在写入之前检查数据是否发生了变化。如果没有改变,请稍等片刻,然后重试。

这是我在 Excel 中获得的一些示例数据:

【讨论】:

  • 让我通读一遍并测试一下。如果它可以拉黄色区域WOOT!那是我战斗的 90%。我想如果我可以了解您是如何为组点击的,那么我应该轻松地为阶段重复该过程。
  • 是的,你应该可以做到,实际上代码并不难,我会用 debug.print 日志更新我的数据
  • 所以我正在阅读您的代码,当我看到您在 cmets 中添加了我需要添加一些库时并没有走多远。 I posted this question 在我开始这个项目后不久,我想知道它是否会成为一个问题。
  • 我想我绝对可以使用您所展示的内容。作为结果。有点难看,但如果你为我做这一切,它会破坏我学习这项任务的所有乐趣! 8)仍在阅读代码并找出添加库的问题。这绝对是一个单独的问题。
  • ooh cheesus 我希望不是,可以在顶部菜单中选择其他库。 Extras->如果这不起作用,我认为是英文参考,请尝试在信任中心激活对 vba-projectmodell 的允许访问
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多