python 爬虫4 - re模块(正则表达式)

一、正则表达式

1.概念

正则表达式(Regular Expression,简称 Regex)是一种用于匹配字符串的模式。它可以用来搜索、替换、验证文本中的特定模式。Python 中的 re 模块提供了对正则表达式的支持。

2.语法

正则表达式的语法相对复杂,但理解其核心概念后,可以用非常简洁的方式来表达字符串匹配规则

符号解释
.匹配任意单个字符(除换行符)。
^匹配字符串的开头。
$匹配字符串的结尾。
*匹配前面的字符 0 次或多次。
+匹配前面的字符 1 次或多次。
?匹配前面的字符 0 次或 1 次。
{n}匹配前面的字符恰好 n 次
{n,}匹配前面的字符至少 n 次
{m,n}匹配前面的字符至少 m 次,至多 n 次。
[]匹配方括号中的任意一个字符(字符类)。
\转义字符,用于匹配一些特殊字符,例如 \. 匹配句点。
()分组,标记一个子表达式。
|或运算符,匹配左边或右边的模式

3.常用字符

表达式说明
\d匹配任何十进制数字,等价于 [0-9]
\D匹配任何非数字字符。
\w匹配任何字母数字字符,等价于 [a-zA-Z0-9_]
\W匹配任何非字母数字字符。
\s匹配任何空白字符(空格、制表符等)。
\S匹配任何非空白字符。

二、re 模块

re模块使得python拥有全部的正则表达式功能。

1.作用

通过使用正则表达式,可以:

  • 测试字符串内的模式。
  • 替换文本。
  • 基于模式匹配从字符串中提取子字符串。

2.re 模块函数

(1)re.match( )

字符串开头进行匹配,如果匹配成功则返回 Match 对象,否则返回 None

语法:

re.match(pattern, string, flags=0)

参数:

参数解释
pattern匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

返回值:

匹配对象和方法描述
group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
import re
 
line = "Cats are smarter than dogs"

# .* 表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
# (.*?) 表示"非贪婪"模式,只保存第一个匹配到的子串
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
 
if matchObj:
   print ("matchObj.group() : ", matchObj.group())
   print ("matchObj.group(1) : ", matchObj.group(1))
   print ("matchObj.group(2) : ", matchObj.group(2))
else:
   print ("No match!!")

(2)re.search()

在整个字符串中搜索,返回第一个成功匹配Match 对象。

 语法:

re.search(pattern, string, flags=0)

参数:

参数解释
pattern匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

返回值:

匹配对象和方法描述
group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
import re

result = re.search(r"world", "hello world")
if result:
    print(result.group())  # Output: world

match 和 rearch 的区别:

方法区别
re.match字符串开头进行匹配,如果开始不匹配,则匹配失败
re.rearch匹配整个字符串,直到找到一个匹配

(3)re.findall()

返回字符串中所有非重叠的匹配项,结果为列表。

语法:

re.findall(pattern, string, flags=0)
或
pattern.findall(string[, pos[, endpos]])

参数:

参数解释
pattern匹配的正则表达式
string要匹配的字符串。
pos可选参数,指定字符串的起始位置,默认为 0。
endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
注意: match 和 search 是匹配一次 findall 匹配所有。
import re

result = re.findall(r"\d+", "My numbers are 123 and 456")
print(result)  # Output: ['123', '456']

(4)re.finditer()

返回所有匹配项的迭代器,每个匹配项为一个 Match 对象,返回值为迭代器

语法:

re.finditer(pattern, string, flags=0)

参数:

参数解释
pattern匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
import re

result = re.finditer(r"\d+", "My numbers are 123 and 456")
for match in result:
    print(match.group())  # Output: 123, 456

(5)re.sub()

替换匹配的字符串,可以控制替换次数。

语法:

re.sub(pattern, repl, string, count=0, flags=0)

参数:

参数描述
pattern 正则中的模式字符串。
repl 替换的字符串,也可为一个函数。
string 要被查找替换的原始字符串。
count 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
flags 编译时用的匹配模式,数字形式。

import re

result = re.sub(r"apple", "orange", "apple pie and apple juice")
print(result)  # Output: orange pie and orange juice

repl是一个函数:

#!/usr/bin/python
 
import re
 
# 将匹配的数字乘以 2
def double(matched):
    value = int(matched.group('value'))
    return str(value * 2)
 
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))

(6)re.split()

使用匹配的子串来分割字符串,返回列表。

语法:

re.split(pattern, string[, maxsplit=0, flags=0])

参数:

描述
pattern匹配的正则表达式
string要匹配的字符串。
maxsplit分割次数,maxsplit=1 分割一次,默认为 0,不限制次数。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
result = re.split(r"\s+", "This is a test")
print(result)  # Output: ['This', 'is', 'a', 'test']

(7)re.compile()

语法:

re.compile(pattern[, flags])

参数:

参数描述
pattern 一个字符串形式的正则表达式
flags 可选,表示匹配模式,比如忽略大小写,多行模式等

import re
pattern = re.compile(r'\d+')                    # 用于匹配至少一个数字
m = pattern.match('one12twothree34four')        # 查找头部,没有匹配
 print( m )
m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配
print( m )
m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
print( m )                                        # 返回一个 Match 对象
m.group(0)   # 可省略 0
m.start(0)   # 可省略 0
m.end(0)     # 可省略 0
m.span(0)    # 可省略 0
  • group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
  • start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
  • end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
  • span([group]) 方法返回 (start(group), end(group))。

3.标志位

标志描述示例
re.IGNORECASE 或 re.I使匹配对大小写不敏感
import re
pattern = re.compile(r'apple', flags=re.IGNORECASE)
result = pattern.match('Apple')
print(result.group())  # 输出: 'Apple'
re.MULTILINE 或 re.M多行匹配,影响 ^ 和 $,使它们匹配字符串的每一行的开头和结尾。
import re
pattern = re.compile(r'^\d+', flags=re.MULTILINE)
text = '123\n456\n789'
result = pattern.findall(text)
print(result)  # 输出: ['123', '456', '789']
re.DOTALL 或 re.S:使 . 匹配包括换行符在内的任意字符。
import re
pattern = re.compile(r'a.b', flags=re.DOTALL)
result = pattern.match('a\nb')
print(result.group())  # 输出: 'a\nb'
re.ASCII使 \w, \W, \b, \B, \d, \D, \s, \S 仅匹配 ASCII 字符
import re
pattern = re.compile(r'\w+', flags=re.ASCII)
result = pattern.match('Hello123')
print(result.group())  # 输出: 'Hello123'
re.VERBOSE 或 re.X忽略空格和注释,可以更清晰地组织复杂的正则表达式。
import re
pattern = re.compile(r'''
    \d+  # 匹配数字
    [a-z]+  # 匹配小写字母
''', flags=re.VERBOSE)
result = pattern.match('123abc')
print(result.group())  # 输出: '123abc'

三、示例

1.提取电子邮件地址

import re

text = "Contact us at support@example.com or sales@example.org"
emails = re.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", text)
print(emails)  # Output: ['support@example.com', 'sales@example.org']

2.替换电话号码

import re

text = "My old phone number was 123-456-7890."
new_text = re.sub(r"\d{3}-\d{3}-\d{4}", "XXX-XXX-XXXX", text)
print(new_text)  # Output: My old phone number was XXX-XXX-XXXX.

3.分割字符串

import re

text = "apple, orange; banana: grape"
fruits = re.split(r"[,;:\s]+", text)
print(fruits)  # Output: ['apple', 'orange', 'banana', 'grape']

4..* 贪婪匹配示例

print(re.findall("a.*d","a11b222d2d33"))

5..*? 非贪婪匹配示例

print(re.findall("a.*?d","a11b222d2d33"))

6.爬虫中的示例

获取豆瓣top250的电影信息

# 拿到页面源代码   requests
# 使用re模块提取
import requests
import re
import csv
url = "https://movie.douban.com/top250"
head = {
    "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
}

for j in range(0, 300, 25):
    param = {
        "start": j
    }
    res = requests.get(url, headers=head, params=param)
    pageContent = res.text

    # 解析数据
    obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<moveName>.*?)'
                    r'</span>.*?<p class="">.*?<br>(?P<year>.*?)&nbsp.*'
                    r'/&nbsp;(?P<conuyty>.*?).*?'
                    r'&nbsp;(?P<type>.*?).*?'
                    r'<span class="rating_num" property="v:average">(?P<average>.*?)'
                    r'</span>.*?<span>(?P<num>.*?)人评价</span>.*?', re.S)
    # 打开文件,指定newline=''(对于Unix系统)或newline='\n'(对于Windows系统)
    f = open("豆瓣top250.csv","a+",encoding="utf-8", newline="\n")
    csvWriter = csv.writer(f)
    for i in obj.finditer(pageContent) :
        # print(i.group("moveName"),i.group("year").strip(),i.group("average"),i.group("num"))
        dict = i.groupdict()
        dict['year'] = dict['year'].strip()
        dict['num'] = dict['num'].strip()
        # dict['type'] = dict['type'].strip()
        print(dict)
        csvWriter.writerow(dict.values())
    f.close()

更多示例:

Python之re模块详解 (超级无敌宇宙灭霸详细)_python re-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shin zhong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值