无法让我的脚本继续点击使用IE加载更多按钮

问题描述 投票:5回答:2

我已经使用IE在vba中创建了一个脚本,以便继续点击位于网页底部的Load more hits按钮,直到没有剩下这样的按钮。

以下是我的脚本如何填充该按钮:在网站的登录页面中有一个名为Type的下拉列表。该脚本可以单击该Type展开dropdown然后点击选项中的一些corporate bond复选框。最后,它点击apply按钮来填充数据。但是,现在底部可以看到load more hits按钮。

我的脚本几乎可以遵循我上面描述的几乎所有步骤。我唯一要努力解决的问题是,在点击该按钮3/4次后,脚本似乎卡住了。

我怎样才能纠正我的脚本以继续点击那个Load more hits按钮,直到没有剩下这样的按钮?

Website link

我到目前为止尝试过:

Sub ExhaustLoadMore()
    Dim IE As New InternetExplorer, I As Long
    Dim Html As HTMLDocument, post As Object, elem As Object
    Dim CheckBox As Object, btnSelect As Object

    With IE
        .Visible = True
        .navigate "https://www.boerse-stuttgart.de/en/tools/product-search/bonds"
        While .Busy Or .readyState < 4: DoEvents: Wend
        Set Html = .document

        Do: Loop Until Html.querySelectorAll(".bsg-loader-ring__item").Length = 0

        Html.querySelector("#bsg-filters-btn-bgs-filter-3").Click
        Do: Set CheckBox = Html.querySelector("#bsg-checkbox-3053"): DoEvents: Loop While CheckBox Is Nothing
        CheckBox.Click

        Set btnSelect = Html.querySelector("#bsg-filters-menu-bgs-filter-3 .bsg-btn__label")
        Do: Loop While btnSelect.innerText = "Close"
        btnSelect.Click

        Do: Loop Until Html.querySelectorAll(".bsg-loader-ring__item").Length = 0
        Do: Set elem = Html.querySelector(".bsg-table__tr td"): DoEvents: Loop While elem Is Nothing

        Do
            Set post = Html.querySelector(".bsg-searchlist__load-more button.bsg-btn--juna")
            If Not post Is Nothing Then
                post.ScrollIntoView
                post.Click
                Application.Wait Now + TimeValue("00:00:05")
            Else: Exit Do
            End If
        Loop
    End With
End Sub

我试过用硒但这似乎慢了。但是,即使没有硬编码等待,它也会在长时间等待之后不断点击加载更多按钮。在硒的情况下:我希望有任何可能有助于减少执行时间的解决方案。

Sub ExhaustLoadMore()
    Const Url$ = "https://www.boerse-stuttgart.de/en/tools/product-search/bonds"
    Dim driver As New ChromeDriver, elem As Object, post As Object

    With driver
        .get Url
        Do: Loop Until .FindElementsByCss(".bsg-loader-ring__item").count = 0
        .FindElementByCss("#bsg-filters-btn-bgs-filter-3", timeOut:=10000).Click
        .FindElementByXPath("//label[contains(.,'Corporate Bond')]", timeOut:=10000).Click
        .FindElementByXPath("//*[@id='bsg-filters-menu-bgs-filter-3']//button", timeOut:=10000).Click
        Do: Loop Until .FindElementsByCss(".bsg-loader-ring__item").count = 0
        Set elem = .FindElementByCss(".bsg-table__tr td", timeOut:=10000)
        Do
            Set post = .FindElementByCss(".bsg-searchlist__load-more button.bsg-btn--juna", timeOut:=10000)
            If Not post Is Nothing Then
                post.ScrollIntoView
                .ExecuteScript "arguments[0].click();", post
                Do: Loop Until .FindElementsByCss("p.bsg-searchlist__info--load-more").count = 0
            Else: Exit Do
            End If
        Loop
        Stop
    End With
End Sub
vba web-scraping internet-explorer-11
2个回答
3
投票

我已经研究了一下你的网站,因为我不能把所有这些都说成一个评论我决定发布一个答案(即使它没有提供具体的解决方案,但只是一个“答案”,也许一些技巧)。

你的问题的答案

如何纠正我的脚本以继续点击“加载更多点击”按钮,直到没有剩下这样的按钮为止?

不幸的是,这不是你的错。您所定位的网站正在通过Web客户端(您的浏览器)和Web服务器之间的WebSocket通信进行处理,并提供您尝试抓取的价格。你可以看到如下:

enter image description here

想象一下这样:

  • 当您第一次加载您的网页时,Web套接字被初始化并发送第一个请求(Web客户端:“嘿服务器,给我第一个X结果”,Web服务器:“当然,这里你去”)。
  • 每次单击“加载更多结果”按钮时,Web客户端(重要:重新使用相同的WS连接)都会继续向Web服务器请求X新结果。

因此,沟通持续了一段时间。在某些时候,出于您的控制,Web套接字就会崩溃。只需单击“加载更多结果”按钮就可以查看JavaScript控制台:您将看到请求一直持续到某个时刻您不会看到引发的NullPointerException

enter image description here

如果在异常之前单击堆栈的最后一行,您将看到它是因为Web套接字:

enter image description here

错误说清楚:cannot read .send() on null,意思是_ws(网络套接字)消失了。

从现在开始,您可以忘记您的网站。当您单击“加载更多结果”按钮时,Web客户端将要求Web套接字将新请求传递给Web服务器,但Web套接字已经消失,因此两者之间的通信很好,所以(不幸的)再见了其余的数据。

您可以通过在堆栈中稍高一点来验证这一点:

enter image description here

如您所见,我们有:

  1. 在发布新数据请求之前,控制台中记录的消息“performSearch params ...”
  2. 新数据请求的post
  3. 在发布新数据请求之后,在控制台中记录的消息“使用结果执行搜索...”

当Web套接字仍处于活动状态时,每次单击“加载更多结果”时,您将在控制台中看到这两条消息(其间的其他消息打印在其余代码上):

enter image description here

但是,在Web套接字第一次崩溃后,无论您尝试单击按钮多少次,您只会收到第一条消息(Web客户端发送请求),但永远不会收到第二条消息(请求丢失了无效):

enter image description here

请注意,这与您在VBA中观察到的行为相对应:

点击该按钮3/4次后脚本似乎卡住了。

它不会卡住,实际上你的脚本继续正确执行。这是超时的网站。

我试图找出网络套接字崩溃的原因,但没有运气。这似乎是一个超时(我在调试他们的JavaScript时已经有了这么多,所以我的断点导致了超时)但我无法确定这是唯一的原因。由于您没有控制Web客户端和Web服务器之间的进程,您所能做的就是希望它不会超时。

此外,我相信使用Selenium会自动设置一些较长的超时时间(因为执行时间较长),这样可以让您保持Web套接字在超时方面更加宽容。

我发现在Web套接字崩溃后恢复连接的唯一方法是完全重新加载网页并从头开始重新启动进程。

我的建议

我认为您可能会构建XHR请求并通过JavaScript发送,因为他们的API(Web客户端/ Web套件通过其向Web服务器发送请求)在其前端代码中非常明显。

如果你打开他们的文件FinderAPI.js,你会发现他们已经离开了端点和API配置:

var FinderAPI = {
  store: null,
  state: null,
  finderEndpoint: '/api/v1/bsg/etp/finder/list',
  bidAskEndpoint: '/api/v1/prices/bidAsk/get',
  instrumentNameEndpoint: '/api/products/ProductTypeMapping/InstrumentNames',
  nameMappingEndpoint: '/api/v1/bsg/general/namemapping/list',
  apiConfig: false,
  initialize: function initialize(store, finderEndpoint) {
    var apiConfig = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
    this.store = store;
    this.state = store.getState();
    this.apiConfig = apiConfig;
    this.finderEndpoint = finderEndpoint;
  },

这意味着您知道应将POST请求发送到的URL。

请求还要求服务器验证承载令牌。幸运的是,他们也忘了保护他们的令牌,提供(GORSH)GET终点来获得令牌:

终点:https://www.boerse-stuttgart.de/api/products

响应:{“AuthenticationToken”:“JgACxn2DfHceHL33uJhNj34qSnlTZu4 + hAUACGc49UcjUhmLutN6sqcktr / T634vaPVcNzJ8sHBvKvWz”,“主持人”:“frontgate.mdgms.com”}

您只需要稍微浏览一下网站,找出POST请求的正文,然后创建一个新的XmlHttpRequest并在其中发送这些值,直接在您的VBA中检索价格,而无需打开网页和机器人刮。

我建议你从文件FinderAPI.js,第66行开始一个断点(代码行是this.post(this.finderEndpoint, params)params应该引导你到请求的主体 - 我记得你可以用JSON.stringify(params)打印对象作为字符串)。

此外,请注意,他们每次使用50结果的分页,即使他们的API支持他们的500。换句话说,如果您将值500(而不是50)扫描到发送到请求的API的分页属性中:

enter image description here

...那么你每次将获得500个结果而不是50个结果,所以如果你决定不深入XHR解决方案,你的代码将花费在刮擦网页上的时间减少10个。


0
投票

你能尝试改变吗?

Do
    Set post = Html.querySelector(".bsg-searchlist__load-more button.bsg-btn--juna")
    If Not post Is Nothing Then
      post.ScrollIntoView
    post.Click
    Application.Wait Now + TimeValue("00:00:05")
    Else: Exit Do
  End If
Loop

至:

Set post = Html.querySelector(".bsg-searchlist__load-more button.bsg-btn--juna")
If Not post Is Nothing Then
      post.ScrollIntoView
      While Not post Is Nothing
        Debug.Print "Clicking"
        post.Click
        Application.Wait Now + TimeValue("00:00:05")
      Wend
      Debug.Print "Exited Click"
End If

(另)

© www.soinside.com 2019 - 2024. All rights reserved.