《python3网络爬虫开发实战》第2章 基本库的使用之正则表达式的基本用法

2.3 正则表达式

2.3.1 基本概念

(1)正则表达式是用来处理字符串的强大工具,它有自己特定的语法结构,可实现字符串的检索、替换、匹配验证等
(2)常见匹配规则


2.3.2 match

(1)基本概念
match方法会尝试从字符串的起始位置开始匹配正则表达式,如果匹配,就返回匹配成功的结果;
如果不匹配,就返回None。
(2)示例
import re

content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello\s\d+\s\d+\s\w{10}', content)  # 修改正则表达式匹配规则
print(result)
print(result.group())
print(result.span())


结果分析:
输出结果打印出来,可以看到结果是SRE_Match对象,证明匹配成功。
该对象包含两个方法:
group方法可以输出匹配到的内容,结果是Hello 1234567 World_This,是正则表达式按照规则匹配的内容;
span方法可以输出匹配的范围,结果是(0,25),这是匹配到的结果字符串在原字符串中的位置范围。

(3)匹配目标
1)原理
可以使用括号()将想提取的子字符串括起来。()实际上标记了一个子表达式的开始和结束位置,被标记的每个子表达式依次对应每个分组,调用group方法传入分组的索引即可获取提取结果。
2)示例
import re
content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld',content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())


注明:group(1)与group()有所不同,后者会输出完整的匹配结果,前者会输出第一个被()包围的匹配结果.假如正则表达式后面还有用()包围的内容,那么可以依次用group(2)、group(3)等获取.

(4)通用匹配
1)万能匹配:.*;其中,.可以匹配任意字符(除换行符),*代表匹配前面的字符无限次。
2)示例
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello.*Demo$',content)
print(result)
print(result.group())
print(result.span())

(5)贪婪与非贪婪

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


2)非贪婪匹配就是匹配尽可能少的字符.
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 = 'http://weibo.com/comment/kEraCN'
result1 = re.match('http.*?comment/(.*?)',content)
result2 = re.match('http.*?comment/(.*)',content)
print('result1',result1.group(1))
print('result2',result2.group(1))

(6)修饰符
1)在正则表达式中,可以用一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。

import re
content ='Hello 1234567 World_This is.a Regex Demo'
result =re.match('^He.*?(\d+).*?Demo$',content)
print(result.group(1))
注意:当遇到换行符时,.*?就不能匹配。

2)常用修饰符

(7)转义匹配
解决目标字符串里面就包含.这个字符的问题(.用于匹配除换行符以外的任意字符)
import re
content ='(百度)www.baidu.com'
result = re.match('\(百度\)www\.baidu\.com',content)
print(result)

说明:当在目标字符串中遇到用作正则匹配模式的特殊字符时,在此字符前面加反斜线\转义一下即可。例如\.就可以用来匹配.。

import re#(非必要)
content ='Extra stings Hello 1234567 World This is a Regex Demo Extra   stings'
result = re.match('Hello.*?(\d+).*?Demo',content)
print(result)

match方法的适用:在使用时需要考虑目标字符串开头的内容,因此在做匹配时并不方便。它更适合检测某个字符串是否符合某个正则表达式的规则。

2.3.3 search

(1)基本原理
在匹配时会扫描整个字符串,然后返回第一个匹配成功的结果。也就是说,正则表达式可以是字符串的一部分;
在匹配时,search方法会依次以每个字符作为开头扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容;
如果扫描完还没有找到符合规则的字符串,就返回None

(2)实例分析
1)待匹配html文本
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>'''

2)思路

第一步,观察html。ul节点里有许多li节点,这些li节点中有的包含a节点,有的不包含。a节点还有一些相应的属性——超链接和歌手名。
第二步,提取节点内容。尝试提取class为active的li节点内部的超链接包含的歌手名和歌名。也就是说需要提取第三个li节点下a节点的singer属性和文本。
第三步,匹配分析。正则表达式可以以li开头,然后寻找一个标志符active,中间的部分可以用.*?来匹配。接下来,因为要提取singer这个属性值,所以还需要写入singer=”(.*?)”,这里把需要提取的部分用小括号括了起来,以便用group方法提取出来,小括号的两侧边界是双引号。
第四步,边界确定。然后还需要匹配a节点的文本,此文本的左边界是>,右边界是</a>。然后目标内容依然用(.*?)来匹配。
第五步,编写正则表达式。正则表达式为:<li.*?active.*?singer="(.*?)">(.*?)</a>
第六步,调用search方法。它会搜索整个HTML文本,找到符合上述正则表达式的第一个内容并返回。

3)结果分析
result =re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S)
if result:
    print(result.group(1),result.group(2))

注意:search方法会返回第一个符合条件的匹配目标。

2.3.5 findall
(1)概述
解决想要获取与正则表达式相匹配的所有字符串,就要借助findal1方法。
(2)实例分析
以上面HTML文本为例,获取其中所有a节点的超链接、歌手和歌名。

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])

链接:如果只想获取匹配到的第一个字符串,可以用search方法;如果需要提取多个内容,可以用findall方法

2.3.4 sub

(1)概述
除了使用正则表达式提取信息,有时候还需要借助它来修改文本。例如,想要把一串文本中的所有数字都去掉,如果只用字符串的replace方法,略显麻烦,可以借助sub方法。
sub方法的第一个参数中传入\d+以匹配所有的数字,往第二个参数中传入把数字替换成的字符串(如果去掉该参数,可以赋值为空),第三个参数是原字符串。
(2)实例分析
1)sub替换用法
import re
content ='54aK54yr5oiR54ix5L2g'
content =re.sub('\d+','',content)
print(content)

2)获取所有li节点的歌名,直接用正则表达式来提取的烦琐写法
results =re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>',html,re.S)
for result in results:
    print(result[1])

3)sub方法获取所有li节点的歌名的用法
思路:先用sub方法将a节点去掉,只留下文本,然后再利用findall提取就
html=re.sub('<a.*?>|</a>','',html)
print(html)
results =re.findall('<li.*?>(.*?)</li>',html,re.S)
for result in results:
    print(result.strip())

2.3.5 compile

(1)概述
(1-6)都是用来处理字符串的方法,将正则字符串编译成正则表达式对象需要用到compile方法,以便在后面的匹配中复用。
(2)实例分析
import re
content1 ='2019-12-15 12:00'
content2 ='2019-12-17 12:55'
content3 ='2019-12-22 13:21'
pattern =re.compile('\d{2}:\d{2}')
result1 =re.sub(pattern,'',content1)
result2 =re.sub(pattern,'',content2)
result3 =re.sub(pattern,'',content3)
print(result1,result2,result3)


操作思路:
需要将3个日期中的时间去掉,可以借助sub方法。
该方法的第一个参数是正则表达式,但是这里没有必要重复写3个同样的正则表达式,此时就可以借助compile方法将正则表达式编译成一个正则表达式对象,以便复用。

链接:compile还可以传入修饰符,例如re.S等修饰符,这样在search、findall等方法中就不需要额外传了。可以说compile方法是给正则表达式做了一层封装,以便我们更好地复用。

  • 33
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值