模块一(re模块)

一、re模块

       首先说一下什么是模块,模块就是一组功能的集合。你要和某个东西打交道,而这个东西本身和python没关系,这个东西本身就存在,所以python提供了一个功能的集合专门负责和这个东西打交道。

       模块的类型:

              内置模块:不需要我们自己安装,解释器自带的;

              第三方模块:需要我们自己安装的模块;

              自定义模块:我们自己写的模块;

       为什么要有模块?先举一个例子:我们都知道是操作系统把所有硬件管理起来的,文件是在硬盘上存储的,python想从硬盘上进行文件的操作和删除时就需要引入os模块,说白了,模块实际上就是给我们提供功能,这个要操作的内容本身就存在,模块只不过是python提供给我们去操作这个内容的方法。

       注意:永远不要起一个和你已知的模块同名的py文件的名字!

       今天我们就来学习一下re模块的几个基础方法,在python中使用正则表达式就要引入re模块。

1,查找

  findall:表示匹配每一项都是列表中的一个元素。 (重要程度*****)

       语法规则:re.findall(‘正则表达式’, 待匹配字符串 , flag),具体示例如下:

    import re
    ret = re.findall('\d+', 'sjkhk172按实际花费928')
    print(ret)  # 结果为:['172', '928']
        
    ret = re.findall('\d', 'sjkhk172按实际花费928')
    print(ret)  # 结果为:['1', '7', '2', '9', '2', '8']

  search:只匹配从左到右的第一个,得到的不是直接的结果,而是一个变量,通过这个变量的group方法来获取结果,如果没有匹配到,会返回None,使用group会报错。(重要程度*****)

       语法规则:re.search(‘正则表达式’, 待匹配字符串 , flag),具体示例如下:

    ret = re.search('\d+', 'sjkhk172按实际花费928')
    print(ret)  # 结果为:<_sre.SRE_Match object; span=(5, 8),     match='172'>
    print(ret.group()) # 结果为:172

    ret = re.search('\d','owghabDJLBNdgv')
    print(ret)   # 结果为:None
    print(ret.group())   # 会报错

    # 因为search方法查找的时候,若待匹配的字符串中没有能匹配到的结果时,
    # 用group会报错,所以通常我们写成下面这样
    ret = re.search('\d+','sjkhk172按实际花费928')
    if ret :   # 内存地址,这是一个正则匹配的结果
        print(ret.group()) # 通过ret.group()获取真正的结果

  match:从头开始匹配,相当于search中的正则表达式加上一个^。(重要程度**)

       语法规则:re.match(‘正则表达式’, 待匹配字符串 , flag),具体示例如下:

    ret = re.match('\d+$','sjkhk172按实际花费928')
    print(ret)  # 结果为:None
    ret = re.match('\d+','172sjkhk按实际花费928')
    print(ret)  # 结果为:<_sre.SRE_Match object; span=(0, 3),     match='172'>
    print(ret.group())  # 结果为:172
    ret = re.match('\d+$','172sjkhk按实际花费928')
    print(ret)  # 结果为:None

2,字符串处理的扩展

       切割:re.split(‘正则表达式’, 待匹配字符串),用正则表达式匹配出来的结果对待匹配字符串切割。如下:

    s = 'alex83taibai40egon25'
    ret = re.split('\d+',s)
    print(ret)  # 结果为:['alex', 'taibai', 'egon', '']

  替换:sub和subn

              re.sub(‘正则表达式’, ‘新内容’, 待匹配字符串 , 替换次数)

    re.subn(‘正则表达式’, ‘新内容’, 待匹配字符串 , 替换次数) ,示例如下:

    ret = re.sub('\d+','H','alex83taibai40egon25')
    print(ret)  # 结果为:alexHtaibaiHegonH
    ret = re.sub('\d+','H','alex83taibai40egon25',1)
    print(ret)  # 结果为:alexHtaibai40egon25

    ret = re.subn('\d+','H','alex83taibai40egon25')
    print(ret)  # 结果为:('alexHtaibaiHegonH', 3)
    ret = re.subn('\d+','H','alex83taibai40egon25', 2)
    print(ret)  # 结果为:('alexHtaibaiHegonH', 2)
    # 我们可以看出sub和subn的区别是subn返回一个元组,元组第二个元素是替换次数。

3,re模块的进阶:时间和空间上更优化

       compile:节省使用正则表达式解决问题的时间(编译,就是将正则表达式编译成字节码,这样在多次使用的过程中不会多次编译,可以用这个结果去直接search、match、findall、finditer),具体示例如下:

    ret = re.compile('\d+')   # 编译
    print(ret)  # 结果为:re.compile('\\d+')
    res = ret.findall('alex83taibai40egon25')  # 编译后直接使用
    print(res)
    res = ret.search('sjkhk172按实际花费928')  # 编译后直接使用
    print(res.group())

  finditer:节省使用正则表达式解决问题的空间/内存(返回一个迭代器,所有的结果都在这个迭代器中,可以通过循环和group取出来),具体示例如下:

    ret = re.finditer('\d+','alex83taibai40egon25')
    print(ret)  # 结果为:<callable_iterator object at 0x00000000029EFDA0>
    for i in ret:
        print(i.group())
    # 结果为:
    # 83
    # 40
    # 25

二、在python中使用正则表达式的特点和问题

1,分组在re模块中的使用,分析如下几段代码,理解并总结规则:

    # 1 search方法中对正则分组,通过group(n)取出相应内容
    s = '<a>wahaha</a>'
    ret = re.search('<(\w+)>(\w+)</(\w+)>',s)
    print(ret.group())  # 结果为:<a>wahaha</a>,默认取出所有匹配内容
    print(ret.group(1)) # 数字参数代表的是取对应分组中的内容,结果为:a
    print(ret.group(2))  # 结果为:wahaha
    print(ret.group(3))  # 结果为:a

    # 2 findall也可以顺利取到分组中的内容,因为它有一个特殊的语法,就是优先显示分组中的内容
    ret = re.findall('(\w+)',s)
    print(ret)  # 结果为:['a', 'wahaha', 'a']
    ret = re.findall('>(\w+)<',s)
    print(ret)  # 结果为:['wahaha']

    # 3 取消分组优先(?:正则表达式)
    ret = re.findall('>(?:\w+)<',s)
    print(ret)  # 结果为:['>wahaha<']
    ret = re.findall('\d+(?:\.\d+)?','1.234*4')
    print(ret)   # 结果为:['1.234', '4']
    # 当你想用()表示正则里的分组,而不想表示优先显示的时候可以用?:取消分组

  综上: 对于正则表达式来说,有些时候我们需要进行分组,来整体约束某一组字符出现的次数;对于python语言来说,分组可以帮助你更好更精准的找到你真正需要的内容;具体想表示哪种分组,要看情况决定。

    # 4 split方法中可以对正则加括号表示使切割的字符不丢失
    ret = re.split('\d+','alex83taibai40egon25')
    print(ret)  # 结果为:['alex', 'taibai', 'egon', '']
    ret = re.split('(\d+)','alex83taibai40egon25')
    print(ret)  # 结果为:['alex', '83', 'taibai', '40', 'egon', '25', '']

    # 分组命名 (?P<组名>正则表达式)
    s = '<a>wahaha</a>'
    ret = re.search('>(?P<con>\w+)<',s)
    print(ret.group(1))  # 结果为:wahaha
    print(ret.group('con'))  # 结果为:wahaha

    # 使用前面的分组 要求使用这个名字的分组和前面同名分组中的内容匹配的必须一致
    pattern = '<(?P<tab>\w+)>(\w+)</(?P=tab)>'
    ret = re.search(pattern,s)
    print(ret.group())   # 结果为:<a>wahaha</a>
    # 可以练习下列的匹配:
    # 2018-12-06
    # 2018.12.6
    # 2018 12 06
    # 12:30:30

三、使用正则表达式的技巧

       当你要匹配的内容太没有特点,容易和你不想匹配的内容混在一起的时候,就可以把不想匹配的也取出来,然后通过python过滤掉,具体示例如下:

    # 想只取整数,但是会带上小数,那么把整数和小数都取出来,然后再过滤掉小数
    ret=re.findall(r"\d+\.\d+|\d+","1-2*(60+(-40.35/5)-(-4*3))")
    print(ret)  # 结果为:['1', '2', '60', '40.35', '5', '4', '3']
    ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
    ret.remove('')
    print(ret)  # 结果为:['1', '2', '60', '5', '4', '3']

四、爬虫的例子

       预备知识:如何获取一个页面的源代码,如下可以做到:

    from urllib import request
    ret = request.urlopen('https://movie.douban.com/top250?    start=50&filter=')
    res = ret.read().decode('utf-8')
    print(res)

  分析并掌握如下爬虫的小例子:

    import re
    from urllib.request import urlopen

    def getPage(url):   # 获取网页的字符串
        response = urlopen(url)
        return response.read().decode('utf-8')

    def parsePage(s):
        ret = com.finditer(s)  # 从s这个网页源码中 找到所有符合com正则表达式规则的内容 并且以迭代器的形式返回
        for i in ret:
            yield {
                "id": i.group("id"),
                "title": i.group("title"),
                "rating_num": i.group("rating_num"),
                "comment_num": i.group("comment_num"),
            }

    def main(num):  # 0  25 50  # 这个函数执行10次,每次爬取一页的内容
        url = 'https://movie.douban.com/top250?start=%s&filter=' % num
        response_html = getPage(url)   # response_html就是这个url对应的html代码 就是 str
        ret = parsePage(response_html) # ret是一个生成器
        print(ret)
        f = open("move_info7", "a", encoding="utf8")
        for obj in ret:
            print(obj)
            data = str(obj)
            f.write(data + "\n")
        f.close()

    com = re.compile(
        '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'
        '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)

    count = 0
    for i in range(10):
        main(count)
        count += 25

写在最后:

  正则表达式到底重要到什么程度?

  掌握作业中的所有内容

  能够看懂常用的正则表达式

  并且能够做出一些公司特异性要求的修改

猜你喜欢

转载自www.cnblogs.com/li-li/p/9494832.html