【总结】爬虫2-正则表达式

爬虫2-正则表达式

1. 正则作用

正则表达式是一种可以让复杂的字符串问题变简单的工具

写正则表达式的时候就是用正则表达式来描述字符串规则

2. 正则表达式的语法

2.1 re模块

  • 提供了python中所有和正则相关的函数
from re import fullmatch, findall, search
  • fullmatch(正则表达式, 字符串) - 判断指定字符串是否满足正则表达式所描述的规

  • findall(正则表达式, 字符串) - 提取正则表达式所满足正则表达式的字串

  • search(正则表达式, 字符串) - 匹配字符串中第一个满足正则表达式的字串

    注意:pythhon中表达式一个正则表达式一般使用r字符串

2.2 正则符号

第一类符号:匹配字符符号

1)普通符号 - 在正则表达式中表示本身的符号

result = fullmatch(r'abc', 'abcc')
print(result)   # None, 只有' 

2). - 匹配任意一个字符

result = fullmatch(r'.bc', '*bc')
print(result)   # <re.Match object; span=(0, 3), match='*bc'>

result = fullmatch(r'.bc.', 'hbc*')     # 前后任意字符,中间必须是bc
print(result)   # <re.Match object; span=(0, 3), match='*bc'>

3)\d - 匹配任意一个数字字符

result = fullmatch(r'\d\dabc', '12abc')
result1 = fullmatch(r'\d\dabc', '1*abc')
print(result)
print(result1)  # None

4)\s - 匹配任意一个空白字符

  • 空白字符:空格(’ ‘)、换行(’\n’)、水平制表符(‘\t’)
  • 手动按tab表示4个空格(4个字符,但\s是一个字符)
result = fullmatch(r'123\sabc', '123 abc')
print(result)
result = fullmatch(r'123\sabc', '123    abc')
print(result)   # None 手动按tab表示4个空格(4个字符,但\s是一个字符)
result = fullmatch(r'123\sabc', '123\tabc')
print(result)

5)\w - 匹配任意一个字母、数字、下划线或者中文

result = fullmatch(r'123\wabc', '123好abc')
print(result)

result = fullmatch(r'123\wabc', '123*abc')
print(result)   # None

6)\D、\S、\W - 分别和\d、\s、\w功能相反

  • \D 不能匹配数字
result = fullmatch(r'123\Dabc', '1237abc')
print(result)   # None
  • \S 不能匹配空格
result = fullmatch(r'123\Sabc', '123 abc')
print(result)   # None
  • \W 不能匹配字母、数字、下划线或者中文
result = fullmatch(r'123\Wabc', '123+abc')
print(result)   # <re.Match object; span=(0, 7), match='123+abc'>

result = fullmatch(r'123\Wabc', '123_abc')
print(result)   # None

7)[字符集] - 匹配在字符集中的任意一个字符

  • [abc] - 匹配a或者b或者c
  • [abc\d] - 匹配a或者b或者c或者任意数字:[abc0123456789]
  • [0-9] - 匹配字符0到字符9的任意字符
  • [a-z] - 匹配任意一个小写字母
  • [A-Z] - 匹配任意一个大写字母
  • [a-zA-Z] - 匹配任意一个字母
  • [a-zA-Z\d] - 匹配任意一个字母或者数字
  • [a-z=%] - 匹配任意一个小写字母或者‘=’或者‘%’
  • [\u4e00-\u9fa5] - 匹配任意一个中文
# 在123和abc中间只能是M、9、你
result = fullmatch(r'123[M9你]abc', '123你abc')
print(result)

# 在123和abc中间匹配任意一个中文
result = fullmatch(r'123[\u4e00-\u9fa5]abc', '123你abc')
print(result)

8)[^字符集] - 匹配不在字符集中的任意字符

# 在123和abc中间匹配任意一个非小写字母
result = fullmatch(r'123[^a-z]abc', '123babc')
print(result)   # None

result = fullmatch(r'123[^a-z]abc', '123你abc')
print(result)  # <re.Match object; span=(0, 7), match='123你abc'>

第二类符号:匹配次数符号

1)* —— 任意次数(0次或者次数)

  • a* —— a出现任意多次
  • \d* —— 任意多个数字
  • [abc]* —— 多个abc中的字母
result = fullmatch(r'1[abc]*2', '1bbababbcc2')
print(result)

result = fullmatch(r'M\d*N', 'M459854420N')
print(result)

result = fullmatch(r'M[3-9]*N', 'M3893N')
print(result)

2)+ - 一次或者多次(至少一次)

result = fullmatch(r'Ma+N', 'MaaN')
print(result)

3) ? - 0次或者1次

result = fullmatch(r'Ma?N', 'MaaN')
print(result)   # None

4){}

  • {N} - N次
  • {M,N} - M到N次
  • {M,} - 至少M次
  • {,N} - 最多N次
# M和N之间只能是三个a
result = fullmatch(r'Ma{3}N', 'MaaN')
print(result)   # None

# M和N之间任意数字出现至少三次
result = fullmatch(r'M\d{3,}N', 'M23N')
print(result)   # None

练习:写一个正则表达式,可以匹配任意一个除了0的整数

# 合法:233、+345、-4561、
# 不合法:0、00034、2.23、+-345
result = fullmatch(r'[+-]?[1-9]\d*', '101')
print(result)

5) 贪婪和非贪婪

  • 在匹配次数不确定的时候,如果有多种次数匹配成功,贪婪取最多的次数,非贪婪取最少次数(默认是贪婪模式)
  • 贪婪模式:+、?
  • {M,N}、{M,}、{,N}、*
    非贪婪模式:+?、??、*?、{M,N}?、{M,}?、{,N}?
# 'aknb'、'aknbhuob'、'aknbhuobjfb'
# 默认贪婪模式,取最大次数
result = search(r'a.+b', '首农dgaknbhuobjfb')
print(result)   # <re.Match object; span=(4, 15), match='aknbhuobjfb'>

# 非贪婪模式,取最小次数
result = search(r'a.+?b', '首农dgaknbhuobjfb')
print(result)   # <re.Match object; span=(4, 8), match='aknb'>

第三类符号:分组和分支

1)分组 - ()

正则表达式中可以用()将部分内容表示一个整体;括号括起来的部分既是一个分组

  • 整体操作的时候需要分组
  • 重复匹配 - 正则中可以通过\M来重复它前面第M个分组来匹配的结果
  • 捕获 - 提取分组捕获到的结果(捕获分为自动捕获(findall)和手动捕获)
# '23M'、/89K10L'、'09H23Y67G90W'
result = fullmatch(r'(\d\d[A-Z])+', '09H23Y67G90W')
print(result)

# '23M23'、'90K90'
result = fullmatch(r'(\d\d)[A-Z]\1', '90K90')
print(result)

result = fullmatch(r'(\d{3})([a-z]{2})!=\2\1{2}', '234hj!=hj234234')
print(result)
  • findall在正则表达式找那个有分组的时候,会自动提取正则匹配结果中分组匹配到的内容
# 案例:提取中文后的数字
message = '单位房203jgi频数op09囧345=23jp-4vs'
result = findall(r'[\u4e00-\u9fa5](\d+)', message)
print(result)   # ['203', '345']
  • seach不能自动捕获,只能手动捕获

匹配结果.group(N) - 获取匹配结果中指定分组匹配到的内容

# 提取身高、体重
message = '我是小明明,今年12岁,身高180厘米,体重70kg'
result = search(r'身高(\d+)厘米,体重(\d+)kg', message)
print(result)   # <re.Match object; span=(12, 26), match='身高180厘米,体重70kg'>
print(result.group())   # 身高180厘米,体重70kg
print(result.group(1), result.group(2))  # 180 70

2)分支 - |

正则1|正则2|正则3|… - 先用正则1进行匹配,匹配成功直接成功;匹配失败用正则2进行匹配…

result = findall(r'\d{3}|[a-z]{2}', 'h34ugh4567uy')
print(result)   # ['ug', '456', 'uy']

# 'abc34'、'abcKP'、'abc56'、'abcHG'
# abc后是两个数字或者两个大写字母
result = fullmatch(r'abc(\d\d|[A-Z]{2})', 'abcKP')
print(result)

第四类:检测类符号

指匹配成功的时候检测所在位置是否符合要求

1)\b:检测是否是单词边界(任何可以将不同单词区分的符号:空白符号、标点符号、字符串开头、结尾)

print(fullmatch(r'abc\b123', 'abc123'))     # None
print(fullmatch(r'abc\b123', 'abc 123'))    # None
print(fullmatch(r'ab3\b', 'ab3'))    # <re.Match object; span=(0, 3), match='ab3'>
print(fullmatch(r'abc\s\b123', 'abc 123'))  # <re.Match object; span=(0, 7), match='abc 123'>

msg = '23红色多5弄了209,jsilh阿杰,欧6.7,派=p=q34f哦!66'
result = findall(r'\d+', msg)
print(result)       # ['23', '5', '209', '6', '7', '34', '66']
result = findall(r'\d+\b', msg)
print(result)       # ['209', '6', '7', '66']
result = findall(r'\b\d+\b', msg)
print(result)       # ['7', '66']

2)^ - 检测是否是字符串开头

print(findall(r'^\d+', msg))    # ['23']

3)$ - 检测是否是字符串结尾

print(findall(r'\d+$', msg))    # ['66']

转义符号

转义符号:在本身具有特殊功能的符号或者特殊意义的符号前加 \ ,让特殊符号变成普通符号

案例:匹配整数部分和小数部分都是两位数的小数

# '\.'表示的就是'.'
result = fullmatch(r'[1-9]\d\.\d\d', '34.09')
print(result)       # <re.Match object; span=(0, 5), match='34.09'>
# 任意两个数相加
result = fullmatch(r'\d+\+\d+', '3+09')
print(result)       # <re.Match object; span=(0, 4), match='3+09'>

# '(amd)'
result = fullmatch(r'\([a-z]{3}\)', '(amd)')
print(result)       # <re.Match object; span=(0, 5), match='(amd)'>

注意:单独存在有特殊意义的符号,在中括号中它的功能会自动消失

比如:.、*、+、?、()、$、^
组合符号不会消失:/s、/w、/d、/W、…
[]里需要有[、],需要用\

3. re模块

from re import fullmatch,findall,search,split, sub, finditer,match

1)fullmatch(正则, 字符串) - 用整个字符串和正则,匹配成功返回匹配对象,匹配不成功返回None
2)findall(正则, 字符串) - 获取字符串所有满足正则的子串,默认返回一个列表,列表中元素是所有匹配的子串(存在自动捕获现象)
3)seach(正则, 字符串) - 匹配第一个满足正则的子串,匹配成功返回匹配对象,匹配不成功返回None
4)split(正则, 字符串, N) - 将字符串中前N个满足正则的子串作为切割点进行切割
5)sub(正则, 字符串1, 字符串2, N) - 将字符串2中前N个满足正则的子串替换成字符串1
6)finditer(正则, 字符串) - 提取字符串中所有满足正则的子串,返回以一个迭代器,迭代器的元素是匹配对象
7)match(正则, 字符串) - 匹配字符串开头

str1 = '鸡7皮肤呢934u9njk4r流口水'
print(split(r'\d+', str1, 3))       # ['鸡', '皮肤呢', 'u', 'njk4r流口水']

str1 = '鸡7皮肤呢934u9njk4r流口水'
print(sub(r'\d', '*', str1))        # 鸡*皮肤呢***u*njk*r流口水

message = '我草,去你妈的,快点!sb,艹!SB'
print(sub(r'(?i)我草|妈的|sb|艹|f\s*u\s*c\s*k', '*', message))

str1 = '鸡7皮肤呢934u9njk4r流口水'
result = finditer(r'\d+', str1)
print(list(result))

result = match(r'\d{3}', '345加囧诶哦jod')
print(result)
  • 补充

1)忽略大小写: (?i)

print(fullmatch('(?i)abc', 'AbC'))

2)单行匹配:(?s)

  • 多行匹配(默认):.不能和换行符进行匹配

  • 单行匹配:可以和换行符进行匹配

print(fullmatch(r'abc.123', 'abc\n123'))    # None
print(fullmatch(r'(?s)abc.123', 'abc\n123'))    # <re.Match object; span=(0, 7), match='abc\n123'>

练习:爬取豆瓣电影TOP250的电影名和详情页网址

import requests
from re import findall
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36',
}
response = requests.get('https://movie.douban.com/top250', headers=headers)
result = response.text
# print(result)
name = findall(r'<img width="100" alt="(.+?)"', result)
print(name)
ip = findall(r'<a href="(.+?)" class="">', result)
print(ip)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值