首页 > 解决方案 > 如何从 tvdb 中抓取剧集编号

问题描述

我正在尝试从 tvdb 中分离和处理总季集数。就像我与 show LEGION ( https://www.thetvdb.com/series/legion ) 一起工作的一个简单示例。此主页将显示该节目有多少季,并且在该行的末尾,有一个徽章指示每个季节的剧集数。我想要一个节目的“绝对数量”剧集,所以我需要将所有这些数字加在一起。这是我能够做到的,但是我想排除“特价”季节剧集编号,这是困难的部分。特别是因为这些元素的内部文本将在指示它所引用的季节之前显示徽章值。

我经历了几个阶段。首先,我能够获得父标签的内部文本,它给了我一个信息块,说明表中的所有内容如下(似乎有 2 个标签具有相同的类名,这就是为什么我得到双重结果。任何帮助这也将不胜感激)

特价 2018 年 4 月 - 2018 年 4 月 8

季节 2017 年 2 月 1 日 - 2017 年 3 月 11

第 2 季 2018 年 4 月 - 2018 年 6 月 8

第 3 季 2019 年 6 月 - 2019 年 8 月

四季

1 特价 2018 年 4 月 - 2018 年 4 月

8 季 2017 年 2 月 1 日 - 2017 年 3 月

11 季 2018 年 4 月 2 日 - 2018 年 6 月

8 季 2019 年 6 月 3 日 - 2019 年 8 月

四季

其次,我能够通过循环遍历父标签中的所有元素来一次隔离一个块,如下所示

1 特价 2018 年 4 月 - 2018 年 4 月

第三,我已经到了可以再次循环并仅隔离徽章中的数字的阶段(我说徽章,因为它是在 html 代码中引用的方式)

我还回溯并使用了第 2 阶段,并在其中放置了一个正则表达式函数来识别单词“specials”,但无法弄清楚如何跳过它并继续运行 for 循环。

我相信我可能需要与父母、孩子、兄弟姐妹一起编码才能实现我想要的。

提前致谢

Sub()

Dim XML_05 As New MSXML2.XMLHTTP60
Dim HTML_05 As New MSHTML.HTMLDocument

XML_05.Open "GET", "https://www.thetvdb.com/series/legion", False
XML_05.send
HTML_05.body.innerHTML = XML_05.responseText

Dim NETC_05 As MSHTML.IHTMLElementCollection
Dim NET_05 As MSHTML.IHTMLElement
Dim REO_05 As VBScript_RegExp_55.RegExp
Dim MO_05 As Object
Dim SeasonsList As MSHTML.IHTMLElementCollection
Dim SeasonsInfo As MSHTML.IHTMLElement
Dim SI_05 As MSHTML.IHTMLElement
Dim Badge As MSHTML.IHTMLElement


Set SeasonsList = HTML_05.getElementsByClassName("hidden-sm hidden-md hidden-lg")

For Each SeasonsInfo In SeasonsList
    Debug.Print SeasonsList.Length
        For Each SI_05 In SeasonsInfo.getElementsByTagName("li")
                    For Each Badge In SI_05.Children
                    Debug.Print Badge.innerText
                Next Badge
        Next SI_05
Next SeasonsInfo

End Sub

标签: htmlvbaweb-scraping

解决方案


Specialsis first and All Seasonsis last 所以你可以循环一个nodeListfrom 1tonodeList.Length-2来避免这两个节点,并简单地将它们之间的数字相加。我使用一个代理 HTMLDocument 变量来保存每个节点的 html,这样我就可以再次利用并避免通过等querySelector长链。我不确定你是否在某个时候也想要其他信息,所以我存储了每个季节的名称、日期和数组中的情节计数(不包括所描述的节点)。这种方法还意味着代码复杂性降低到单个循环。getElementsnextSiblingresults

Option Explicit
Public Sub GetTotalEpisodes()
    Dim i As Long, html As MSHTML.HTMLDocument, html2 As MSHTML.HTMLDocument, seasons As Object, results(), r As Long

    Set html = New HTMLDocument: Set html2 = New HTMLDocument

    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", "https://www.thetvdb.com/series/legion", False
        .send
        html.body.innerHTML = .responseText
    End With

    Set seasons = html.querySelectorAll(".hidden-xs .list-group-item")
    ReDim results(1 To seasons.Length - 2, 1 To 3)

    For i = 1 To seasons.Length - 2
        html2.body.innerHTML = seasons.item(i).outerHTML
        results(i, 1) = Trim$(html2.querySelector(".list-group-item-heading").innerText)
        results(i, 2) = Trim$(html2.querySelector(".list-group-item-text").innerText)
        results(i, 3) = 1 * html2.querySelector(".badge").innerText
    Next
    Debug.Print Application.Sum(Application.index(results, 0, 3))
End Sub

如果您想存储所有信息,包括第一个和最后一个节点,但仍执行条件求和,您可以将标题排除在数组中并在循环期间检查该标题;仅当当前标头不在排除数组中时求和

Option Explicit
Public Sub GetTotalEpisodes()
    Dim i As Long, html As MSHTML.HTMLDocument, html2 As MSHTML.HTMLDocument, seasons As Object, results(), r As Long
    Dim exclusions(), heading As String, badge As Long, total As Long

    Set html = New HTMLDocument: Set html2 = New HTMLDocument
    exclusions = Array("Specials", "All Seasons")
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", "https://www.thetvdb.com/series/legion", False
        .send
        html.body.innerHTML = .responseText
    End With

    Set seasons = html.querySelectorAll(".hidden-xs .list-group-item")
    ReDim results(1 To seasons.Length, 1 To 3)

    On Error Resume Next
    For i = 0 To seasons.Length - 1
        html2.body.innerHTML = seasons.item(i).outerHTML
        heading = Trim$(html2.querySelector(".list-group-item-heading").innerText)
        badge = 1 * html2.querySelector(".badge").innerText
        results(i + 1, 1) = html2.querySelector(".list-group-item-heading").innerText
        results(i + 1, 2) = Trim$(html2.querySelector(".list-group-item-text").innerText)
        results(i + 1, 3) = badge
        If IsError(Application.match(heading, exclusions, 0)) Then
            total = total + badge
        End If
    Next
    On Error GoTo 0
    Debug.Print total
End Sub

操作问题:

  1. Option Explicit - 强制变量声明。

当 Option Explicit On 或 Option Explicit 出现在文件中时,您必须使用 Dim 或 ReDim 语句显式声明所有变量。如果您尝试使用未声明的变量名,则会在编译时发生错误。Option Explicit Off 语句允许隐式声明变量。

这是最佳实践,对于捕获拼写错误也很有用。

  1. results()- 我正在声明一个动态数组,这意味着我还不知道所需的尺寸,但稍后会在我知道时重新调整。它实际上是 results() As Variant(隐式)。另请参见此处。我可以稍后再调整,因为此时

    设置季节 = html.querySelectorAll(".hidden-xs .list-group-item")

seasons.Length会给我第一个维度的行数results()

  1. querySelectorAll - 类似于getElementsBy. 它将CSS 选择器(或组合)应用于HTMLDocument(例如ie.Document)。

Document 方法 querySelectorAll() 返回一个静态(非实时)NodeList,表示与指定选择器组匹配的文档元素列表

现代浏览器针对 css 进行了优化,因此这通常是一种快速灵活的查找节点的方法。

  1. Trim$- 是Trim. 它用于从node.innerText.

  2. 底部版本应该适用于单季。只需更改数组exclusions以说明您希望包含/排除的内容。如果没有,请给我一个例子,我会为你更新。


推荐阅读