python网络爬虫之三re正则表达式模块
"""
re正则表达式,正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的
一些特定字符,及这些特定字符的组合,组成一个"规则字符串",然后用这个"规则
字符串"去匹配过滤出我们想要的字符串。
"""
我们可以利用工具来测试或者生成我们想要的"规则字符串"。
正则表达式常见的匹配模式:
匹配模式 描述
^ 匹配字符串的开头
$ 匹配字符串的结尾
. 表示匹配任意一个字符,除了换行符,当re.DOTALL标记被指定时,则表示匹配包括
换行符在内的任意字符。
* 表示匹配任意多个前面的表达式,通常.*用来表示任意的字符。
? 非贪婪匹配,通常用.*?表示非贪婪匹配。
a|b 表示匹配a或b
() 匹配括号内的一个表达式,也表示匹配一个组
\s 匹配任意空白字符,也通常用来表示空白换行符。
\w 表示可以匹配一个字符串,匹配字母数字及下划线,或者中文字符都可以。\w+可以表示匹配任意多个字符
\W 匹配非字母数字及下划线
\S 匹配任意非空字符
\d 匹配任意数字,等价与[0-9],注:\为转移字符,d表示数字,而\d+可以表示任意的数字。
\D 匹配任意非数字
\A 匹配字符串开始
\n 匹配一个换行符
\t 匹配一个制表符 + 匹配一个或多个表达式 {n} 精确匹配前面的n个表达式
{n,m} 贪婪模式,匹配前面的n到m次前面的表达式 常用的正则表达式匹配标志位:
正则表达式的匹配标志位可以用来控制正则表达式的匹配模式,这个匹配标志位是可选的,多个正则表达式的
匹配标志位可以用OR或|来链接指定他们,如re.S|re.M
常用的正则表达式匹配标志位有:
re.DOTALL :用来表示.可以匹配包括换行符在内的任意字符,正常情况下.是不能匹配换行符的。
re.S :同re.DOTALL一样,也用来表示.可以匹配包括换行符在内的任意字符,正常情况下.是不能匹配
换行符的,用这两个哪个都可以。
re.M :表示多行匹配,影响^和$
re.l :表示匹配对大小写不敏感
re.U :根据Unicode字符集解析字符,这个影响标志位\w,\W,\b,\B。
re.L :做本地化识别匹配
re.X :可以更改正则表达式的格式以便我们更方便理解查看 常用的匹配方法:re.match re.search re.findall re.sub re.compile re.finditer re.split 这些常用的匹配方法返回的结果分别是:
1. re.compile re.compile() 是将正则表达封装并返回正则表达式对象,这样更方便我们理解阅读。
2. re.match #返回一个字符串
3. re.search #返回一个字符串
4. re.findall #返回一个字符串
5. re.sub
6. re.finditer
7. re.split 一. re.compile
re.compile函数用来编译正则表达式,用来将正则表达式编译成一个正则表达式对象,供后面的几个
正则表达式匹配函数使用。
re.compile语法:
re.compile(pattern[,flags])
注:pattern表示一个字符串形式的正则表达式,flags表示正则表达式标志位,这个参数可选。
我们可以用re.compile返回的这个正则表达式对象去匹配我们想要的函数,这样的话我们就方便
了代码的复用和调用:
如下所示:
import re
content = "Hello 1234567 World_This
is a Regex Demo"
pattern = re.compile('Hello.*Demo',re.S)
result = re.match(pattern,content)
print(result) 二. re.match
re.match函数尝试从字符串的起始位置去匹配一个字符串,如果不是从起始位置匹配成功的话,
re.match函数就返回一个none。
re.match(patter,string,flags=0) #1.最常规的匹配:
import re
content = "Hello 123 4567 World_This is a Regex Demo"
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$',content)
print(result)
print(result.group())
print(result.span()) #2.匹配目标,用()来指定我们的匹配目标:
import re
content = "Hello 1234567 World_This is a Regex Demo"
result = re.match('^Hello\s(\d+)\sWorld.*Demo$',content)
print(result)
print(result.group(1))
print(result.span()) #3.泛匹配,用.*表示所有的匹配字符:
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()) #4.贪婪匹配:
import re
content = "Hello 1234567 World_This is a Regex Demo"
result = re.match('^Hello\s(\d+)\sWorld.*Demo$',content)
print(result)
print(result.group(1))
print(result.span()) #5.非贪婪匹配:
import re
content = "Hello 1234567 World_This is a Regex Demo"
result = re.match('^Hello\s(\d+)\sWorld.*Demo$',content)
print(result)
print(result.group(1))
print(result.span()) #6.匹配模式:
import re
content = "Hello 1234567 World_This
is a Regex Demo"
result = re.match('^He.*?(\d+).*?Demo$',content)
print(result)
print(result.group(1))
print(result.span()) #7.匹配转义字符: 总结:我们在使用re.match进行匹配字符串时,尽量使用泛匹配,即尽量多使用.*?来匹配,
尽量使用非贪婪模式匹配,有换行符就指定匹配模式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> """ 2. re.search
re.search扫描整个字符串并返回第一个成功的匹配 re.search与re.match的比较:
import re
content = "Extra strings Hello 1234567 World_This is a Regex Demo Extra strings"
result = re.match('Hello.*?(\d+).*?',content)
print(result)
此时返回结果为空。 import re
content = "Extra strings Hello 1234567 World_This is a Regex Demo Extra strings"
result = re.search('Hello.*?(\d+).*?',content)
print(result)
print(result.group(1))
输出为:
<_sre.SRE_Match object; span=(14, 27), match='Hello 1234567'>
1234567 总结,从上面的匹配结果可以看到,re.match必须从字符串的头部开始匹配,因此,为了匹配方便,
我们尽量能用re.search就不用re.match。 re.search匹配练习:
第一种:
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.*?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)) 第三种: 三.re.sub
替换字符串中我们所指定的字符串,然后返回我们替换后的字符串
我们结合re.sub可以更方便的完成字符串的提取:
re.sub的格式如下:
re.sub('原字符串','要替换成的目标字符串',flags)
如下所示:
#1.替换为空,删除功能,使用这种方式我们可以用来删除指定的字符串,如一些常用的
#不需要的a标签,换行符等
import re
content = "Hello strings 1234567 World_This is a Regex Demo"
content = re.sub('\d+',"",content)
print(content)
此时我们可以看到,就把原来字符串中的数字删除掉了,或者可以认为把原来的数字
替换成了空字符串,并输出:
Hello strings World_This is a Regex Demo #2.替换成指定的字符串,如下所示:
import re
content = "Hello strings 1234567 World_This is a Regex Demo"
content = re.sub('\d+',"Replacement",content)
print(content)
此时我们可以看到,就把原来字符串中的数字替换成了字符串Replacement,并输出结果为:
Hello strings Replacement World_This is a Regex Demo #3.在原来内容内追加,为了避免歧义,这种方式我们一般不常用,一般都是使用第2种方式直接替换。
import re
content = "Hello strings 1234567 World_This is a Regex Demo"
content = re.sub('(\d+)',r'\1 8910',content)
print(content)
此时我们可以看到,使用r可以保证原来1中的那个原生的字符,就把原来数字元组中的数字
替换成了1234567 8910,并输出结果为:
Hello strings 1234567 8910 World_This is a Regex Demo
#注:r表示原生字符串的意思。 四. re.findall
搜索字符串,并以列表的形式返回所有的匹配结果对象,而每一个结果对象都一个元组的形式存在的。
从这里我们可以看到,一般在python编程中,只要是一个对象,一般都是以元组的形式存在的。
#1.简单匹配,查找指定的字符串元组。
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)) #此时我们可以看到,这是一个列表的形式,<class 'list'>
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 邓丽君 但愿人长久 #注:通过上面的方式,我们可以看到,第一首歌因为它的歌名的超链接不存在,因此整个信息都没匹配出来,
#因此我们需要寻找一种方式,而这种方式既能匹配有的结果,又能匹配没有的结果,即表示,有没有都能匹
#配出来,此时我们可以用()?来表示,匹配的元组数据,?表示前面的数据有没有都可以,如果是单独的字符
#的话,可以指定单独的字符,比如a?,或者是a*?,()?,()*?,都可以,如果是空格或者是换行符的话可以
#使用\s*?来表示。
#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> """
results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)?(</a>)?\s*?</li>',html,re.S)
#注:换行可以用\s表示,*表示一个或多个之前的元素,?可以表示有还是没有,()内的内容可以表示为有或者没有, print(results)
print(type(results)) #此时我们可以看到,这是一个列表的形式,<class 'list'>
for result in results:
print(result) #此时可以看到,每一个结果都是元组的形式
print(result[1]) #此时我们可以通过每一个元组的位置参数取出元组中的第二个位置中的歌名的信息。
#此时可以看到打印结果如下:
[('', '一路上有你', ''), ('<a href="/2.mp3" singer="任贤齐">', '沧海一声笑', '</a>'),
('<a href="/3.mp3" singer="齐秦">', '往事随风', '</a>'),
('<a href="/4.mp3" singer="beyond">', '光辉岁月', '</a>'),
('<a href="/5.mp3" singer="陈慧琳">', '记事本', '</a>'),
('<a href="/6.mp3" singer="邓丽君">', '但愿人长久', '</a>')]
<class 'list'>
一路上有你
沧海一声笑
往事随风
光辉岁月
记事本
但愿人长久 #3.我们可以使用re.sub结合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> """ #此时我们可以先用re.sub将原来的a标签删除替换掉:
html = re.sub('<a.*?>|</a>',"",html)
print(html)
#注:这个地方a标签中间的|表示与,表示两者内容都替换,然后再用re.findall来提取歌名即可。
results = re.findall('<li.*?>(.*?)</li>',html,re.S)
print(results)
print(type(results))
for result in results:
print(result.strip()) #因为列表中含有换行字符,使用strip()方法,去除换行字符即可。
#此时打印输出,即可得到我们想要的结果:
['一路上有你', '\n 沧海一声笑\n ',
' \n 往事随风 \n ', '光辉岁月',
'记事本', ' \n 但愿人长久 \n ']
<class 'list'>
一路上有你
沧海一声笑
往事随风
光辉岁月
记事本
但愿人长久 #此时我们就通过了re.sub(),和re.findall()方法实现了歌名的爬取。
python网络爬虫之三re正则表达式模块的更多相关文章
- 05.Python网络爬虫之三种数据解析方式
引入 回顾requests实现数据爬取的流程 指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指 ...
- 05,Python网络爬虫之三种数据解析方式
回顾requests实现数据爬取的流程 指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指定数据 ...
- 《Python网络爬虫之三种数据解析方式》
引入 回顾requests实现数据爬取的流程 指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指 ...
- Python网络爬虫之三种数据解析方式 (xpath, 正则, bs4)
引入 回顾requests实现数据爬取的流程 指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指 ...
- Python网络爬虫之三种数据解析方式
1. 正则解析 正则例题 import re # string1 = """<div>静夜思 # 窗前明月光 # 疑是地上霜 # 举头望明月 # 低头思故乡 ...
- python网络爬虫之二requests模块
requests http请求库 requests是基于python内置的urllib3来编写的,它比urllib更加方便,特别是在添加headers, post请求,以及cookies的设置上,处理 ...
- PYTHON网络爬虫与信息提取[正则表达式的使用](单元七)
正则表达式由字符和操作符构成 . 表示任何单个字符 []字符集,对单个字符给出取值范围 [abc]或者关系 [a-z]表示 [^abc]表示非这里面的东西 非字符集 * 表示星号之前的字符出现0次或 ...
- 【python网络爬虫】之requests相关模块
python网络爬虫的学习第一步 [python网络爬虫]之0 爬虫与反扒 [python网络爬虫]之一 简单介绍 [python网络爬虫]之二 python uillib库 [python网络爬虫] ...
- Python 正则表达式 (python网络爬虫)
昨天 2018 年 01 月 31 日,农历腊月十五日.20:00 左右,152 年一遇的月全食.血月.蓝月将今晚呈现空中,虽然没有看到蓝月亮,血月.月全食也是勉强可以了,还是可以想像一下一瓶蓝月亮洗 ...
随机推荐
- python绘图入门
python绘图入门 学习了:https://zhuanlan.zhihu.com/p/34200452 API:https://matplotlib.org/api/pyplot_api.html ...
- Android自己定义之TextView跑马灯的监听
TextView都有跑马灯的效果,假设说让你去监听跑马灯效果的运行.我认为这个需求有点二了.可是也要实现. 思路: 1.自己定义View 继承TextView 这样的方法过于麻烦,仅仅是监听一个 ...
- Nginx在Linux下的安装部署
Nginx简单介绍 Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 server,也是一个 IMAP/POP3/SMTP server.Nginx作为 ...
- 【Mongodb教程 第一课 补加课1 】windows7 下安装mongodb 开启关闭服务
mongodb在2.2版本开始就不支持windows xp了(我想现在用xp的应该也是带着情怀的一部分人吧,我只是一个工匠而已),windows下server8 R2,64位,32位,只是32位只支持 ...
- ASP.NET MVC 学习笔记-2.Razor语法 ASP.NET MVC 学习笔记-1.ASP.NET MVC 基础 反射的具体应用 策略模式的具体应用 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用 C#读取XML文件的基类实现
ASP.NET MVC 学习笔记-2.Razor语法 1. 表达式 表达式必须跟在“@”符号之后, 2. 代码块 代码块必须位于“@{}”中,并且每行代码必须以“: ...
- Android 怎样在java/native层改动一个文件的权限(mode)与用户(owner)?
前言 欢迎大家我分享和推荐好用的代码段~~ 声明 欢迎转载.但请保留文章原始出处: CSDN:http://www.csdn.net ...
- struts2的(S2-045,CVE-2017-5638)漏洞测试笔记
网站用的是struts2 的2.5.0版本 测试时参考的网站是http://www.myhack58.com/Article/html/3/62/2017/84026.htm 主要步骤就是用Burp ...
- taskTracker和jobTracker 启动失败
2011-01-05 12:44:42,144 ERROR org.apache.hadoop.mapred.TaskTracker: Can not start task tracker becau ...
- 暴走吧!Snapdragon SDK开发速成指南
(文/Aurora J) Qualcomm的Snapdragon处理器.它快如闪电.效率极高.擅长挑战多任务极限,而且拥有攻城狮们梦寐以求的无限潜能.它能确保您的手机集4G LTE.极速体验.长久续航 ...
- adbi命令【转】
本文转载自:https://zmywly8866.github.io/2015/01/24/all-adb-command.html ADB很强大,记住一些ADB命令有助于提高工作效率. 获取序列 ...