【问题标题】:Retrieving all Excel file links from a webpage从网页中检索所有 Excel 文件链接
【发布时间】:2019-04-25 20:43:23
【问题描述】:

我正在尝试从网站上获取所有可下载的 Excel 文件链接,但遇到了困难。请帮助指导我。谢谢。

Sub TYEX()

    Dim internet As Object
    Dim internetdata As Object
    Dim div_result As Object
    Dim header_links As Object
    Dim link As Object
    Dim URL As String

    Set internet = CreateObject("InternetExplorer.Application")
    internet.Visible = True

    URL = "https://www.jpx.co.jp/markets/public/short-selling/index.html"
    internet.Navigate URL

    Do Until internet.ReadyState >= 4
        DoEvents
    Loop

    Application.Wait Now + TimeSerial(0, 0, 5)

    Set internetdata = internet.Document
    Set div_result = internetdata.getElementById("readArea")

    Set header_links = div_result.getElementsByTagName("td")

    For Each h In header_links
        Set link = h.ChildNodes.item(0)
        Cells(Range("A" & Rows.Count).End(xlUp).Row + 1, 1) = link.href
    Next

    MsgBox "done"
End Sub

【问题讨论】:

  • 也许你可以提供更多关于困难在哪里以及你尝试了什么的信息。

标签: html excel vba web-scraping


【解决方案1】:

你的想法是正确的,但这里有一个不同的方法:

Sub TYEX()

    Dim ie As Object
    Set ie = CreateObject("InternetExplorer.Application")
    With ie
        .navigate "https://www.jpx.co.jp/markets/public/short-selling/index.html"
        .Visible = True

        Do While .Busy Or .readyState < 4
            DoEvents
        Loop

        Dim doc As Object, tbl As Object
        Set doc = .document
        Set tbl = doc.getElementsByClassName("component-normal-table")(0).Children(0)

        Dim r As Long, xlsArr(), a As Object

        With tbl.Rows
            ReDim xlsArr(1 To .Length - 1)
            For r = 1 To .Length - 1   ' 0 is the table header
                xlsArr(r) = .Item(r).Children(1).innerHTML
            Next r
        End With

        With CreateObject("VBScript.RegExp")
            .Pattern = "<a href=""(\/markets.*?\.xls)"
            For r = 1 To UBound(xlsArr)
                xlsArr(r) = "https://www.jpx.co.jp" & .Execute(xlsArr(r))(0).SubMatches(0)
                Debug.Print xlsArr(r)
            Next
        End With
    End With

    'Add to sheet
    Dim ws As Worksheet, rng As Range
    Set ws = ThisWorkbook.Worksheets(1)
    With ws
        Set rng = .Range(.Cells(NextRow(ws), 1), .Cells(NextRow(ws) + UBound( _
                xlsArr) - 1, 1))
        rng.Value = Application.Transpose(xlsArr)
    End With

End Sub

Public Function NextRow(ByVal ws As Worksheet, Optional ByVal col As Variant = 1) As Long
    With ws
        NextRow = .Cells(.Rows.Count, col).End(xlUp).Row + 1
    End With
End Function

分解代码

这将循环您的 html 表格行。我们从 1 开始,因为 0 实际上只是表头。

With tbl.Rows
    ReDim xlsArr(1 To .Length - 1)
    For r = 1 To .Length - 1   ' 0 is the table header
        xlsArr(r) = .Item(r).Children(1).innerHTML
    Next r
End With

这使用正则表达式从innerHTML 属性中提取url。你可以在这里看到这个特殊的正则表达式是如何工作的:Regex101

With CreateObject("VBScript.RegExp")
    .Pattern = "<a href=""(\/markets.*?\.xls)"
    For r = 1 To UBound(xlsArr)
        xlsArr(r) = "https://www.jpx.co.jp" & .Execute(xlsArr(r))(0).SubMatches(0)
        Debug.Print xlsArr(r)
    Next
End With

您将范围调整为与包含链接的数组大小相同,然后将该数组写入工作表。这通常比逐个写入单元格要快得多。

'Add to sheet
Dim ws As Worksheet, rng As Range
Set ws = ThisWorkbook.Worksheets(1)
With ws
    Set rng = .Range(.Cells(NextRow(ws), 1), .Cells(NextRow(ws) + UBound( _
            xlsArr) - 1, 1))
    rng.Value = Application.Transpose(xlsArr)
End With

【讨论】:

    【解决方案2】:

    您可以使用attribute = value CSS selector$ 运算符来表示href 值必须以.xls 结尾。然后使用querySelectorAll 检索所有匹配的结果。使用 CSS 选择器是一种非常快速且通常稳健的方法。

    Dim list As Object
    Set list = ie.document.querySelectorAll("[href$='.xls']")
    

    使用 XMLHTTP 也比打开 IE 快得多。请注意,然后您可以将这些链接传递给执行二进制下载的函数或 URLMon 进行下载。

    Option Explicit   
    Public Sub Links()
        Dim sResponse As String, html As HTMLDocument, list As Object, i As Long
    
        With CreateObject("MSXML2.XMLHTTP")
            .Open "GET", "https://www.jpx.co.jp/markets/public/short-selling/index.html", False
            .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
            .send
            sResponse = StrConv(.responseBody, vbUnicode)
        End With
    
        Set html = New HTMLDocument
        With html
            .body.innerHTML = sResponse
            Set list = html.querySelectorAll("[href$='.xls']")
        End With
        For i = 0 To list.Length - 1
            Debug.Print Replace$(list.item(i), "about:", "https://www.jpx.co.jp")
        Next
    End Sub
    

    示例下载功能(尽管您可以重新使用现有的 XMLHTTP 对象 - 这只是为了说明):

    Public Function DownloadFile(ByVal downloadFolder As String, ByVal downloadURL As String) As String
        Dim http As Object , tempArr As Variant
        Set http =  CreateObject("WinHttp.WinHttpRequest.5.1")
        http.Open "GET", downloadURL, False
        http.send
        On Error GoTo errhand
        With CreateObject("ADODB.Stream")
            .Open
            .Type = 1
            .write http.responseBody
            tempArr = Split(downloadURL, "/")
            tempArr = tempArr(UBound(tempArr))
            .SaveToFile downloadFolder & tempArr, 2  '< "/" on enter of downloadFolder. 2 for overwrite which is Ok if no file modifications.
            .Close
        End With
        DownloadFile = downloadFolder & tempArr
        Exit Function
    errhand:
        If Err.Number <> 0 Then
            Debug.Print Err.Number, Err.Description
            MsgBox "Download failed"
        End If
        DownloadFile = vbNullString
    End Function
    

    参考资料(VBE > 工具 > 参考资料):

    1. Microsoft HTML 对象库

    【讨论】:

    • 我希望你能在这里发帖。我仍然尝试使用querySelectorAll() 从您的技术中学习 - 它似乎非常强大。 OP,您可能应该使用这种方法。
    • @K.Dᴀᴠɪs 如果您想讨论什么或要求任何有用的参考资料,或者放弃您自己的任何参考资料,请跳到dawghaus。我们还添加了一个库。
    • 感谢 QHarr!会试试你的方法。
    • 酷。有任何问题请告诉我,并会解释。
    猜你喜欢
    • 2014-10-31
    • 1970-01-01
    • 2014-01-30
    • 2013-02-23
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多