以Excel VBA实现对网页中Table的爬虫 --- Part 2



  • 在上一篇帖子当中我们介绍了XMLHTTP对象及方法获取网页中Table对应的网页字符串. 那么如何从这些字符串中获取我们想要的数据呢?在python或者java中这些会有对应的包和函数可以实现. 而本篇将会介绍一种简单而基础的方法: 正则表达式 (Regex).

    3.正则表达式 (Regex):

    正则表达式是一种用于匹配字符串中字符模式的工具, 它可以用来搜索、编辑和处理文本.

    正则表达式的作用非常强大,详细的总结可以参考CSDN大佬的帖子:VBA学习笔记六:正则表达式.

    下面我会总结用到的一些对象和方法:

    3.1 创建正则表达式对象:

    3.1.1 前期绑定:

    添加引用库:工具 > 引用 >勾选 ’Microsoft VBScript Regular Expressions 5.5‘

    '直接声明reg对象就可以使用'
    Dim reg as New RegExp
    

    3.1.2 后期绑定 (推荐使用):
    使用 CreateObject 方法来创建 VBScript.RegExp 对象,便可使用
    代码

    '先声明再创建reg对象'
    Dim reg As Object
    Set reg = CreateObject("VBScript.RegExp")
    

    3.2 用到的属性及方法:

    3.2.1 Pattern 属性
    • 描述:定义要匹配的正则表达式模式
    • 示例:匹配任意四个字母的单词
    reg.Pattern = "\b\w{4}\b"
    3.2.2 Global 属性
    • 描述:设置是否全局搜索匹配。默认为 False,只匹配第一个
    • 示例:全局匹配所有符合模式的字符串
    reg.Global = True

    3.2.3 Execute 方法
    • 描述:执行正则表达式匹配,查找所有符合匹配模式的子字符串,并返回一个匹配集合对象 (MatchCollection对象)
    • 示例:查找匹配项,其中 string 是要搜索的字符串
    Set matches = reg.Execute(string)

    3.3 匹配规则 这里我照抄CSDN文章:

    157d2261-46c2-4313-a232-0c4c8079a265-image.png
    6258b8f7-a1f8-4c19-a267-e49b7cc8e985-image.png
    16d5c92c-3716-47b2-aa97-71571c626c78-image.png
    c315a32b-c95e-458b-a491-f5d99b516307-image.png
    a29325aa-1fbb-4e53-8929-fe412fd97883-image.png
    9af8624b-dfbe-4ab8-b2a1-69fa9e32465c-image.png
    72445095-6198-4af6-a7c1-1c1930fb2132-image.png
    0b578d14-5ad9-4391-bf2d-3975a7d69d45-image.png

    3.4 匹配结果的对象:

    3.4.1 MatchCollection对象:

    含义:是一个集合对象,包含了正则表达式在输入文本中找到的所有匹配项,每个匹配项都表示为一个 Match 对象.

    用到的属性:
    Item 属性
    ○ 功能:返回集合中第几个 Match 对象,从0开始计数
    ○ 用法:matches.Item(index)matches(index)
    ○ 示例:输出第一个匹配到的对象
    Set match = matches(0)
    MsgBox "Found match: " & match.Value

    3.4.2 Match对象:

    含义:表示正则表达式匹配中的一个匹配项,包含匹配的文本和其他相关信息

    用到的属性:

    SubMatches 属性
    ○ 功能:返回一个 SubMatches 集合(注意这里返回了集合,因而适用MatchCollection对象的所有方法),包含所有捕获的子匹配项,通过索引访问捕获组的内容(索引从0开始)可以获取匹配到的分组内容
    ○ 前提:在正则表达式模式中使用了括号来创建捕获组 (参考3.3.>>>)
    ○ 用法:match.SubMatches(n)*表示访问子匹配项第n+1个捕获组的内容,也就是表达式里面的第n+1个括号

    *这里的语法也可以写成match.SubMatches.Item(n)来表达同样的意思。

    4.正则表达式应用实例:

    4.1 代码及注释

    Sub getrates(s As String)
    
        Dim reg As Object, m As Object, mchs As Object
        Dim i As Long, j As Long, p As String
        
        Set reg = CreateObject("vbscript.regexp")'后期绑定创建regex'
        
        '----regex'
        p = "<tr>\s*<td.*><time.*>([^<]*)</time>\s*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>.*</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*<td.*>([^<]*)</td>\s*</tr>"
        
        reg.pattern = p'3.2.1 pattern属性'
        reg.Global = True'3.2.2 global属性'
        
        Set mchs = reg.Execute(s)'3.2.3 execute方法'
        
        i = 6
        For Each m In mchs'3.4.1 MatchCollection对象'
            For j = 0 To m.submatches.Count - 1
                Cells(i, j + 1) = m.submatches.Item(j)
           '利用3.4.2match对象的submatches属性去将捕获字符输出到单元格中'
            Next j
            i = i + 1
        Next m
        
    End Sub
    

    4.2 正则表达式p的写法:

    这里我复制出来整个Table的字符串, 以第一行(<tr>...</tr>为一行的字符串)为例, 用黄色标出来我想要的字符.

    fc7c8410-56ab-4546-8119-8652145ea589-image.png

    参照3.3匹配规则中的捕获组方法, 将需要输出的字符以()包含进去,根据网页字符串的语法<tr>.*</tr><td>.*</td>做一些识别与中间内容的捕获, 作者就得到了如下的正则表达式.

    997718e6-8a54-411b-872e-9af853eb8a4d-image.png

    5.总结:

    作者所使用的方法基本可以分为两步:
    第一步, 利用XMLHTTP对象先从网页中返回字符串;
    第二步, 利用正则表达式的匹配及捕获funtion从字符串中返回需要的字符

    6.杂谈:

    本帖是作者应管理员珂珂之邀写的第一篇技术分享帖子, 谢邀~

    但作者对本论坛的流量表示怀疑, 因为截止到作者写part 2时, part 1帖仅有两个浏览量, 其中一个还是作者本人贡献QAQ.

    在此呼吁珂珂阿姨将论坛内容在公众号中做实时更新, 并祝愿珂珂阿姨做大做强, 再创辉煌~ 此致, 敬礼^.^-!


登录后回复