• 爬虫之Re库


    一、常见匹配模式

    W        # 匹配字母数字及下划线
    W        # 匹配非字母数字下划线
    s        # 匹配任意空白字符,等价于[	
    
    f]
    S        # 匹配任意非空字符
    d        # 匹配任意数字,等价于[0-9]
    D        # 匹配任意非数字
    z        # 匹配字符串结束
            # 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串
    A        # 匹配字符串开始
    G        # 匹配最后匹配完成的位置
    
            # 匹配一个换行符
    	        # 匹配一个制表符
    ^         # 匹配字符串的开头
    $         # 匹配字符串的末尾。
    a|b       # 匹配a或b
    .         # 匹配任意字符(除了换行符),当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符
    ()        # 匹配括号内的表达式,也表示一个组
    [...]     # 用来表示一组字符,单独列出:[abc] 匹配 a、b或c
    [^...]    # 不在[]中的字符:[^abc] 匹配除了a、b、c之外的字符
    
    ?         # 匹配 0个 或 一个 由前面的正则表达式定义的片段,非贪婪方式
    *         # 匹配 0个 或 多个
    +         # 匹配 1个 或 多个
    {n}       # 精确匹配n个前面表达式
    {n, m}    # 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式

    二、re.match

    re.match(pattern, string, flags=0)

    re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none

    最常规的匹配

    import re
    
    content = "Hello 123 4567 World_This is a Regex Demo"
    print(len(content))
    result = re.match("^Hellosdddsd{4}sw{10}.*Demo$", content)
    print(result)
    print(result.group()) # 匹配结果
    print(result.span())  # 输出匹配结果范围
    # 41
    # <_sre.SRE_Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
    # Hello 123 4567 World_This is a Regex Demo
    # (0, 41)
    View Code

    泛匹配

    像上面写的正则表达式,写的太多,非常繁琐,通用性不强。一个非常好的解决方法是:使用 .* 匹配所有的字符串。

    result = re.match("^Hello.*Demo$", content)

    获取匹配目标

    import re
    
    content = "Hello 1234567 World_This is a Regex Demo"
    result = re.match("^Hellos(d+)s.*Demo$", content)
    print(result.group(1))  # 1234567

    贪婪匹配

    import re
    
    content = "Hello 1234567 World_This is a Regex Demo"
    result = re.match("^He.*(d+).*Demo$", content)
    print(result.group(1))  # 7

    可以看到 d+ 只匹配到7,前面的123456被 .* 匹配掉了,也就是 .* 会尽可能匹配更多的字符,但是后面有 d+,所以这个只能匹配到7。

    非贪婪模式

    在 .* 后面加个?即可变成非贪婪匹配。

    import re
    
    content = "Hello 1234567 World_This is a Regex Demo"
    result = re.match("^He.*?(d+).*Demo$", content)
    print(result.group(1))  # 1234567

    几个常用的非贪婪匹配:

    ??    # 匹配 0次 或 1次,但尽可能少重复
    *?    # 匹配 任意次,但尽可能少重复
    +?    # 匹配 1次 或 更多次,但尽可能少重复

    .*? 的用法:取尽量少的任意字符;但一般不会这么单独写,它大多用法为.*?x表示取前面任意长度的字符,直到一个x出现。

    匹配模式

    import re
    
    content = """Hello 1234567 World_This 
    is a Regex Demo"""
    result = re.match("^He.*?(d+).*?Demo$", content)
    print(result)  # None

    可以看到没有匹配到内容,这是因为 . 不能匹配到换行符,这时就需要指定匹配模式,使用re.S,代表 . 能匹配换行符了。

    result = re.match("^He.*?(d+).*?Demo$", content, re.S)

    转义

    import re
    
    content = "price is $5.00"
    result = re.match("price is $5.00", content)
    print(result)  # None

    使用 转义字符。

    import re
    
    content = "price is $5.00"
    result = re.match("price is $5.00", content)
    print(result.group())  # price is $5.00

    总结:尽量使用泛匹配、使用括号得到匹配目标、尽量使用非贪婪模式、有换行符就用re.S

    三、re.search

    使用re.match有不太方便的,因为它会从字符串开头开始匹配,如果没匹配到,就返回None了;而 re.search 会扫描整个字符串并返回第一个成功的匹配。

    import re
    
    content = "Extra stings Hello 1234567 World_This is a Regex Demo Extra stings"
    result1 = re.match("Hello.*?(d+).*?Demo", content)
    print(result1)  # None
    
    result2 = re.search("Hello.*?(d+).*?Demo", content)
    print(result2)  # <_sre.SRE_Match object; span=(13, 53), match='Hello 1234567 World_This is a Regex Demo'>
    print(result2.group(1))  # 1234567

    总结:为匹配方便,能用search就不用match

    匹配练习

    测试字符串:

    html = '''<div id="songs-list">
        <h2 class="title">经典老歌</h2>
        <p class="introduction">
            经典老歌列表
        </p>
        <ul id="list" class="list-group">
            <li data-view="2">一路上有你</li>
            <li data-view="7">
                <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
            </li>
            <li data-view="4" class="active">
                <a href="/3.mp3" singer="齐秦">往事随风</a>
            </li>
            <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
            <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
            <li data-view="5">
                <a href="/6.mp3" singer="邓丽君"><i class="fa fa-user"></i>但愿人长久</a>
            </li>
        </ul>
    </div>'''
    # 匹配带有active类的li标签
    result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>', html, re.S)
    if result:
        print(result.group(1), result.group(2))  # 齐秦 往事随风
    # 匹配li标签(只要匹配成功就返回)
    result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html, re.S)
    if result:
        print(result.group(1), result.group(2))  # 任贤齐 沧海一声笑
    # 匹配li标签(将re.S去掉)
    result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html)
    if result:
        print(result.group(1), result.group(2))  # beyond 光辉岁月

    四、re.findall

    返回所有满足匹配条件的结果,放在列表里。

    import re
    
    html = '''<div id="songs-list">
        <h2 class="title">经典老歌</h2>
        <p class="introduction">
            经典老歌列表
        </p>
        <ul id="list" class="list-group">
            <li data-view="2">一路上有你</li>
            <li data-view="7">
                <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
            </li>
            <li data-view="4" class="active">
                <a href="/3.mp3" singer="齐秦">往事随风</a>
            </li>
            <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
            <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
            <li data-view="5">
                <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
            </li>
        </ul>
    </div>'''
    
    result = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
    for item in result:
        print(item)
    
    """
    ('/2.mp3', '任贤齐', '沧海一声笑')
    ('/3.mp3', '齐秦', '往事随风')
    ('/4.mp3', 'beyond', '光辉岁月')
    ('/5.mp3', '陈慧琳', '记事本')
    ('/6.mp3', '邓丽君', '但愿人长久')
    """
    View Code

    上面的例子可以看到并没有匹配到第一个li,这是因为li标签并没有包含a标签,不符合匹配规则。如果我们也想把这个内容也获取到,怎么做呢?

    import re
    
    html = '''<div id="songs-list">
        <h2 class="title">经典老歌</h2>
        <p class="introduction">
            经典老歌列表
        </p>
        <ul id="list" class="list-group">
            <li data-view="2">一路上有你</li>
            <li data-view="7">
                <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
            </li>
            <li data-view="4" class="active">
                <a href="/3.mp3" singer="齐秦">往事随风</a>
            </li>
            <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
            <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
            <li data-view="5">
                <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
            </li>
        </ul>
    </div>'''
    
    result = re.findall('<li.*?>s*?(<a.*?>)?(w+)(</a>)?s*?</li>', html)
    for item in result:
        print(item)
        # print(item[1])
    """
    ('', '一路上有你', '')
    ('<a href="/2.mp3" singer="任贤齐">', '沧海一声笑', '</a>')
    ('<a href="/3.mp3" singer="齐秦">', '往事随风', '</a>')
    ('<a href="/4.mp3" singer="beyond">', '光辉岁月', '</a>')
    ('<a href="/5.mp3" singer="陈慧琳">', '记事本', '</a>')
    ('<a href="/6.mp3" singer="邓丽君">', '但愿人长久', '</a>')
    """
    View Code

    五、re.sub

    替换字符串中每一个匹配的子串后返回替换后的字符串。

    import re
    
    content = "Hello 1234567 World"
    
    result1 = re.sub("d", "v", content, 3)  # 将数字替换成 v ,参数3表示替换3个
    print(result1)  # Hello vvv4567 World
    
    result2 = re.sub("d", "v", content)
    print(result2)  # Hello vvvvvvv World
    
    result3 = re.sub("d+", "v", content)
    print(result3)  # Hello v World
    
    result4 = re.sub("d+", "", content)
    print(result4)  # Hello  World
    import re
    
    content = "Hello 1234567 World"
    result = re.sub("(d+)", r"1 8910", content)
    print(result)  # Hello 1234567 8910 World
    # 使用 1 拿到匹配内容,即用1234567 8910 替换1234567

    会了re.sub,对于上面re.findall的第二个例子,现在就简单多了:

    import re
    
    html = '''<div id="songs-list">
        <h2 class="title">经典老歌</h2>
        <p class="introduction">
            经典老歌列表
        </p>
        <ul id="list" class="list-group">
            <li data-view="2">一路上有你</li>
            <li data-view="7">
                <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
            </li>
            <li data-view="4" class="active">
                <a href="/3.mp3" singer="齐秦">往事随风</a>
            </li>
            <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
            <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
            <li data-view="5">
                <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
            </li>
        </ul>
    </div>'''
    html = re.sub("<a.*?>|</a>", "", html)
    print(html)
    result = re.findall("<li.*?>(.*?)</li>", html, re.S)
    print(result)
    for item in result:
        print(item.strip())
    View Code

    六、re.compile

    将正则字符串编译成正则表达式对象,以便于复用该匹配模式。

    import re
    
    content = '''Hello 1234567 World_This
    is a Regex Demo'''
    # 方式1
    pattern = re.compile("Hello.*Demo", re.S)
    result1 = re.match(pattern, content)
    # 方式2
    result2 = re.match("Hello.*Demo", content, re.S)

    七、实战

    import re
    import requests
    
    html = requests.get("https://movie.douban.com/chart").text
    pattern = re.compile('<table.*?nbg.*?href="(.*?)".*?title="(.*?)".*?rating_nums">(.*?)</span>.*?</table>', re.S)
    result = re.findall(pattern, html)
    for item in result:
        url, title, rating_nums = item
        print(url, title, rating_nums)
    https://movie.douban.com/subject/25986662/ 疯狂的外星人        6.4
    https://movie.douban.com/subject/3878007/  海王            7.7
    https://movie.douban.com/subject/27597250/ 极限职业          7.7
    https://movie.douban.com/subject/26816076/ “大”人物          6.5
    https://movie.douban.com/subject/30209818/ 忌日快乐2         6.7
    https://movie.douban.com/subject/20438964/ 无敌破坏王2:大闹互联网  8.1
    https://movie.douban.com/subject/26147417/ 神奇动物:格林德沃之罪   7.1
    https://movie.douban.com/subject/27119586/ 谁先爱上他的        8.6
    https://movie.douban.com/subject/27065898/ 神探蒲松龄          3.8
    https://movie.douban.com/subject/30170448/ 何以为家           8.8
    
  • 相关阅读:
    ExecuteScalar requires the command to have a transaction when the connection assigned to the command is in a pending
    如何从vss中分离程序
    String or binary data would be truncated
    the pop3 service failed to retrieve authentication type and cannot continue
    The POP3 service failed to start because
    IIS Error he system cannot find the file specified _找不到页面
    pku2575Jolly Jumpers
    pku2940Wine Trading in Gergovia
    pku3219二项式系数
    pku1029false coin
  • 原文地址:https://www.cnblogs.com/believepd/p/10656980.html
Copyright © 2020-2023  润新知