一、什么是Re解析
“Re解析”是指使用正则表达式(regular expression,简称regex)进行文本解析或匹配的过程。
解析网页内容的三种方式:
1、bs4解析(最简单)
2、re解析(解析速度最快)
3、xpath解析(语法规则最舒服)
选择解析方法通常取决于要处理的文档类型和具体的任务需求。
Beautiful Soup适合处理不规范的HTML和简单的数据提取;
正则表达式适合对文本模式进行精确匹配和替换;
而XPath则是处理复杂XML文档和需要精确节点定位的首选工具。
二、正则表达式
正则的语法:使用元字符进行排列组合,用来匹配字符串。
(元字符:具有固定含义的特殊符号)
在线正则表达式测试网址:https://tool.oschina.net/regex/
1、常用元字符:
. (除换行符以外的任意字符) | |
\w (数字、字母和下划线) | \W (\w的反义) |
\d (数字) | \D (非数字) |
\s (空白符) | \S (非空白符) |
\n (换行符) | \t (制表符) |
^ (字符串的开始) (比如:^\d\d\d\d\d\d$) | $ (字符串的结尾) |
a|b (匹配字符串a或字符串b) (比如:10010|10086) | |
[...] (匹配字符组中含有的字符) (比如:[a-zA-Z0-9]表示 匹配所有数字和字母) | [^...] (匹配除了字符组中字符 的所有字符) |
2、量词:
量词:控制前面的元字符出现的次数
* | 重复0次或更多次 |
+ | 重复1次或更多次 |
? | 重复0次或1次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
比如:\d+表示一串数字,前后可以是其他类型的内容
^\d+表示字符串的开头必须是一串数字 (前面不能有其他类型的内容)
3、贪婪匹配和惰性匹配:
.* | 贪婪匹配 |
.*? | 惰性匹配 |
贪婪匹配:尽可能多地匹配内容
惰性匹配(爬虫常用):尽可能少地匹配内容
举个例子:
玩儿开心消消乐游戏吗?晚上一起玩游戏。干嘛呢?打游戏啊!
匹配:玩儿.*?游戏
结果:玩儿开心消消乐游戏
原理:回溯算法
先找“玩儿”,然后“.*游戏”表示尽可能多地找,找到最后一个“游戏”,再是“?”表示尽可能少地找,逼迫着计算机回溯找反方向的最后一个“游戏”。
三、Re模板
Re模板为python自带的内置模块,是标准库的一部分,不需要自己安装。
六小点:
1、findall(正则,字符串) 全局匹配,返回列表list
2、finditer 全局匹配,返回迭代器iter ( .group() )
3、search 仅能匹配出第一个结果 ( .group() )
4、match 从头开始匹配(相当于给正则加上^)( .group() )
5、compile(正则) 预加载
6、(?P<组名>正则) 精细筛选 ( .group(“组名”))
注意:要不要加上“ ”
import re # re.findall(pattern,string,flags=0) # 返回字符串中所有符合正则的内容,组成一个列表 list=re.findall(r"\d+","我的电话号码是:10086,他的电话号码是:10010") print(list) #"\d"前加r,可以防止出现波浪线 # re.finditer(pattern,string,flags) # 返回字符串中所有符合正则的内容(不过以match方式呈现),组成一个迭代器 it=re.finditer(r"\d+","我的电话号码是:10086,他的电话号码是:10010") for i in it: print(i.group()) # list可以直接到打印,而迭代器需要利用for循环来逐个打印其中内容(迭代器的效率比列表高) # 迭代器中包含的是match对象,要想拿到实际内容需要用到.group() # re.search(pattern,string,flags) # 返回字符串中第一个符合正则的内容(不过以match方式呈现),相当于迭代器的第一个迭代结果 s=re.search(r"\d+","我的电话号码是:10086,他的电话号码是:10010") print(s.group()) # 要想拿到实际数据同样要用到.group() # re.match(pattern,string,flags) # 从头开始匹配,相当于把"\d+"变成了"^\d+",表示字符串的开头必须是纯数字 # 否则会出现AttributeError: 'NoneType' object has no attribute 'group' m=re.match(r"\d+","10086,他的电话号码是:10010") print(m.group()) # find全局匹配(findall返回列表,finditer返回迭代器),search匹配第一个,match从头开始匹配 #预加载(预编译)正则表达式(若正则表达式很长,先预加载好,后续直接用、反复用,可以提高一点效率) # obj=re.comfile(pattern,flags) # obj.finditer(string) obj=re.compile(r"\d+") it=obj.finditer("我的电话号码是:10086,他的电话号码是:10010") for i in it: print(i.group()) content=""" <div class='a'><span id='1'>刘亦菲</span></div> <div class='b'><span id='2'>宋祖儿</span></div> <div class='c'><span id='3'>谷爱凌</span></div> """ # re.S: 让 . 能匹配换行符,防止匹配的内容断掉 obj1=re.compile(r"<div class='.*?'><span id='(?P<id>\d+)'>(?P<wahaha>.*?)</span></div>",re.S) res=obj1.finditer(content) for i in res: print(i.group("wahaha")) print(i.group("id")) # 就是套娃,写模板 # 精细筛选(可以单独从正则匹配的内容中进一步提取内容):(?P<组名>正则) .group("组名")