置顶:华为云618大促火热进行中,全场1折起,免费抽主机,消费满额送P30 Pro,点此抢购

正则表达式是处理字符串的强大工具,它有自己特定的语法结构,有了它,实现字符串的检索、替换、匹配验证都不在话下。对于爬虫,基于正则表达式,从HTML里提取想要的信息就非常方便了。

正则表达式有特定的语法规则的。写好正则表达式后,就可以拿它去一个长字符串里匹配查找了。不论这个字符串里面有什么,只要符合我们写的规则,统统可以找出来。对于网页来说,如果想找出网页源代码里有多少URL,用匹配URL的正则表达式去匹配即可。下图就列出了正则表达式常用的匹配规则。

正则表达式不是Python独有的,它可以用在其他编程语言中。在Python中,re库提供了整个正则表达式的实现,利用这个库,可以在Python中使用正则表达式。在Python中写正则表达式几乎都用这个库,下面就来了解它的一些常用方法。

match()

match()传入要匹配的字符串以及正则表达式,就可以检测这个正则表达式是否匹配字符串。match()方法会尝试从字符串的起始位置匹配正则表达式,如果匹配,就返回匹配成功的结果,如果不匹配,就返回None。

 import re

 content = 'Blog:hy592070616 Corporation:HUAWEI'
result = re.match('Blog:\w{11}', content)
print(result.group())

运行结果:

Blog:hy592070616

这里首先声明了一个字符串 'Blog:hy592070616 Corporation:HUAWEI',其中包含英文字母、空格、数字、冒号等。接下来,我们写一个正则表达式'Blog:\w{11}'来匹配这个字符串。正则表达式中Blog:就是待匹配字符串的开头,\w通过查上表可知是匹配字母、数字及下划线,\w后面跟着{11}表示匹配11个\w。根据这个规则就可以从字符串 'Blog:hy592070616 Corporation:HUAWEI'中匹配出字符串Blog:hy592070616。同样,我们可以加入\s来匹配空格,\d来匹配数字以匹配整个字符串。

 import re

 content = 'Blog:hy592070616 Corporation:HUAWEI'
result = re.match('\w{4}:\w{2}\d{9}\s\w{11}:\w{6}', content)
print(result.group())

运行结果:

Blog:hy592070616 Corporation:HUAWEI

当然,做这种简单的任务我们可以用\S来匹配任意非空字符达到相同的效果。

 import re

 content = 'Blog:hy592070616 Corporation:HUAWEI'
result = re.match('\S{16}\s\S{18}', content)
print(result.group())

上面几种正则表达式比较复杂,出现空白字符我们就写\s匹配,出现数字我们就用\d匹配,这样的工作量非常大。其实完全没必要这么做,在上表中有一个万能匹配.*。其中,.可以匹配任意字符(除换行符),*代表字符无限次,所以它们组合在一起就可以匹配任意字符了。有了.*,我们就不用挨个字符地匹配了。

 import re

 content = 'Blog:hy592070616 Corporation:HUAWEI'
result = re.match('B.*I', content)
print(result.group())

正则表达式B.*I中的BI代表了字符串Blog:hy592070616 Corporation:HUAWEI首位两个字符,其它的字符均用.*来进行匹配。我们就可以得到相同的结果:

Blog:hy592070616 Corporation:HUAWEI

如果想从字符串中提取一部分内容,可以使用()将想提取的子字符串括起来。()实际上标记了一个子表达式的开始和结束位置,被标记的每个子表达式会依次对应每一个分组,调用group()方法传入分组的索引即可获取提取的结果。

 import re

 content = 'Blog:hy592070616 Corporation:HUAWEI'
result = re.match('\w{4}:\w\w(\d+)', content)
print(result.group())

运行结果:


可以看到,我们成功得到了592070616。这里用的是group(1),它与group()有所不同。group()会输出完整的匹配结果,而group(1)会输出第一个被()包围的匹配结果。假如正则表达式后面还有()包括的内容,那么可以依次用group(2)、group(3)等来获取。

若使用.*匹配时,有时候匹配到的并不是我们想要的结果。

 import re

 content = 'Blog:hy592070616 Corporation:HUAWEI'
result = re.match('B.*(\d+)', content)
print(result.group())

运行结果为:

 

很明显,我们希望提取的是592070616,而此处由于我们用了万能匹配符.*在语句中,正则表达式就会匹配59207061,所以在括号中我们就只能提取到一个数字6。这里就涉及一个贪婪匹配与非贪婪匹配的问题了。在贪婪匹配下,.*会匹配尽可能多的字符。正则表达式中.*后面是\d+,也就是至少一个数字,并没有指定具体多少个数字,因此,.*就尽可能匹配多的字符,这里就把59207061给匹配了,给\d+留下一个可满足条件的数字6。这很明显会给我们带来很大的不便。有时候,匹配结果会莫名其妙少了一部分内容。其实,这里只需要使用非贪婪匹配就好了。非贪婪匹配的写法是.*?,我们需要将将第一个.*改成了.*?就可以转变为非贪婪匹配。

 import re

 content = 'Blog:hy592070616 Corporation:HUAWEI'
result = re.match('B.*?(\d+)', content)
print(result.group())

结果如下:


match()还有个可选参数修饰符,修饰符可以扩展正则表达式的匹配范围。

比如,在字符串Blog:hy592070616 Corporation:HUAWEI中加入换行,将其变为:

 Blog:hy592070616
Corporation:HUAWEI

用之前的方法就没有办法对其进行匹配:

 import re

 content = '''Blog:hy592070616
Corporation:HUAWEI
'''
result = re.match('B.*I', content)
print(result.group())

这里的result就会返回一个None,因为.*无法匹配换行符。我们只需在match()中的第三个参数加一个修饰符re.S,即可修正这个错误。

 import re

 content = '''Blog:hy592070616
Corporation:HUAWEI
'''
result = re.match('B.*I', content, re.S)
print(result.group())

这样就可以正常返回结果:

 Blog:hy592070616
Corporation:HUAWEI

search()

match()方法是从字符串的开头开始匹配的,一旦开头不匹配,那么整个匹配就失败了。而search()方法在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果。也就是说,正则表达式可以是字符串的一部分,在匹配时,search()方法会依次扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容,如果搜索完了还没有找到,就返回None。比如我们要匹配字符串Blog:hy592070616 Corporation:HUAWEI中的HUAWEI:

 import re

 content = 'Blog:hy592070616 Corporation:HUAWEI'
result = re.search('Corporation:(\w+)', content)
print(result.group())

就可以得到HUAWEI结果,而不需要将字符串前部全部匹配。

findall()

search()方法可以返回匹配正则表达式的第一个内容,但是如果想要获取匹配正则表达式的所有内容,就需要findall()方法。该方法会搜索整个字符串,然后返回匹配正则表达式的所有内容并返回列表。假设我们有HTML文件:

 <div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="">一路上有你</li>
<li data-view="">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view=""><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view=""><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="">
<a href="/6.mp3" singer="邓丽君"><i class="fa fa-user"></i>但愿人长久</a>
</li>
</ul>
</div>

我们希望提取歌手和歌名的信息,则可以:

 import re

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

我们可以看到,大部分的歌手和歌名是singer="歌手">歌名</a>的形式,则我们可以写正则表达式singer="(\w+)">(\w+)</a>。但是我们发现有一条 singer="邓丽君"><i class="fa fa-user"></i>但愿人长久</a>中有其他信息,使用上述的正则表达式这无法匹配出(邓丽君,但愿人长久)这个信息。基于这个问题,我们可以将正则表达式修改为singer="(\w+).*>(\w+)</a>(上述代码中的正则表达式),就可以顺利匹配出所有信息了。

 [('任贤齐', '沧海一声笑'), ('齐秦', '往事随风'), ('beyond', '光辉岁月'), ('陈慧琳', '记事本'), ('邓丽君', '但愿人长久')]

sub()

除了使用正则表达式提取信息外,有时候还需要借助它来修改文本。比如,想要把一串文本中的所有数字都去掉,这时就可以借助sub()方法。比如,我想将字符串Blog:hy592070616 Corporation:HUAWEI中的Corporation:HUAWEI去掉,就可以匹配Corporation:HUAWEI并用空的字符串替换。

 import re

 content = 'Blog:hy592070616 Corporation:HUAWEI'
result = re.sub('Corporation:.*', '',content)
print(result)

结果如下:

Blog:hy592070616

compile()

除了前面提到的处理字符串的方法以外,最后再介绍一下compile()方法,这个方法可以将正则字符串编译成正则表达式对象,以便在后面的匹配中复用。

 import re

 content1 = '2019-01-01 12:00'
content2 = '2019-01-02 12:30'
content3 = '2019-01-03 13:00'
pattern = re.compile('(\d+)-(\d+)-(\d+)\s.*')
result_1 = re.match(pattern, content1)
result_2 = re.match(pattern, content2)
result_3 = re.match(pattern, content3)
print('Year:' + result_1.group() + ' Month:' + result_1.group() + ' Day:' + result_1.group())
print('Year:' + result_2.group() + ' Month:' + result_2.group() + ' Day:' + result_2.group())
print('Year:' + result_3.group() + ' Month:' + result_3.group() + ' Day:' + result_3.group())

这里为了找到各个字符串中的年月日信息构建了正则表达式对象(\d+)-(\d+)-(\d+)\s.*以复用,输出结果如下:

 import re

 content1 = '2019-01-01 12:00'
content2 = '2019-01-02 12:30'
content3 = '2019-01-03 13:00'
pattern = re.compile('(\d+)-(\d+)-(\d+)\s.*')
result_1 = re.match(pattern, content1)
result_2 = re.match(pattern, content2)
result_3 = re.match(pattern, content3)
print('Year:' + result_1.group() + ' Month:' + result_1.group() + ' Day:' + result_1.group())
print('Year:' + result_2.group() + ' Month:' + result_2.group() + ' Day:' + result_2.group())
print('Year:' + result_3.group() + ' Month:' + result_3.group() + ' Day:' + result_3.group())

私货时间:华为云618大促火热进行中,全场1折起,免费抽主机,消费满额送P30 Pro,点此抢购

来源:CSDN 作者:洪远

HDC.Cloud 华为开发者大会2020 即将于2020年2月11日-12日在深圳举办,是一线开发者学习实践鲲鹏通用计算、昇腾AI计算、数据库、区块链、云原生、5G等ICT开放能力的最佳舞台。

欢迎报名参会

Python爬虫从入门到精通——基本库re的使用:正则表达式【华为云技术分享】的更多相关文章

  1. Python 中拼音库 PyPinyin 的用法【华为云技术分享】

    [摘要] 最近碰到了一个问题,项目中很多文件都是接手过来的中文命名的一些素材,结果在部署的时候文件名全都乱码了,导致项目无法正常运行. 后来请教了一位大佬怎么解决文件名乱码的问题,他说这个需要正面解决 ...

  2. Python爬虫帮你打包下载所有抖音好听的背景音乐,还不快收藏一起听歌【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  3. Python开发GUI工具介绍,实战:将图片转化为素描画!【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  4. 【Python3网络爬虫开发实战】6.4-分析Ajax爬取今日头条街拍美图【华为云技术分享】

    [摘要] 本节中,我们以今日头条为例来尝试通过分析Ajax请求来抓取网页数据的方法.这次要抓取的目标是今日头条的街拍美图,抓取完成之后,将每组图片分文件夹下载到本地并保存下来. 1. 准备工作 在本节 ...

  5. 这个七夕节,用Python为女友绘制一张爱心照片墙吧!【华为云技术分享】

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字“加群”,加入华为云线上技术讨论群:输入关键字“最新活动”,获取华为云最新特惠促销.华为云诸多技术大咖.特 ...

  6. 图库网站Unsplash高清原图爬虫【华为云技术分享】

    [摘要] 写博客的好工具,快速获得高清图片 在百度图片爬虫小助手里,我开发了一个爬虫,来节约我写博客时搜集图片的时间. 但是,也出现了一些问题,主要有以下几点: 百度图片上的质量参差不齐,大部分图片质 ...

  7. Python正则表达式,看完这篇文章就够了...#华为云&#183;寻找黑马程序员#【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  8. Python面试的一些心得,与Python练习题分享【华为云技术分享】

    版权声明:本文为CSDN博主「华为云」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/devcloud/arti ...

  9. 用python读取word文件里的表格信息【华为云技术分享】

    在企查查查询企业信息的时候,得到了一些word文件,里面有些控股企业的数据放在表格里,需要我们将其提取出来. word文件看起来很复杂,不方便进行结构化.实际上,一个word文档中大概有这么几种类型的 ...

随机推荐

  1. SJ定理的坑点

    目录 \(\bf Anti-Nim\) 定义 结论 \(\bf Anti-SG\) 定义 SJ 定理 由于出题人在膜你赛出了假题,于是就发现了这个坑点-- 反正这个出题人出的都是假题 我感觉这个好像大 ...

  2. Spark安装与学习

    http://www.cnblogs.com/jerrylead/archive/2012/08/13/2636115.html

  3. Asp.net Core 系列之--3.领域、仓储、服务简单实现

    ChuanGoing 2019-11-11  距离上篇近两个月时间,一方面时因为其他事情耽搁,另一方面也是之前准备不足,关于领域驱动有几个地方没有想通透,也就没有继续码字.目前网络包括园子里大多领域驱 ...

  4. 利用DI实现级联删除 - xms跨平台基础框架 - 基于.netcore

    一.引言 所谓级联删除是指删除一条记录后,附带关联记录也一起删除,比如删除客户后,联系人也一起删除: 以往我们会依赖于数据库表的外键约束,但存在着明显的问题,增加数据库压力.提示不友好.职责越界.事务 ...

  5. python——inspect模块

    inspect模块常用功能 import inspect # 导入inspect模块 inspect.isfunction(fn) # 检测fn是不是函数 inspect.isgenerator((x ...

  6. 易初大数据 spss 2019年10月31日 wangqingchao

    ---恢复内容开始--- 1.描述性统计分析方法是指应用分类.制表.图形及概括性数据指标来概括数据分析特征的方法. 2.而推断性统计分析方法则是通过随机抽样,应用统计方法把从样本数据得到的结论推广到总 ...

  7. [LC]206题 Reverse Linked List (反转链表)(链表)

    ①英文题目 Reverse a singly linked list. Example: Input: 1->2->3->4->5->NULL Output: 5-> ...

  8. Cache地址映射

    原理:程序访问局部性         在较短时间内由程序产生的地址往往集中在存储器逻辑地址空间的很小范围内         时间:在一小段时间内,最近被访问过的程序和数据很可能再次被访问       ...

  9. 力扣(LeetCode)验证回文字符串II 个人题解

    给定一个非空字符串 s,最多删除一个字符.判断是否能成为回文字符串. 示例 1: 输入: "aba" 输出: True 示例 2: 输入: "abca" 输出: ...

  10. Linux基础命令复习01

    一.Linux中的基本查看.查找命令: 1.ls 查看目录信息:  -l  #查看属性,以长格式显示 -d #查看本身属性 -A #显示包括以.开头的隐藏文档 -h #提供易读的单位 -R  #表示递 ...