当前位置:   article > 正文

更适合爬虫的正则表达式

更适合爬虫的正则表达式

1. 认识正则表达式

1.1 正则表达式的匹配规则

模式描述
\w匹配字母、数字、下划线
\W匹配非字母、数字、下划线
\s匹配任何空白字符,包括空格、制表符、换页符等等
\S匹配任何非空白字符
\d匹配一个数字字符
\D匹配一个非数字字符
^匹配输入字符串的开始位置。
$匹配输入字符串的结束位置
.匹配任意字符,除了换行符,当re.DOTALL标记被指定时,可以匹配包括换行符的任意字符
*匹配前面的子表达式零次或多次
?匹配前面的子表达式零次或一次
+匹配前面的子表达式一次或多次
a|b匹配a或b
()匹配括号内的表达式,也表示一个组
\对匹配内容的特殊字符做保留 ,即转义匹配

1.2 贪婪匹配和非贪婪匹配

贪婪匹配:
符号:.*
表示为匹配尽可能符合要求的字符

非贪婪匹配:
符号: .*?
表示为匹配尽可能少的符合要求的字符

比如:

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match(r'^He.*(\d+).*Demo$', content)
print(result)
print(result.group(1))

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match(r'^He.*?(\d+).*Demo$', content)
print(result)
print(result.group(1))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

输出结果:

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
7
<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567
  • 1
  • 2
  • 3
  • 4

输出解释:
       对于第一个输出,我们使用的是.*的方式来正则字符串,对于.*而言,它会尽量匹配更多的符合要求的字符串,而.*后面的是 \d+,也就是至少会留一个数字给到 \d+,于是.*就把前面的123456都匹配掉,只留一个7给到 \d+,当使用group(1)方法时,访问的是(\d+),这个时候输出的就只有 7 了。
       对于第二个输出就不一样,使用.*?的方式来正则字符串,使用非贪婪的方式,.*?只会匹配到符合要求更少的字符串,当.*?匹配到hellow的空格字符时,就停止匹配,因为后面的数字部分,可以留给(\d+)来匹配,于是在使用group(1)方法时,访问(\d+),这个时候输出就会出现1234567。

总结:
       在匹配的时候,字符串中间使用非贪婪匹配,但是当匹配字符串的结果在字符串末尾时,要用贪婪匹配。

1.3 修饰符匹配

在HTML结点中,会存在很多的修饰符,比如换行,这会妨碍数据的获取,所以要对修饰符的存在进行处理。
这里只介绍两种常见的修饰符处理:

修饰符描述
re.I使匹配内容对大小写不敏感
re.S使匹配内容包括换行符在内的所有字符

2. 匹配方法

这里介绍两个常用匹配方式 2.1 re.search()方法,re.findall()方法,不对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="邓丽君">但愿人长久</a>
		</li>
	</ul>
</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2.1 re.search()方法

原理:search方法首先会扫描字符串,搜寻符合匹配规则的字符串,如果没有,则返回None,如果存在,则返回第一个匹配成功的结果的内容

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>'''
import re
# 查询li中标识符为active的元素,获取其a标签里面的singer的值,获取a标签内的文字部分
result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
    print(result.group(1), result.group(2))		#输出:齐秦 往事随风

# 查询li中的第一个singer的值,和a标签里面的文字    
result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
    print(result.group(1), result.group(2))		#输出:任启贤 沧海一声笑

# 查询li中的第一个singer的值,和a标签里面的文字,与上面不同的是,这里缺少了re.S参数,这这里查询的是没有换行符的第一个符合要求的li对象
result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html)
if result:
    print(result.group(1), result.group(2))		#输出:beyond 光辉岁月
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

2.2 re.findall()方法

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

# 查询元素li中所有的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])	# 打印一个元组里面的所有元素
    
# 输出:
#[('/2.mp3', '任贤齐', '沧海一声笑'), ('/3.mp3', '齐秦', '往事随风'), ('/4.mp3', 'beyond', '光辉岁月'), ('/5.mp3', '陈慧琳', '记事本'), ('/6.mp3', '邓丽君', '但愿人长久')]
#<class 'list'>
#('/2.mp3', '任贤齐', '沧海一声笑')
#/2.mp3 任贤齐 沧海一声笑
#('/3.mp3', '齐秦', '往事随风')
#/3.mp3 齐秦 往事随风
#('/4.mp3', 'beyond', '光辉岁月')
#/4.mp3 beyond 光辉岁月
#('/5.mp3', '陈慧琳', '记事本')
#/5.mp3 陈慧琳 记事本
#('/6.mp3', '邓丽君', '但愿人长久')
#/6.mp3 邓丽君 但愿人长久

# 查询所有li元素中a结点的歌名
results = re.findall(r'<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>', html, re.S)
for result in results:
    print(result[1])

# 输出:
#一路上有你
#沧海一声笑
#往事随风
#光辉岁月
#记事本
#但愿人长久
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

2.3 re.sub()方法

将获取到的文本内容进行删除部分内容等
sub()方法里面含三个参数

  1. 匹配规则
  2. 将符合匹配规则的字符替换成的字符串(如果要去掉的话,则可以赋值为空 ‘’)
  3. 匹配的字符串对象
import re

content = '54aK54yr5oiR54ix5L2g'
content = re.sub(r'\d+', '', content)
print(content)	
# 输出:aKyroiRixLg
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.4 re.compile()方法

将正则的部分实例化,避免代码重复书写正则表达式。

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)

# 输出:
# 2019-12-15  2019-12-17  2019-12-22 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/630235
推荐阅读
相关标签
  

闽ICP备14008679号