正则表达式的概念和作用
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
概念:正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
正则表达式的作用:
1.验证数据的有效性
2.替换文本内容
3.从字符串中提取子字符串
简单的正则表达式代码事例
import re
# 导出正则表达式模块
string="A1.45,b5,6.45,8.82ab5."
print (re.findall(r"\d+\.?\d*",string))
# ['1.45', '5', '6.45', '8.82', '5.']
分析:正则表达式模式为:"\d+\.?\d*"。
\d+匹配1次或者多次数字,注意这里不要写成*,因为即便是小数,小数点之前也得有一个数字;
\.?这个是匹配小数点的,可能有,也可能没有;
\d*这个是匹配小数点之后的数字的,所以是0个或者多个;
import re
pattern=r"(13[4-9]\d{8})$|(15[01289]\d{8})$"
# 以13开头后面跟4-9之间的一个字符然后后面是8个任意数字的字符
mobile="13634222222"
match = re.match(pattern,mobile)
# 进行模式匹配
if match == None:
# 判断是否为None,为真表示匹配失败
print(mobile,'不是有效的中国移动手机号码。')
else:
print(match.group(),'是有效的中国移动手机号码。')
分析:正则表达式模式为:"(13[4-9]\d{8})$|(15[01289]\d{8})$"
“( )” 表示要获取括弧之间的信息。
“|” 表示或者
“13"或者"15"开头
"[4-9]"表示数字4到9之间均可,"[01289]"表示数字0、1、2、8、9均可
"d{8}"匹配连续8个数字
"$"匹配字符串结尾
# 爬取百度首页标题
import re
from urllib import request
#爬虫爬取百度首页内容
data = request.urlopen("http://www.baidu.com/").read().decode()
# print(data)
#分析网页,确定正则表达式
pat = r'<title>(.*?)</title>'
'''
“.*?” 表示非贪心算法,表示要精确的配对。
“.*”表示贪心算法,表示要尽可能多的匹配
“( )” 表示要获取括弧之间的信息。
'''
result = re.search(pat,data)
print(result)
print(result.group())
# <title>百度一下,你就知道</title>
print(result.groups())
# ('百度一下,你就知道',)
print(result.group(1))
# 百度一下,你就知道
findall_result = re.findall(pat,data)
print(findall_result)
# ['百度一下,你就知道']
# “.*?” 表示非贪心算法 和 “.*”表示贪心算法
import re
a = 'xxIxxjshdxxlovexxsffaxxpythonxx'
infos = re.findall('xx(.*?)xx', a)
print(infos)
# ['I', 'love', 'python']
infos = re.findall('xx(.*)xx', a)
# ['Ixxjshdxxlovexxsffaxxpython']
print(infos)
正则表达式模式在线图示网站
https://regexper.com/
(?= re)
前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。a(?=\d),返回匹配字符串中以数字为结尾的a字符。
(?! re)
前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功。a(?!\d),返回不匹配字符串中以数字结尾的a字符。
(?> re)
匹配的独立模式,省去回溯。
正则表达式详细表
附:零宽断言: (了解)
时候在使用正则表达式做匹配的时候,我们希望匹配一个字符串,这个字符串的前面或后面需要是特定的内容,但我们又不想要前面或后面的这个特定的内容,这时候就需要零宽断言的帮助了。所谓零宽断言,简单来说就是匹配一个位置,这个位置满足某个正则,但是不纳入匹配结果的,所以叫“零宽”,而且这个位置的前面或后面需要满足某种正则。
示例:提取<div>Hello World</div>中Hello World,正则表达式如下:
(?<=).*(?=[a-zA-Z]+>);
正则表达式实例
1)、re.match( pattern,string [,flags=0] )
re.match 尝试从字符串的
起始位置匹配
一个模式,如果不是起始位置匹配成功的话,match()就返回none。
flags是匹配模式修饰符,见下表:(了解)
使匹配对大小写不敏感
做本地化识别(locale-aware)匹配
多行匹配,影响 ^ 和 $
使 . 匹配包括换行在内的所有字符
根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
事例代码如下:
import re
print(re.match('www', 'www.runoob.com').span()) # 在起始位置匹配,结果:(0,3)
print(re.match('com', 'www.runoob.com')) # 不在起始位置匹配,结果:None
line = "Cats are smarter than dogs"
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I) # 有两个group,()
print(matchObj.group()) # 结果:Cats are smarter than dogs
print(matchObj.groups()) # 结果:('Cats', 'smarter')
print(matchObj.group(1)) # 结果:Cats
print(matchObj.group(2)) # 结果:smarter
2)、re.search( pattern,string [,flags=0] )
参数和返回同上
re.search函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回,如果字符串没有匹配,则返回None,参数与返回与re.match完全一致。re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
3)、re.findall( pattern,string [,flags] )
参数同上,返回列表,找不到则返回空列表
text = 'apple is my love $45, apple is delicouis $56'
ret = re.findall('\$\d+', text)
print(ret) #['$45', '$56']
ret = re.findall(r"html$","https://docs.python.org/3/whatsnew/3.6.html")
print (ret) # ['html']
text = "JGod is a handsome boy ,but he is a ider"
print(re.findall(r'\w*o\w*',text)) # 查找有o的单词
# 输出结果为:['JGod', 'handsome', 'boy']
4)、re.split( pattern,string [,flags] )
参数同上;根据正则表达式的模式分隔符,split函数将字符串分割为列表,然后返回成功匹配的列表;注意:没有可匹配的项时,返回原来的字符串。
import re
s = 'abc, abc, defg, dds'
print(re.split('\W+',s)) # 相当于以非字母数字下划线分割 ['abc', 'abc', 'defg', 'dds']
# 如果加上括号,结果会同时返回去掉的值
print(re.split('(\W+)',s)) # ['abc', ', ', 'abc', ', ', 'defg', ', ', 'dds']
5)、re.complie(pattern [, flags])
re.compile 函数用于编译正则表达式,生成一个正则表达式( re.Pattern )对象
,供以上使用.
调模式为:pattern.函数名(string [,flags])。
import re
text = 'Hello World Wide Web'
pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # pattern为编译后的模式对象 re.I 表示忽略大小写
m = pattern.match(text)
print(m.groups()) # 匹配成功,返回一个 Match 对象,结果:('Hello', 'World')
m = pattern.search(text)
print(pattern.findall(text)) # [('Hello', 'World'), ('Wide', 'Web')]
text = 'python 123 google 456 aa'
pattern = re.compile(r'\d+') # 查找数字
result1 = pattern.findall(text)
print(result1) # ['123', '456']
print(pattern.split(text)) # ['python ', ' google ', ' aa']
正则表达式应用
1)、获取页面中的所有超链接
import re
import urllib.request
# 打开网页,读取页面并解码
response = urllib.request.urlopen("http://www.suda.edu.cn")
html = response.read().decode('utf-8')
#print(html)
pat1 = r'<a .*?>.*?</a>' # r'<a .*?>(.*?)</a>'
pat2 = r'<a href="([a-zA-z]+://[^\s]*)"'
pat3 = r"<a.*?href=.*?<\/a>"
a = re.findall(pat3, html)
print(a) # 打印页面中的全部超链接,即a标签<a href=.......
2)、获取页面小说
import re
import urllib.request
response = urllib.request.urlopen("http://sit666.cn/python/chapter1/python_1_1.html")
html = response.read()
data=html.decode('utf-8')
#print(data) 查看页面源码
pat=r'<p>(.+)</p>' # 简单获取章节的内容
result=re.findall(pat,data)
print(result)
3)、下载页面中的图所有片
import urllib.request # urllib是python内置的一个http请求库,urllb.request 请求模块
import re
req = urllib.request.urlopen('http://www.imooc.com/course/list')
buf = req.read()
buf = buf.decode('utf-8') # 特别需要注意,python3和python之间的区别
#print(buf)
listurl = re.findall(r'//.+\.jpg',buf) # 图片链接格式为://任意多个字母数字等.jpg
#print(listurl)
i = 1
for url in listurl:
#print('http:'+url)
f = open(str(i)+'.jpg','wb')
req = urllib.request.urlopen('http:'+url) # 注意图片的绝对地址
buf = req.read()
f.write(buf)
i + = 1
课外阅读:网络爬虫
概念:网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。
搜索引擎网络爬虫的基本工作流程
首先选取一部分的种子URL,将这些URL放入待抓取URL队列;
取出待抓取URL,解析DNS得到主机的IP,并将URL对应的网页下载下来,存储进已下载网页库中,并且将这些URL放进已抓取URL队列。
分析已抓取URL队列中的URL,分析其中的其他URL,并且将URL放入待抓取URL队列,从而进入下一个循环..
常见的Python爬虫框架:
Scrapy框架:
Scrapy框架是一套比较成熟的Python爬虫框架,是使用Python开发的快速、高层次的信息爬取框架,可以高效的爬取web页面并提取出结构化数据。Scrapy应用范围很广,爬虫开发、数据挖掘、数据监测、自动化测试等。
Crawley框架:
Crawley也是Python开发出的爬虫框架,该框架致力于改变人们从互联网中提取数据的方式。
Python 网络爬虫的常用库
Python标准库——urllib模块:一系列用于操作URL的功能。
requests:基于 urllib 编写的,阻塞式 HTTP 请求库,发出一个请求,一直等待服务器响应后,程序才能进行下一步处理。
beautifulsoup:html 和 XML 的解析,从网页中提取信息,同时拥有强大的API和多样解析方式。
lxml:支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高。
正则表达式常用模式如下:
最简单的正则表达式是普通字符串,可以匹配自身
'[pjc]ython'可以匹配'python'、'jython'、'cython'
'[a-zA-Z0-9]'可以匹配一个任意大小写字母或数字
'[^abc]'可以一个匹配任意除'a'、'b'、'c'之外的字符
'python|perl'或'p(ython|erl)'都可以匹配'python'或'perl'
子模式后面加上问号表示可选。r'(http://)?(www\.)?python\.org'只能配'http://www.python.org'、'http://python.org'、'www.python.org'和'python.org'
'^http'只能匹配所有以'http'开头的字符串
(pattern)*:允许模式重复0次或多次
(pattern)+:允许模式重复1次或多次
(pattern){m,n}:允许模式重复m~n次
'(a|b)*c':匹配多个(包含0个)a或b,后面紧跟一个字母c。
'ab{1,}':等价于'ab+',匹配以字母a开头后面带1个至多个字母b的字符串。
'^[a-zA-Z]{1}([a-zA-Z0-9._]){4,19}$':匹配长度为5-20的字符串,必须以字母开头、可带数字、“_”、“.”的字串。
'^(\w){6,20}$':匹配长度为6-20的字符串,可以包含字母、数字、下划线。
'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$':检查给定字符串是否为合法IP地址。
'^(13[4-9]\d{8})|(15[01289]\d{8})$':检查给定字符串是否为移动手机号码。
'^[a-zA-Z]+$' :检查给定字符串是否只包含英文字母大小写。
'^\w+@(\w+\.)+\w+$' :检查给定字符串是否为合法电子邮件地址1。
^([a-zA-Z\.0-9]+)@[a-zA-Z0-9]+\.[a-zA-Z]{3}$ :检查给定字符串是否为合法电子邮件地址2。
\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\.[a-zA-Z]{1,4}\b :检查给定字符串是否为合法电子邮件地址3。
'^(\-)?\d+(\.\d{1,2})?$':检查给定字符串是否为最多有2位小数的正数或负数。
'[\u4e00-\u9fa5]':匹配给定字符串中所有汉字。
'^\d{18}|\d{15}$':检查给定字符串是否为合法身份证格式。
'\d{4}-\d{1,2}-\d{1,2}':匹配指定格式的日期,例如2016-1-31。
'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[,._]).{8,}$':检查给定字符串是否为强密码,必须同时包含英语字母大写字母、英文小写字母、数字或特殊符号(如英文逗号、英文句号、下划线),并且长度必须至少8位。
"(?!.*[\'\"\/;=%?]).+":如果给定字符串中包含’、”、/、;、=、%、?则匹配失败。
‘(.)\\1+’:匹配任意字符的一次或多次重复出现。注:\\1中第一个\为转义,\1表示匹配第1个分组的内容