Python爬虫理论Pro | (4) 正则表达式

本篇博客我们将介绍正则表达式,它是处理字符串,如查找、替换等,解析HTML代码、数据清洗等操作的强大工具。

目录

1. 什么是正则表达式?

2. 常见匹配模式

3. re.match

4. re.search

5. re.findall

6. re.sub

7. re.compile

8. 实战


1. 什么是正则表达式?

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”⽤来表达对字符串的⼀种过滤逻辑。

非Python独有,通过re模块实现。

2. 常见匹配模式

3. re.match

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

re.match(pattern, string, flags=0)
  • 最常规匹配
import re

content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$', content)
print(result)
print(result.group()) 
print(result.span()) #匹配范围

  • 泛匹配
import re

content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello.*Demo$', content)
print(result)
print(result.group())
print(result.span())

  • 匹配目标
import re
#匹配1234567  
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld.*Demo$', content)#将目标用()扩起来 目标前后指明 确定范围
print(result)
print(result.group())
print(result.group(1)) #打印第一个()匹配的目标 
print(result.span())

  • 贪婪匹配
import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*Demo$', content) #前面的1-6被.*匹配掉了 贪婪模式下.*匹配尽可能多 \d+至少一个数字
print(result)
print(result.group(1))

  • 非贪婪模式
import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$', content)#加上? 非贪婪模式 匹配尽可能少的字符
print(result)
print(result.group(1))

  • 匹配模式
import re
#字符串包含换行符
content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\d+).*?Demo$', content, re.S) #.不能匹配换行符 加上re.S可以匹配
print(result.group(1))

  • 转义
import re

content = 'price is $5.00'
result = re.match('price is $5.00', content)
print(result)

import re

content = 'price is $5.00'
result = re.match('price is \$5\.00', content) #特殊字符前加转义字符
print(result)

  • 小结

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

 

4. re.search

re.search 扫描整个字符串并返回第一个成功的匹配。

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.match('Hello.*?(\d+).*?Demo', content)#只能从第一个字符开始匹配 如果第一个字符不匹配 就不会成功匹配
print(result)

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.search('Hello.*?(\d+).*?Demo', content)
print(result)
print(result.group(1))

为匹配方便,能用search就不用match.

  • 匹配演练
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="邓丽君"><i class="fa fa-user"></i>但愿人长久</a>
        </li>
    </ul>
</div>'''
result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
    print(result.group(1), result.group(2))

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.search('<li.*?singer="(.*?)">(.*?)</a>', html, re.S) #只返回第一个成功的匹配
if result:
    print(result.group(1), result.group(2))

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.search('<li.*?singer="(.*?)">(.*?)</a>', html) #此时不能匹配换行符 
if result: #所以第一个匹配的是第四个标签
    print(result.group(1), result.group(2))

5. 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>'''

results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
print(results) #返回全部匹配 列表形式 每个元素是一个元组
print(type(results))
for result in results:
    print(result)
    print(result[0], result[1], result[2])

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>'''

#匹配所有歌名 形式不一  有的有换行有的无 有的有a标签有的无
#()表示一个整体 ?匹配0个或1个 可能有可能无
#\s*?可能有换行也可能无

results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>', html, re.S)
print(results)
for result in results:
    print(result[1])

6. re.sub

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

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('\d+', '', content)
print(content)

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('\d+', 'Replacement', content)
print(content)

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('(\d+)', r'\1 8910', content) #\1把第一个()中匹配到的字符串 拿过来 
print(content)

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) #把<a...> 或</a>替换为空''
print(html)
results = re.findall('<li.*?>(.*?)</li>', html, re.S)
print(results)
for result in results:
    print(result.strip())

7. re.compile

将一个正则表达式串编译成正则对象,以便于复用该匹配模式.

import re

content = '''Hello 1234567 World_This
is a Regex Demo'''
#便于复用 直接用pattern就好了 不需要再写一遍字符串
pattern = re.compile('Hello.*Demo', re.S) #把正则表达式字符串先编译成对象
result = re.match(pattern, content) #此时第一个参数是正则表达式对象
#result = re.match('Hello.*Demo', content, re.S)  #与上面等价 此时第一个参数是正则表达式串
print(result)
'''
#还有一种写法是
pattern = re.compile('Hello.*Demo', re.S) #把正则表达式字符串先编译成对象
#直接用对象调用方法
result = pattern.match(content) #此时第一个正则表达式参数可以不用写
'''

8. 实战

import requests
import re
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}

response = requests.get('https://book.douban.com/',headers=headers)
print(response.status_code)
content = response.text
print(content)
#获取url 书名 作者 日期
'''
<div class="info">
              <div class="title">
                <a class="" href="https://book.douban.com/subject/33447868/?icn=index-latestbook-subject" title="精致的独处">精致的独处</a>
              </div>
              <div class="author">
                [美]斯蒂芬妮·罗森布鲁姆
              </div>
              <div class="more-meta">
                <h4 class="title">
                  精致的独处
                </h4>
                <p>
                  <span class="author">
                    [美]斯蒂芬妮·罗森布鲁姆
                  </span>
                  /
                  <span class="year">
                    2019-6
                  </span>
                  /
                  <span class="publisher">
                    未读·文艺家 北京联合出版公司
                  </span>
                </p>
                <p class="abstract">
                  
                  斯蒂芬妮•罗森布鲁姆用一种全新的方式道出了独处的价值。
-
罗森布鲁姆将自己的观察、思考与心理学、社会学的研究结果相结合,以自我的亲身体验和艺术家、文学家们的生活为样本,剖析独处之于每个人的重要意义,回答什么是有益的独处,如何让独处有价值。
她以优雅的笔触记录她一年当中的旅行足迹,向我们展示了如何在一成不变的城市生活中,通过独处,梳理自己与外界...
                </p>
              </div>
            </div>
'''
pattern = re.compile('<div class="info".*?title.*?href="(.*?)".*?more-meta.*?title">(.*?)</h4>.*?author">(.*?)</span>.*?year">(.*?)</span>.*?</div>', re.S)
results = re.findall(pattern, content)
for result in results:
    url, name, author, date = result
    author = re.sub('\s', '', author)
    date = re.sub('\s', '', date)
    print(url, name, author, date)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值