使用 XMLHTTP 方法时等到页面加载完毕

Posted

技术标签:

【中文标题】使用 XMLHTTP 方法时等到页面加载完毕【英文标题】:Wait until page is loaded when using XMLHTTP approach 【发布时间】:2020-02-03 13:53:41 【问题描述】:

在以下工作代码中,我正在尝试导航到特定的 youtube 频道 要将视频名称转换为 excel .. 它正在工作,但部分是因为代码只列出了大约 30 个视频

    Dim x, html As Object, ele As Object, sKeyWords As String, i As Long

With CreateObject("MSXML2.ServerXMLHTTP")
    .Open "GET", "youtube channel url videos", False
    .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
    .send

    If .Status <> 200 Then MsgBox "Problem" & vbNewLine & .Status & " - " & .statusText: Exit Sub

    Set html = CreateObject("htmlfile")
    html.body.innerHTML = .responseText

我怎样才能使代码加载页面的所有内容..?以便获取那里列出的所有视频。

我找到了一个网站,将所有视频都列在一个表格中,但是对于抓取表格的部分,我无法提取视频名称,甚至无法处理表格 这是我的尝试

Sub Post_Method()
Dim http        As New XMLHTTP60
Dim html        As New HTMLDocument
Dim htmla       As Object
Dim trow        As Object
Dim tcel        As Object
Dim strArg      As String
Dim c           As Long
Dim x           As Long

strArg = "inputType=1&stringInput=https%3A%2F%2Fwww.youtube.com%2Fchannel%2FUC43lrLHl4EhxaKQn2HrcJPQ&limit=100&keyType=default&customKey="

With http
    .Open "POST", "https://youtube-playlist-analyzer.appspot.com/submit", False
    .setRequestHeader "Content-type", "application/x-www-form-urlencoded"
    .send strArg
    html.body.innerHTML = .responseText
   ' WriteTxtFile html.body.innerHTML
End With

Dim posts As Object, elem As Object, r As Long

'This part I can't adjust
'------------------------
    Set posts = html.getElementById("container").getElementById("tableContainer").getElementById("tableData")

    For Each elem In posts.Children
        For Each trow In elem.Cells
            c = c + 1: Cells(r + 1, c) = trow.innerText
        Next trow
        c = 0: r = r + 1
    Next elem
    '----------------------------------
 Stop

End Sub

【问题讨论】:

您意识到 YouTube 经常会在您滚动页面时动态加载很多内容 - 您是否检查过这是否是一个因素? 非常感谢。我注意到。所以我问了这个问题,可能有一种解决方法可以使页面完全加载... 我的直觉是硒和慢滚动可能是最好的方法,但我还没有测试过。 谢谢。你能指导我如何在 selenium 中使用滚动 ..? 应该有关于 SO 的例子,尤其是在 python 标签中。缓慢滚动,直到没有更多结果。用户 alexce 对此写了一个众所周知的答案——除非你能阅读 python,否则我认为它没有多大帮助。用户 sim 可能在此处或代码审查中用 vba selenium 编写了等效的代码。 【参考方案1】:

您可以使用该端点,然后从包含感兴趣数据的响应中提取 javascript 对象并使用 jsonconverter.bas 进行解析。

Json 库:

我使用 jsonconverter.bas。从here 下载原始代码并添加到名为 JsonConverter 的标准模块中。然后您需要转到 VBE > 工具 > 参考 > 添加对 Microsoft Scripting Runtime 的引用。从复制的代码中删除顶部的 Attribute 行。


VBA:

Option Explicit

Public Sub GetYouTubeViews()

    Dim s As String, ws As Worksheet, body As String

    body = "inputType=1&stringInput=https://www.youtube.com/channel/UC43lrLHl4EhxaKQn2HrcJPQ&limit=100&keyType=default"

    Set ws = ThisWorkbook.Worksheets("Sheet1")

    With CreateObject("MSXML2.XMLHTTP")
        .Open "POST", "https://youtube-playlist-analyzer.appspot.com/submit", False
        .setRequestHeader "User-Agent", "Mozilla/5.0"
        .send body
        s = .responseText
    End With

    Dim results(), r As Long, jsonSource As String
    Dim json As Object, item As Object, headers()

    jsonSource = GetString(s, "json_items = ", ";")

    If jsonSource = "No match" Then Exit Sub

    Set json = JsonConverter.ParseJson(jsonSource)

    headers = Array("Title", "ViewCount")

    ReDim results(1 To json.Count, 1 To UBound(headers) + 1)

    For Each item In json
        r = r + 1
        results(r, 1) = item("title")
        results(r, 2) = item("viewCount")
    Next

    With ws
        .Cells(1, 1).Resize(1, UBound(headers) + 1) = headers
        .Cells(2, 1).Resize(UBound(results, 1), UBound(results, 2)) = results
    End With
End Sub

Public Function GetString(ByVal inputString As String, ByVal startPhrase As String, ByVal endPhrase As String) As String
    Dim s As Long, e As Long

    s = InStr(inputString, startPhrase)
    If Not s > 0 Then
        GetString = "No match"
        Exit Function
    End If

    e = InStr(s + Len(startPhrase) - 1, inputString, endPhrase)

    If Not e > 0 Then
        GetString = "No match"
        Exit Function
    End If
    GetString = Mid$(inputString, s + Len(startPhrase), e - (s + Len(startPhrase)))
End Function

示例结果:


派:

使用 python 更简洁

import requests, re, json ,csv

data = 
  'inputType': '1',
  'stringInput': 'https://www.youtube.com/channel/UC43lrLHl4EhxaKQn2HrcJPQ',
  'limit': '100',
  'keyType': 'default'


r = requests.post('https://youtube-playlist-analyzer.appspot.com/submit',  data=data)
p = re.compile(r'json_items = (.*?);', re.DOTALL)
results = json.loads(p.findall(r.text)[0])

with open("data.csv", "w", encoding="utf-8-sig", newline='') as csv_file:
    w = csv.writer(csv_file, delimiter = ",", quoting=csv.QUOTE_MINIMAL) #change this for locale
    w.writerow(['Title','ViewCount'])
    for item in results:
        w.writerow([item['title'], item['viewCount']])

【讨论】:

太棒了。非常棒。非常感谢,至于刮桌的部分,究竟是什么问题,我根本无法处理……? 我认为该表是由响应中的 JavaScript 指令动态构建的。如果是这种情况,则需要浏览器来填充表格。 您需要打印响应而不是让它到达 jsonconverter。是的,我今天晚些时候会看看。 我稍后再看 我已经找到原因了。有一个带有分号描述的视频,所以我更改了这一行jsonSource = GetString(s, "json_items = ", ";" &amp; vbLf &amp; vbLf),现在效果很好

以上是关于使用 XMLHTTP 方法时等到页面加载完毕的主要内容,如果未能解决你的问题,请参考以下文章

如何让页面加载完成后执行js

JS中的DOM

js怎样页面加载之前执行

Vue 在页面加载结束后执行某个函数

js怎样页面加载之前执行?

大坑啊!!!关于页面加载完毕事件!!!