目录
2. 代码实例一:获取下图所示的新闻链接和标题(考虑自动换行)
3. 代码实例二:获取下图所示的新闻链接和标题(考虑自动换行)
一、什么是正则表达式
正则表达式(regular expression)是用来进行较为复杂的文本处理,特别是复杂的查找和替换处理的计算机语言。我们在进行计算机编程或者文本处理时,通常需要进行一些文本的查找、替换。如果查找或替换的工作比较复杂,就需要借助正则表达式来完成。此外,我们需要对文本进行清洁处理或者提取文本的特定信息时,也需要使用正则表达式。
简单来说,正则表达式就是一个提取信息的手段,它可以帮助提取文本中所需信息,而且掌握了正则表达式后,不仅可以在爬虫中运用它来提取网页信息,在普通的文本信息中,也可以通过正则表达式来提取所需的内容,这是BeautifulSoup、pquery和Xpath这些专门用来解析网页源代码的库所不能比拟的。
在Python中使用正则表达式需要引入re模块,引入re模块需要使用import re语句。引入re模块后,即可通过下列犯法来使用正则表达式。re模块常用的方法有:re.search()、re.findall()和re.sub()等。
二、正则表达式基础1:re.findall()方法
1. re.findall方法的使用规则
简单来说,re.findall()方法是根据匹配规则在原始文本中找寻合适的内容:
2. 提取文本中的数字
‘\d’表示匹配一个数字,‘\d\d\d’就表示匹配三个数字,所以re.findall('\d\d\d', content)就是在content中寻找连续的三个数字,最后findall会得到一个列表。
实例1:提取文本中的数字
import re
content = 'Hello world 123'
result = re.findall('\d\d\d',content)
print(result)
>>> ['123']
实例2:提取文本中的所有3位数字
import re
content = 'Hello world 123 python 456 study 789'
result = re.findall('\d\d\d',content)
print(result)
可以看到,findall最后得到其实是一个列表,如果我们想获取列表中的某个元素,那么就需要使用list[i]的方法来获取我们想要的信息:
a1 = result[0] #注意列表的一个元素的序号是0
print(a1)
a2 = result[1]
print(a2)
a3 = result[2]
print(a3)
逐行打印findall爬到的所有内容的方法是:
for i in result:
print(i)
三、正则表达式基础2:非贪婪匹配(.*?)
有非贪婪匹配,那就就有贪婪匹配,这两个术语听起来很吓人,但这就是正则表达式的两种模式,也很容易解释:
- 贪婪匹配:尽可能匹配匹配最长的字符串。
- 非贪婪匹配:尽可能匹配最短的字符串。
在实际应用中,我们应用的最多的还是非贪婪匹配。
1. 常用的匹配规则的符号
模式 | 描述 |
\d | 匹配一个数字字符 |
\w | 匹配一个字母、数字及下划线字符 |
\s | 匹配一个空白字符 |
\S | 匹配一个非空白字符 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
. | 匹配一个任意的字符,换行符除外 |
* | 匹配前面的字符无限次直到停止 |
? | 常和.与*配合使用,组成非贪婪匹配 |
() | 匹配括号内的表达式,也表示一个组 |
但在爬虫实战中,大部分情况下需要用到的只有这两种情况:(.*?)与.*?。
"\n"表示输出一个换行符,相当于你在编辑WORD时用到的Enter键
"\t"表示后退一个制表符,相当于按一下Tab键或者是按八下空格键
2. 非贪婪匹配(.*?)(正则表达式核心内容)
简单来说(.*?)的作用就是来找到你想要的东西,同时你不确定它的长度以及格式,但是知道它大概在哪两块内容中间,这时就可以用(.*?)来获取。
其中.表示除了换行符外的任意字符,*表示0个或多个表达式,两者合在一起叫做贪婪匹配.*,贪婪匹配的话会“贪婪”地匹配,也就是会匹配到过多的内容。如果加上一个问号构成.*?即构成非贪婪匹配,则会较精确地匹配到想要的内容,对于贪婪和非贪婪这个概念了解即可,通常都是用非贪婪匹配。
如上图所示,(.*?)就是用来获取文本A与文本B之间的内容,我们并不需要知道这个内容到底有多长以及它里面是否有什么乱七八糟的字符。
实例1:单个文本提取
在实际应用中,我们一般不把匹配规则直接写到findall后面的括号里,而是拆成两行来写,先写匹配规则,然后写findall语句。因为有的时候匹配规则会比较长,分开写会比较清晰。
import re
res = '文本A百度新闻文本B'
p_source = '文本A(.*?)文本B'
source = re.findall(p_source, res)
print(source)
>>> ['百度新闻']
实例2:多个文本提取
在实际应用中,符合文本A(.*?)文本B的匹配规则内容通常不止一个,这时我们就要提取多个符合规则的内容。
import re
res = '文本A百度新闻文本B,新闻标题文本A腾讯新闻文本B,文本A搜狐新闻文本B新闻网址'
p_source = '文本A(.*?)文本B'
source = re.findall(p_source, res)
print(source)
实例3:(下面我们通过实例来展示一下,如下图所示,我们想提取其中的新闻标题信息。)
利用非贪婪匹配提取信息最重要的一点就是寻找到定位所需内容的文本A和文本B。在这里可以看到新闻标题在一个<h2 class="index-module_articleTitle_28fPT">的框里,class表示类别,同一类别的框里存储的是类似的内容,那么利用<h2 class="index-module_articleTitle_28fPT">和</h2>就可以作为寻找新闻标题一个强定位条件,演示代码如下:
import re
res = '<h2 class="index-module_articleTitle_28fPT">不仅要把权力关进笼子里,更要把资本关进笼子里。</h2>'
title = '<h2 class="index-module_articleTitle_28fPT">(.*?)</h2>'
info = re.findall(title,res)
print(info)
四、 正则表达式基础3:非贪婪匹配 .*?
1. 非贪婪匹配 .*?(正则表达式核心内容)
简单来说.*?是表示文本C和文本D之间的内容,因为我们不想写太多的东西或者说文本C和文本D中间的内容其实是经常变动的,那么我们就需要用这个方法来获取我们需要的内容。在爬虫实战中,一直变化的东西用.*?来代替就好了。
2. 非贪婪匹配实例
很多时候新闻标题和新闻链接靠的非常近,下图我们可以看到这个新闻链接和新闻标题其实都是在<h3 class=“news-title_1YtI1”>这个框内。
我们要得到这个新闻的标题就可以这样输入代码运行一下:
import re
res = '<h3 class="news-title_1YtI1"><a href="https://baijiahao.baidu.com/s?id=1707670655196285835&wfr=spider&for=pc" target="_blank" class="news-title-font_1xS-F" data-click="{一堆英文}"><em>阿里巴巴</em>传巨响轰动!市值蒸发逾1826亿元 南向资金..</a>'
news = '<h3 class="news-title_1YtI1">.*?>(.*?)</a>'
title = re.findall(news, res)
print(title)
3. 非贪婪匹配 (.*?)和.*?的含义与区别
- (.*?)是用来获取文本A与文本B之间的内容,其作用就是来找到想要的内容,同时不确定它的长度以及格式,但是知道它在哪两块内容中间。
- .*?是用来表示文本C和文本D之间的内容,这个内容有可能是经常变动的。
五、正则表达式基础4 : 自动考虑换行
1. re.S修饰符
re.S唯一的作用,就是在findall查找的时候,可以自动考虑到换行,能自动考虑网页源代码换行。它的使用方法如下:
2. 代码实例一:获取下图所示的新闻链接和标题(考虑自动换行)
import re
res = '''<h3 class="c-title">
<a href="http://news.sina.com.cn/o/2018-12-12/doc-ihqackaa4351174.shtml"
data-click="{
'f0':'77A717EA',
'f1':'9F63F1E4',
'f2':'4CA6DD6E',
'f3':'54E5343F',
't':'1544622684'
}"
target="_blank"
>
<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部
</a>
'''
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
href = re.findall(p_href, res,re.S) # 使用re.S换行修饰符,这样就不用考虑源代码里有换行的问题
title = re.findall(p_title, res,re.S)
print(href)
print(title)
运行结果:(通过上述代码,就可以轻松获取到该网页的网址链接和新闻标题了)
3. 代码实例二:获取下图所示的新闻链接和标题(考虑自动换行)
代码:
import re
res = '''
<li>
<a href="http://baijiahao.baidu.com/s?id=1702270079582494113" mon="col=3&a=2&pn=4" target="_blank">鸿蒙概念热度空前 龙头股提示风险后仍斩获三连板</a>
</li>
'''
p_href = '<li>.*?<a href="(.*?)"'
p_title = '<li>.*?>(.*?)</a>'
href = re.findall(p_href, res,re.S) # 使用re.S换行修饰符,这样就不用考虑源代码里有换行的问题
title = re.findall(p_title, res,re.S)
print(href)
print(title)
六、正则表达式基础5 :小知识点补充
1. re. sub()方法
re.sub()方法,它是英文substitute(替换)的缩写,它的具体使用格式是:
re.sub(需要替换的内容,替换值,原字符串)
re.sub()方法主要就是用来处理正则表达式获取到的内容,比如说,我们之前获取的到的新闻标题,其实有点瑕疵:
那么我们就可以用re.sub()方法将其替换掉,具体代码如下:
title = ['<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部']
title[0] = re.sub('<.*?>', '', title[0]) # 用.*?方式来替代< >之间的文本,替换值为空
print(title[0])
对于第二行代码,可以通过一幅图片来进行理解:
2. 中括号[ ]的用法
功能一:在中括号里的内容不再有特殊含义。
例:比如我们想去掉“广州大学”周围的“?”,就可以用一下代码进行去除:
功能二:表示某几个的范围,比如我们想把爬到的日期里的“年月日”通通都换成“-”号,那么通过下面的方法就可以做到。
方法1:
date = '2021年6月11日'
date = re.sub('[年月日]', '-', date)
date = date[:-1] # 取该字符串除了最后一个元素的其他元素
print(date)
方法2:
date = '2021年6月11日'
date = re.sub('年', '-', date)
date = re.sub('月', '-', date)
date = re.sub('日', '', date)
print(date)
图片来源:本篇博客部分图片来源于《华小智Python系列课程》中,仅供自身学习记录,不用做任何商业用途。