爬虫基础 -----3正则表达式

一、正则基础

1、为什么使用正则

  • 客户需求

    例如:当需求需要判断一个字符串是否是手机号

  • 解决方式

    编写一个函数,给函数传入一个字符串,判断是手机号则返回True,否则返回False

  • 代码

    伪代码:
    def IsPhone():
        # 判断长度为11
        # 全部都是数字字符
        # 以1开头
        if.... True
        else:
        	False
    

    如果使用正则,会让这个问题变得非常简单。

2、正则与re模块简介

正则表达式:又称规则表达式。

(1)正则表达式(regular expression)描述了一种字符串匹配的模式(pattern)。

(2)正则匹配是一个 模糊的匹配(不是精确匹配)。

re模块:python自1.5版本开始增加了re模块,该模块提供了perl风格的正则表达式模式,re模块是python语言拥有了所有正则表达式的功能。

  • 如下四个方法经常使用:
    • match()
    • search()
    • findall()
    • finditer()

二、正则表达式

1、匹配单个字符与数字

匹配说明
.匹配除换行符以外的任意字符,当flags被设置为re.S时,可以匹配包含换行符以内的所有字符
【】里面是字符集合,匹配[]里任意一个字符
【0123456789】匹配任意一个数字字符
【0-9】匹配任意一个数字字符
【a-z】匹配任意一个小写英文字母字符
【A-Z】匹配任意一个大写英文字母字符
【A-Za-z】匹配任意一个英文字母字符
【A-Za-z0-9】匹配任意一个数字或英文字母字符
【^lucky】[]里的^称为脱字符,表示非,匹配不在[]内的任意一个字符
^【lucky】以[]中内的某一个字符作为开头
\d匹配任意一个数字字符,相当于[0-9]
\D匹配任意一个非数字字符,相当于[^0-9]
\w匹配字母、下划线、数字中的任意一个字符,相当于[0-9A-Za-z_]
\W匹配非字母、下划线、数字中的任意一个字符,相当于[^0-9A-Za-z_]
\s匹配空白符(空格、换页、换行、回车、制表),相当于[ \f\n\r\t]
\S匹配非空白符(空格、换页、换行、回车、制表),相当于[^ \f\n\r\t]

2、匹配锚字符

锚字符:判定是否按照规定开始或者结尾。

匹配说明
^行首匹配,和[]里的^不是一个意思
$行尾匹配,和^一起使用
\A匹配字符串的开始,和^的区别是\A只匹配整个字符串的开头,即使在re.M模式下也不会匹配其他行的行首
\Z匹配字符串的结尾,和$的区别是\Z只匹配整个字符串的结尾,即使在re.M模式下也不会匹配其他行的行尾

3、限定符

限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 *+?{n}{n,}{n,m} 共6种。

匹配说明
(xyz)匹配括号内的xyz,作为一个整体去匹配 一个单元 子存储
x?匹配0个或者1个x,非贪婪匹配
x*匹配0个或任意多个x
x+匹配至少一个x
x{n}确定匹配n个x,n是非负数
x{n,}至少匹配n个x
x{n,m}匹配至少n个最多m个x
x|y|表示或的意思,匹配x或y
# []  # 原子表
[a]   # 匹配a
[ab]  # 匹配a或者b
[abc]  # 匹配a或者b后者c
[123]  # 匹配1或者2或者3
[0-9]  # 匹配任意一位数字
[a-z]  # 匹配任意以为小写字母
[A-Z]  # 匹配任意一位大写字母
[a-zA-Z]  # 匹配任意大小写字母
[abc][0-9]  # 匹配a或者b后者c和任意一位数字  
1[3-9][0-9]{9}   # {9} 代表前面的[0-9]9位  第一个数据为1,第二个数字从3-9,后9位数字随机

# ^ 限制开头  $ 限制结尾  一般用于组合
^1[3-9][0-9]{9}$  # 完全匹配  匹配的字符串中 必须完全符合才算匹配成功

# {} 代表前面正则匹配的n词
[a-z]{2}  # 匹配俩位小写字母
[a-z][a-z]  # 等同于上方

# {m,n}  m-n之间的
[a-z]{2,5}  # 匹配2-5个小写字母

# {m,}  # 至少m个
[a-z]{2,}  # 至少匹配2个小写字母

# ? 可有可无
-?[1-9]   # 匹配正负1-9

# .  匹配换行符以外的任意字符
[.]

# * 代表前面的0次到多次  {0,}

# .* 组合 了解  贪婪模式  匹配换行符以外的任意字符任意次

# .*? 组合  非贪婪模式 匹配换行符以外的任意字符任意次

# +  匹配一次到多次  {1,}

# .+?  非贪婪模式 匹配换行符以外的任意字符至少1次

# |  代表或
[a-z]|[0-9] # 匹配字母或数字

# ()  # 1.作为一个单元   2.作为子存储

三、re模块中常用函数

通用flags(修正符)

说明
re.I是匹配对大小写不敏感
re.M多行匹配,影响到^$
re.S使.匹配包括换行符在内的所有字符

通用函数

1、match()函数 (用于匹配-完全匹配)

  • 原型
def match(pattern, string, flags=0)
  • 参数
参数说明
pattern匹配的正则表达式(一种字符串的模式)
string要匹配的字符串
flags标识位,用于控制正则表达式的匹配方式
  • 功能

匹配成功返回 匹配的对象 。

匹配失败 返回 None。

  • 注意:从第一位开始匹配 只匹配一次

  • 代码

import re  # 导入re正则模块
  # match  只匹配一次  必须从第一位开始
print(re.match("a", '123456'))  # None
print(re.match("[a-z]", '123456'))  # None
print(re.match("[a-z]", '123x456'))  # None
print(re.match("[a-z][a-z]", '123x456'))  # None
print(re.match("1[3-9][0-9]{9}", 'x15611833906a'))  # None
print(re.match("1[3-9][0-9]{9}$", '15611833906').group())  # 完全匹配

2、searce()函数 (模糊搜索-模糊匹配)

  • 原型

    def search(pattern, string, flags=0)
    
  • 参数

    参数说明
    pattern匹配的正则表达式(一种字符串的模式)
    string要匹配的字符串
    flags标识位,用于控制正则表达式的匹配方式
  • 功能

    扫描整个字符串string,并返回第一个pattern模式成功的匹配。

    匹配失败 返回 None。

  • 注意:

    只要字符串包含就可以。只匹配一次。

  • 代码

    	import re
      		# search  只匹配一次
      	print(re.search("a", '123456'))  # None
      	print(re.search("[a-z]", '123456'))  # None
      	print(re.search("[a-z]", '123x456'))
      	print(re.search("[a-z][a-z]", '123x456'))  # None
      	print(re.search("[a-z][a-z]", '123ab456'))
      	print(re.search("[a-z][a-z]", '123ax456b'))
      	print(re.search("1[3-9][0-9]{9}", '15611833906'))
      	print(re.search("1[3-9][0-9]{9}", '15611833906a'))  
      	print(re.search("1[3-9][0-9]{9}", 'x15611833906a'))  
      	print(re.search("^1[3-9][0-9]{9}", 'x15611833906a'))  # None
      	print(re.search("^1[3-9][0-9]{9}", '15611833906a'))
      	print(re.search("^1[3-9][0-9]{9}$", '15611833906a'))  # 完全匹配   # None
      	print(re.search("^1[3-9][0-9]{9}$", '15611833906'))  # 完全匹配
      	print(re.search("^1[3-9][0-9]{9}$", '1561183390'))  # 完全匹配  # None
      	print(re.search("^1[3-9][0-9]{9}$", '15611833906').group())  # 完全匹配
    
  • 注意

    match()与search()的区别

    相同点:

    都只匹配一次。

    不同点:

    • search是在要匹配的字符串中 包含正则表达式的内容就可以。
    • match 必须第一位就开始匹配 否则匹配失败。

3、findall()函数(返回列表)

  • 原型

    def findall(pattern, string, flags=0)
    
  • 参数

    参数说明
    pattern匹配的正则表达式(一种字符串的模式)
    string要匹配的字符串
    flags标识位,用于控制正则表达式的匹配方式
  • 功能

    扫描整个字符串string,并返回所有匹配的pattern模式结果的字符串列表。

  • 示例

    
    myStr = """
    <a href="http://www.baidu.com">百度</a>
    <A href="http://www.taobao.com">淘宝</A>
    <a href="http://www.id97.com">电
    影网站</a>
    <i>我是倾斜1</i>
    <i>我是倾斜2</i>
    <em>我是倾斜2</em>
    """
    # html里是不区分大小写
    # (1)给正则里面匹配的 加上圆括号 会将括号里面的内容进行 单独的返回
    #[('<a href="http://www.baidu.com">百度</a>', 'baidu', '百度')]
    res = re.findall("(<a href=\"http://www\.(.*?)\.com\">(.*?)</a>)",myStr)
    
    # 括号的区别
    #['<a href="http://www.baidu.com">百度</a>']
    res = re.findall("<a href=\"http://www\..*?\.com\">.*?</a>",myStr) 
    
    #(2) 不区分大小写的匹配
    #['<a href="http://www.baidu.com">百度</a>', '<A href="http://www.taobao.com">淘宝</A>']
    res = re.findall("<a href=\"http://www\..*?\.com\">.*?</a>",myStr,re.I)
    
    #['<a href="http://www.baidu.com">百度</a>']
    res = re.findall("<[aA] href=\"http://www\..*?\.com\">.*?</[aA]>",myStr)
    
    
    # (3) 使.支持换行匹配
    #['<a href="http://www.baidu.com">百度</a>', '<a href="http://www.id97.com">电\n影网站</a>']
    res = re.findall("<a href=\"http://www\..*?\.com\">.*?</a>",myStr,re.S) #
    
    # (4) 支持换行 支持不区分大小写匹配
    # ['<a href="http://www.baidu.com">百度</a>', '<A href="http://www.taobao.com">淘宝</A>', '<a href="http://www.id97.com">电\n影网站</a>']
    res = re.findall("<a href=\"http://www\..*?\.com\">.*?</a>",myStr,re.S|re.I) #
    
    
  • 贪婪与非贪婪模式

    <H1>Chapter 1 - 介绍正则表达式</H1>
    

    **贪婪:**下面的表达式匹配从开始小于符号 (<) 到关闭 H1 标记的大于符号 (>) 之间的所有内容。

    /<.*>/
    

    **非贪婪:**如果您只需要匹配开始和结束 H1 标签,下面的非贪婪表达式只匹配

    /<.*?>/
    

    如果只想匹配开始的 H1 标签,表达式则是:

    /<\w+?>
    

4、finditer()函数

  • 原型
    def finditer(pattern, string, flags=0)
    
  • 参数
参数说明
pattern匹配的正则表达式(一种字符串的模式)
string要匹配的字符串
flags标识位,用于控制正则表达式的匹配方式
  • 功能

    与findall()类似,返回一个迭代器。

  • 代码

    import re
    
    res = re.finditer('\w', '12hsakda1')
    print(res)
    
    for i in res:
        print(i) # 循环遍历出每一个值
    

5、split()函数

  • 作用:切割字符串

  • 原型:

    def split(patter, string, maxsplit=0, flags=0)
    
  • 参数
参数说明
pattern匹配的正则表达式(一种字符串的模式)
string要匹配的字符串
maxsplit最大拆分次数 默认拆分全部
flags标识位,用于控制正则表达式的匹配方式
  • 示例

    import re
    myStr = "asdas\rd&a\ts12d\n*a3sd@a_1sd"
    #通过特殊字符 对其进行拆分 成列表
    #  ['asdas', 'd', 'a', 's', '', 'd', '', 'a', 'sd', 'a', '', 'sd']
    res = re.split("[^a-z]",myStr)
    # ['asdas', 'd', 'a', 's12d', '', 'a3sd', 'a_1sd']
    res = re.split("\W",myStr)
    

6、修正符

  • 作用

    对正则进行修正

  • 使用

    search()/match()/findall()/sub()/subn()/finditer() 等函数 flags参数的使用。

  • 修正符

    re.I 不区分大小写匹配。

    re.M 多行匹配 影响到^ 和 $ 的功能。

    re.S 使.可以匹配换行符 匹配任意字符。

  • 使用

    re.I

    print(re.findall('[a-z]','AaBb')) # ['a', 'b']
    print(re.findall('[a-z]','AaBb', flags=re.I)) # ['A', 'a', 'B', 'b']
    

    re.M

      myStr = """asadasdd1\nbsadasdd2\ncsadasdd3"""
      print(re.findall('^[a-z]', myStr, ))  # ['a']
      print(re.findall('\A[a-z]', myStr))  # ['a']
      print(re.findall('\d$', myStr))  # ['3']
      print(re.findall('\d\Z', myStr))  # ['3']
      # re.M
      print(re.findall('^[a-z]', myStr, flags=re.M))  # ['a', 'b', 'c']
      print(re.findall('\A[a-z]', myStr, flags=re.M))  # ['a']
      print(re.findall('\d$', myStr, flags=re.M))  # ['1', '2', '3']
      print(re.findall('\d\Z', myStr, flags=re.M))  # ['3']
    

    re.S

    print(re.findall('<b>.*?</b>','<b>b标签</b>'))
    print(re.findall('<b>.*?</b>','<b>b标\n签</b>', flags=re.S))
    

四、正则高级

1、分组&起名称

  • 概念

    处理简单的判断是否匹配之外,正则表达式还有提取子串的功能,用()表示的就是要提取的分组

  • 代码

      import re
      myStr = "abcd1"
      print(re.search("(?P<number>\d+)", myStr).group(0))
      # 当有多个子存储的时候 使用别名比较方便
      # print(re.search("(?P<number>\d+)", myStr).group('number'))
      print(re.search("(?P<asd>\d+)", myStr).group('asd'))
    
  • 说明

    • 正则表达式中定义了组,就可以在Match对象上用group()方法提取出子串来
    • group(0)永远是原始字符串,group(1)、group(2)……表示第1、2、……个子串

2、编译 、compile()函数

  • 概念

    当在python中使用正则表达式时,re模块会做两件事,一件是编译正则表达式,如果表达式的字符串本身不合法,会报错。另一件是用编译好的正则表达式提取匹配字符串

  • 编译优点

    如果一个正则表达式要使用几千遍,每一次都会编译,出于效率的考虑进行正则表达式的编译,就不需要每次都编译了,节省了编译的时间,从而提升效率

  • compile()函数

    • 原型

      def compile(pattern, flags=0)
      
    • 作用

      将pattern模式编译成正则对象。

    • 参数

      参数说明
      pattern匹配的正则表达式(一种字符串的模式)
      flags标识位,用于控制正则表达式的匹配方式
    • flags

      说明
      re.I是匹配对大小写不敏感
      re.M多行匹配,影响到^和$
      re.S使.匹配包括换行符在内的所有字符
    • 返回值

      编译好的正则对象

    • 示例

      import re
      
      re_phone = re.compile(r"(0\d{2,3}-\d{7,8})")
      print(re_phone, type(re_phone))
      
  • 编译后其他方法的使用

    原型

    def match(self, string, pos=0, endpos=-1)
    def search(self, string, pos=0, endpos=-1)
    def findall(self, string, pos=0, endpos=-1)
    def finditer(self, string, pos=0, endpos=-1)
    

    参数

    参数说明
    string待匹配的字符串
    pos从string字符串pos下标开始
    endpos结束下标

    示例

    s1 = "lucky's phone is 010-88888888"
    s2 = "kaige's phone is 010-99999999"
    ret1 = re_phone.search(s1)
    print(ret1, ret1.group(1))
    ret2 = re_phone.search(s2)
    print(ret2, ret2.group(1))
    

3、贪婪与非贪婪

  • 贪婪模式

    贪婪概念:匹配尽可能多的字符

    • .+ 匹配换行符以外的字符至少一次
    • .* 匹配换行符以外的字符任意次

    实例

    res = re.search('<b>.+</b>', '<b></b><b>b标签</b>')
    res = re.search('<b>.*</b>', '<b>b标签</b><b>b标签</b><b>b标签</b><b>b标签</b>')
    
  • 非贪婪模式

    非贪婪概念:尽可能少的匹配称为非贪婪匹配,*?、+?即可

  • .+? 匹配换行符以外的字符至少一次 拒绝贪婪

    • .*? 匹配换行符以外的字符任意次 拒绝贪婪

    实例

    res = re.search('<b>.+?</b>', '<b>b标签</b><b>b标签</b>')
    res = re.search('<b>.*?</b>', '<b>b标签</b><b>b标签</b><b>b标签</b><b>b标签</b>')
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值