re模块

一、正则表达式

  1.正则表达式与re模块的关系

    (1)正则表达式是一门独立的技术,任何语言均可使用

    (2)python中要想使用正则表达式需要通过re模块

  2.正则表达式就是用来筛选字符串中的特定的内容

  3.正则的应用场景

    (1)爬虫

    (2)数据分析

  4.有无正则校验的区别

    (1)纯python代码校验

while True:
    phone_number = input('please input your phone number : ')
    if len(phone_number) == 11 \
            and phone_number.isdigit()\
            and (phone_number.startswith('13') \
            or phone_number.startswith('14') \
            or phone_number.startswith('15') \
            or phone_number.startswith('18')):
        print('是合法的手机号码')
    else:
        print('不是合法的手机号码')

    (2)正则表达式校验

import re
phone_number = input('please input your phone number : ')
if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):
        print('是合法的手机号码')
else:
        print('不是合法的手机号码')

  5.字符组

    在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中使用[ ]表示(一个字符组每次只能匹配一个字符)

字符组
正则 待匹配字符 匹配结果 说明
[0123456789] 8 True 在一个字符组里枚举合法的所有字符,字符组里的任意一个字符和"待匹配字符"相同都视为可以匹配
[0123456789] a False 由于字符组中没有"a"字符,所以不能匹配
[0-9] 7 True 也可以用-表示范围,[0-9]就和[0123456789]是一个意思
[a-z] s True 同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示
[A-Z] B True [A-Z]就表示所有的大写字母
[0-9a-fA-F] e True 可以匹配数字,大小写形式的a~f,用来验证十六进制字符


  6.字符

   优先掌握:

    ^:以什么什么开头

      ^[a-z]

      ^[0-9]

    $:以什么什么结尾

    ps:^与$连用能够精准匹配固定长度的目标字符,^只能出现在开头(),\$只能出现结尾

    |:或

      ab|abc优先匹配前面的正则表达式ab,匹配上就不再用后面的abc,可以通过调换顺序修改优先级

    ^:出现在[ ]中的^表示除了^后面的其他都匹配

      [^a]除了a其他都匹配

      [^a-z]除了小写字母a-z其他都匹配

   了解:

    \w,\s,\d与\W,\S,\D相反的匹配关系(对应的两者结合就是匹配全局)

    \t匹配制表符

    \b匹配结尾的指导单词

元字符
元字符 匹配内容
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示一个组
[...] 匹配字符组中的字符
[^...] 匹配除了字符组中的字符的所有字符

  7.量词

    量词必须跟在正则符号的后面

    量词只能能够限制紧挨着它的那一个正则符号

量词
量词 y用法说明
* 重复零次或更多次
+ 重复一次或更多次
重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

  8.例子

  注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成非贪婪匹配(惰性匹配)

  9.分组

    当多个正则符号需要重复多次的时候或者当做一个整体进行其他操作,那么可以用分组的形式

    分组在正则的语法中就是()

    例子:

    一次性匹配a1b2c3:

    分组方法:(\[a-z][0-9])+

    身份证号码验证:

  10.转义符\

  11.贪婪匹配

    在满足匹配时,匹配尽可能长的字符串

    几个常用的非贪婪匹配:

    *?  重复任意次,但尽可能少重复

    +? 重复1次或更多次,但尽可能少重复

    ?? 重复0次或1次,但尽可能少重复

    {n,m}? 重复n到m次,但尽可能少重复

    {n,}? 重复n次以上,但尽可能少重复

    .*?x就是取前面任意长度的字符,直到一个x出现

二、re模块

  findall:返回所有满足匹配条件的结果,放在列表里

import re
ret = re.findall('a', 'eva egon yuan')  # 返回所有满足匹配条件的结果,放在列表里
print(ret)  # ['a', 'a']

  search:

    (1)search只会依据正则查一次,只要查到了结果,就不会再往后查找

    (2)当查找的结果不存在的情况下,调用group直接报错

import re
ret = re.search('a', 'eva egon yuan')
print(ret.group())  # 结果:'a'
# 函数会在字符串内查找模式匹配,直到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None,并且需要注意的是如果ret是None,再调用.group()会直接报错。这一易错点可以通过if判断来进行筛选
if ret:
    print(ret.group())  # a

  match:

    (1)match只会匹配字符串的开头部分

    (2)当字符串的开头不符合匹配规则的情况下,返回的也是None,调用group也会报错

import re
ret = re.match('a', 'abc').group()  # 同search,不过仅在字符串开始处进行匹配
print(ret)  # ‘a'
# match是从头开始匹配,如果正则规则从头开始可以匹配上,就返回一个对象,需要用group才能显示,如果没匹配上就返回None,调用group()就会报错

  其他方法:

  split分割

ret = re.split('[ab]', 'abcd')  # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret)  # ['', '', 'cd']

  sub按参数将数字替换成某个字母

ret = re.sub('\d', 'H', 'eva3egon4yuan4', 1)  # 将数字替换成'H',参数1表示只替换1个
print(ret)  # evaHegon4yuan4

  subn将数字替换成某个字母,返回元组并将替换的次数显示

ret = re.subn('\d', 'H', 'eva3egon4yuan4')  # 将数字替换成'H',返回元组(替换的结果,替换了多少次)
print(ret)  # ('evaHegonHyuanH', 3)

  compile将正则表达式编译成为一个正则表达式对象,规则要匹配的是多少个数字就是多少个数字

obj = re.compile('\d{3}')  #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串
print(ret.group())  #结果 : 123

  finditer返回一个存放匹配结果的迭代器

import re
ret = re.finditer('\d', 'ds3sy4784a')   #finditer返回一个存放匹配结果的迭代器
print(ret)  # <callable_iterator object at 0x10195f940>
print(next(ret).group())  #查看第一个结果 3
print(next(ret).group())  #查看第二个结果 4
print([i.group() for i in ret])  #查看剩余的左右结果 ['7', '8', '4']

  起别名 

  可以在分组中利用?<name>的形式给分组起名字
  获取的匹配结果可以直接用group('名字')拿到对应的值

res = re.search('^[1-9](\d{14})(\d{2}[0-9x])?$','110105199812067023')
# 还可以给某一个正则表达式起别名
res1 = re.search('^[1-9](?P<password>\d{14})(?P<username>\d{2}[0-9x])?$','110105199812067023')

  注意:?P=tag_name相当于引用之前正则表达式,并且匹配到的值必须和前面的正则表达式一模一样

  findall的优先级查询;

import re

ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
print(ret)  # ['oldboy']     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可

ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
print(ret)  # ['www.oldboy.com']

  split的优先级查询

ret=re.split("\d+","eva3egon4yuan")
print(ret) #结果 : ['eva', 'egon', 'yuan']

ret=re.split("(\d+)","eva3egon4yuan")
print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']

三、正则在爬虫中的应用

import re
import json
from urllib.request import urlopen


"""
https://movie.douban.com/top250?start=0&filter=
https://movie.douban.com/top250?start=25&filter=
https://movie.douban.com/top250?start=50&filter=
https://movie.douban.com/top250?start=75&filter=


<li>
            <div class="item">
                <div class="pic">
                    <em class="">1</em>
                    <a href="https://movie.douban.com/subject/1292052/">
                        <img width="100" alt="肖申克的救赎" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class="">
                    </a>
                </div>
                <div class="info">
                    <div class="hd">
                        <a href="https://movie.douban.com/subject/1292052/" class="">
                            <span class="title">肖申克的救赎</span>
                                    <span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
                                <span class="other">&nbsp;/&nbsp;月黑高飞(港)  /  刺激1995(台)</span>
                        </a>


                            <span class="playable">[可播放]</span>
                    </div>
                    <div class="bd">
                        <p class="">
                            导演: 弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
                            1994&nbsp;/&nbsp;美国&nbsp;/&nbsp;犯罪 剧情
                        </p>            
                        <div class="star">
                                <span class="rating5-t"></span>
                                <span class="rating_num" property="v:average">9.6</span>
                                <span property="v:best" content="10.0"></span>
                                <span>1489907人评价</span>
                        </div>

                            <p class="quote">
                                <span class="inq">希望让人自由。</span>
                            </p>
                    </div>
                </div>
            </div>
        </li>
"""


def getPage(url):
    response = urlopen(url)
    return response.read().decode('utf-8')

def parsePage(s):
    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)

    ret = com.finditer(s)
    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):
    url = 'https://movie.douban.com/top250?start=%s&filter=' % num
    response_html = getPage(url)
    ret = parsePage(response_html)
    print(ret)
    f = open("move_info7", "a", encoding="utf8")

    for obj in ret:
        print(obj)
        data = str(obj)
        f.write(data + "\n")

count = 0
for i in range(10):
    main(count)
    count += 25
posted @ 2019-07-17 19:54  静心学  阅读(117)  评论(0)    收藏  举报