资讯专栏INFORMATION COLUMN

Python 从零开始爬虫(四)——强大的正则表达式,re模块

novo / 2592人阅读

摘要:为了逮住某个目标,你可能要写一条长长的,看到自己都头晕的正则表达式,看上去就像乱码一样。屁,学正则还不是迟早的事模块自带模块,直接导入即可。匹配规则规则其实是一个原字符串如表达式表达式,较正式的叫法是模式字符串。

如果把BeautifulSopu比喻成通过线索一步步接近目标的侦探的话,那么正则表达式就是牛逼哄哄的“天眼系统”,只要提供一些目标的特征,无论搜索范围多大,只要存在那么一两个符合特征的目标,全都会被它直接逮住。

特性 牛逼王

BS的爸爸,我告诉你个秘密,其实BeautifulSoup也是用正则实现的,而且它find_all的参数里还能接收正则呢

信息精确定位,BeautifulSoup用的是节点定位,可能会出现多个符合条件的节点(却没有目标信息);正则是直接针对目标信息,以字符为单位匹配,一次筛选出正确结果(前提是写好正则)

能获取信息的部分,有时候完整的信息不是你想要的,你只想取它的某一部分,正则能搞定,BS只能先获取完整信息再分离。

用途大着呢,不要以为正则只能爬虫,前后端都少不了正则,你填个信息判断是否合法这都是正则,总之学到赚到

劝退大王+

这么强大的方法是不是看到都心动了,不过强大是有代价的,较难上手很难精通这两根大棒一下子锤走了不少初学者。当时学的我是这样的:

抽象&可读性差。为了逮住某个目标,你可能要写一条长长的,看到自己都头晕的正则表达式,看上去就像乱码一样。举个栗子,如果你要匹配一个ip地址,正则表达式会是这样

匹配ip地址:((?:(?:25[0-5]|2[0-4]d|[01]?d?d).){3}(?:25[0-5]|2[0-4]d|[01]?d?d)) ——真·乱码

编写时出错率高,新手很难一次写对,需要不停地修改几次十几次才能pass(大脑在颤抖)

难于优化,优化好的正则能提高匹配速度,然而你这新手还想优化,能匹配对就很不错了(正则暗中偷笑)

如果有足够的自信和毅力不被正则击倒,那就来吧。(屁,学正则还不是迟早的事!)

re 模块

python 自带模块,直接导入即可。有匹配,替换等方法。
思考了许久后笔者觉得还是先讲表达式(规则)好,因为某些方法的理解是要了解表达式的。
下文的规则是完全版的,花了很久写成,分享给读者,顺便当成自己的网上笔记。

如果你学正则只是单单用来爬虫的话,你只要熟悉“字符匹配”,“分组&或&转义”,“预定字符集”,“数量词”,“非贪婪模式”和(?:)取消分组,了解(或干脆不学)“边界匹配”,“特殊构造”就行了。

如果你觉得正则是你未来工作的刚需的话,推荐熟悉所有规则。

匹配规则(pattern)

规则其实是一个原字符串如r"表达式"/r"表达式",较正式的叫法是模式字符串。最后再说一句,匹配以单个字符为单位(除括号能把多个字符打包成分组(整体)来匹配


表达式本质是字符串,不要单引(双引)号里套单引(双引)号,会出错。

字符匹配

任一字符(空格也算)——就是匹配这个字符,某些字符因为在正则中有特殊用途需前加反斜杠转义如 [ { . | ( ) ^ * + ? $

.——英文句号,匹配除换行符 外的任意单个字符

[]——匹配中括号里的任一字符,与-结合还能表示范围内的任一字符,中括号内的字符除外会自动转义,还有小心多个中括号嵌套错误

[^]——中括号最前面加^,与[ ]反义,匹配一个不在中括号里的字符,也可以用横杠-

r"[abcd]"#匹配一个a或b或c或d
r"[0-9]"#匹配一个0至9的数,-的作用域是左右各一个字符
r"[a-z]"  r"[A-Z]"#分别匹配a到z或A到Z的一个字母
r"[12-89]"#注意因为是单字符匹配,匹配的是1,2到8的数,9(即1到9的一个数),不是12到89的数
r"[{.|()^*+?$]"#匹配 { . | ( ) ^ * + ? $ 中任一个,要转义
r"[^a-zA-Z]"#匹配一个不是字母的字符

分组&或&转义

()——括号,表达式分组(第n组,n=1,2,3....99,从左往右数),并形成子表达式

(?P)——拥有括号的功能,但能为该分组再指定一个自定名字

(?P=name)——引用分配过名字的分组,但没有分组功能

|——或,左右规则任意匹配一个,从左往右尝试匹配,一旦成功就跳过后面的规则。|没被包在括号中间的话它的作用域是整个表达式,被包的话作用域在括号内

——反斜杠,后接功能字有符转义功能,后接数字(1到99)有引用分组的功能,后接某些字母又有特殊功能

r"abc|def|ghi"#匹配abc或def或ghi
r"ma(?:k|d)e"#匹配make或made
r"(abc)def1"#相当于r"(abc)defabc",匹配abcdefabc
r"(?Pabc)f(?P=ok)"#为(abc)子组分配了“ok”的名字,然后再引用,匹配abcfabc

预定字符集

d——匹配任一个数字(0~9)

D——匹配一个非数字字符,与d互补

s——匹配一个空白字符,包括空格, , , , ,f,v

S——匹配一个非空白字符

w——匹配一个单词字符。unicode下匹配各种语言的单个字符,单个数字,和下横线。ASCII下匹配单个英文字母,单个数字,和下横线

W——匹配一个非单词字符

r"w" #能匹配"物语&ものがたり"中的:物,语,も,の,が,た,り,汉语日语的单字,其他语言同理

数量词(接在字符或子组后)

{n}——作用于前一个字符或子表达式,匹配它重复n次

{min,max}——作用于前一个字符或子表达式,匹配它重复重复多少次min~max次,min和max可只写一个设置重复下限或上限,但逗号不能省,不写min时min默认为0

*——星号,作用于前一个字符或子表达式,匹配它零次或多次

+——作用于前一个字符或子表达式,匹配它至少一次

?——作用于前一个字符或子表达式,匹配它零次或一次

r"z{3}"#匹配zzz
r"z{0,3}"#匹配z或zz或zzz
r"(?:abc){2}"#对子表达式匹配两次,匹配abcabc,(?:)是一个用法,不分组的意思,详看后面
#星号加号问号同理

非贪婪模式

在数量词后接?,对前面的数量词开启非贪婪模式,意思就是在能匹配的前提下尽可能少的重复匹配

正则默认开启贪婪模式

r"<.+>"#默认贪婪,对于""能匹配到""整条,因为.贪婪地把尖括号也匹配掉了
r"<.+?>"#非贪婪,对于""能匹配到""和""
边界匹配

^——放在表达式的最前面,作用域是表达式,在多行模式中,在每一行匹配字符串开头(多行模式要手动开启,否则和A没什么区别)

$——放在表达式的最后面,作用域是表达式,在多行模式中,在每一行匹配字符串末尾(多行模式要手动开启,否则和没什么区别)

A——放在表达式的最前面,作用域是表达式,匹配字符串开头,不能多行匹配

——放在表达式的最后面,作用域是表达式,匹配字符串末尾,不能多行匹配

——不匹配字符,只匹配一个边界,匹配w和W或W和w的边界(单词字符和非单词字符的边界)

B——不匹配字符,只匹配一个边界,与相反,匹配w和w或W和W的边界

r"^abc|^def"#匹配abc开头或def开头,开启了多行模式时,对字符串"abcd
defh"能匹配出abc,def两个
r"abc$|def$"#匹配abc结尾或def结尾,开启了多行模式时,对字符串"0abc
0def"能匹配出abc,def两个
r"Aabc"#匹配abc开头,因为不能多行匹配,就算开启多行模式,对字符串"abcd
abcd"只能匹配到前面的abc
#同理
r"wW"#匹配“单词字符+非单词字符”的结构如"a!","1%"
#B同理

特殊构造(不作为分组,不被findall捕获)

(?:)——取消括号的分组功能,使其不会被findall方法捕获

(?#)——#后写注释内容,整个(?#)会被忽略

A(?=)——A之后的字符串需要匹配括号里的表达式A才会被匹配,一定用在表达式的最后(A是表达式,(?=)内的表达式不会被匹配捕捉,下同)

A(?!)——A之后的字符串需要不匹配括号里的表达式A才会被匹配,一定用在表达式的最后

(?<=)A——A之前的字符串需要匹配括号里的表达式A才会被匹配,一定用在表达式的最前,括号内的表达式需固定长度不能使用除{n}外的数量词

(?——A之前的字符串需要不匹配括号里的表达式A才会被匹配,一定用在表达式的最前,括号内的表达式需固定长度不能使用除{n}外的数量词

r"(ab(?=cde))"#匹配后面是bcd的ab
r"a(?!d+)"#匹配后面不跟一串数字的a,后括号可用所有数量词
r"(?<=abc)de"#匹配前面是abc的de
r"(?

(?iLmsux)——放在表达式最前面,为所在的表达式设置模式,”i”, “L”, “m”, “s”, “u”, “x”,它们不匹配任何字串,对应python中re模块当中的(re.I, re.L, re.M, re.S, re.U, re.X)的6种模式,下面flag参数讲

r"(?i)abc"#“i”对应re.I,忽略大小写模式,能匹配Abc,ABC,abc等

方法&参数

相比于繁杂的规则,方法则要简单多了,常用的就这几个:

re.search(pattern,string,flags=0),返回第一个匹配的match对象(内含匹配字符串的信息)

re.findall(pattern,string,flags=0),返回所有匹配分组的字符串组成的列表,没设置分组相当于整个表达式就是一个分组

#如果表达式有多个分组,会返回复杂的列表,因此findall中的表达式通常只有一个分组

re.finditer(pattern,string,flags=0),同findall功能,但是返回的是迭代器

re.findall(r"d+(abc)d+","1abc1,2abc2")#分组为(abc),findall只捕捉被数字包起来的abc返回列表["abc","abc"]
re.findall(r"((?:ab){2}d)d","abab11,abab22")#整个表达式匹配abab加一个两位数,(?:)取消了ab的分组,findall只捕捉abab加一个数,返回列表["abab1","abab2"]

pattern = re.compile(pattern,flags=0),把规则打包返回(如多次使用该规则),相当与pattern和flag的合体,当成pattern使用可免去设置flags

re.sub(pattern,repl,string,count=0,flags)把匹配到的部分用指定字符串repl替换,count设置替换次数,默认为零替换所有

参数:

pattern:接收模式字符串,即表达式,也可以接收打包的规则

string:接收待匹配字符串,如html文档

flags:模式(标签),接受以下模式,多个模式用“|”分开如 flags=re.I|re.M

re.I = re.IGNORECASE   忽略大小写

re.L = re.LOCALE   支持当前语言,为了支持多语言版本的字符集使用环境

re.U = re.UNICODE   使用w,W,b,B这些元字符时将按照UNICODE定义的属性

re.M = re.MULTILINE   开启多行模式

re.S = re.DOTALL   使.能匹配换行符

re.X = re.VERBOSE   可以忽略正则表达式中的空白和#号的注释,不匹配空格和#注释

re.A  开启ASCII模式

match对象方法

列出常用方法,下面的match是对象

match.group(id/name)id是分组序号(1~99),name是分组的自定名字,返回指定分组的字符串;不传参数数是返回整条匹配字符串

match.start(id/name),match.end(id/name),match.span(id/name),分别返回指定分组字符串在整个字符串中的开始位置,结束位置,范围。



地狱之旅到这就结束了,不仅是读者的,还是我的,お疲れ
文章过长,可能存在某些瑕疵和错误,欢迎提出
累成苟,最近而且要忙于学习,又被P大学事件恶心了一下,接下来的产能会下降,估计一个星期多一点更一次
正则慢慢学就行,正则的使用后面会有实例让大家熟悉

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/41584.html

相关文章

  • 关于爬虫解析数据4种方式

    摘要:大奉打更人卖报小郎君这个人仙太过正经言归正传从红月开始黑山老鬼稳住别浪跳舞二解析数据是一个可以从或文件中提取数据的库。 目录 一、XPath解析数据 1、XPath解析数据 2、XML的树形结构 3、使用XPath选取节点 4、课堂案例 - 爬取起点小说网 二、BeautifulSoup解析...

    newtrek 评论0 收藏0
  • Python 从零开始爬虫(五)——初遇json&爬取某宝商品信息

    摘要:能看到这里说明快进入动态网页爬取了,在这之前还有一两个知识点要了解,就如本文要讲的及其数据提取是什么是轻量级的文本数据交换格式,符合的格式的字符串叫字符串,其格式就像中字符串化后的字典,有时字典中还杂着列表字典,但是里面的数据都被双引号包着   能看到这里说明快进入动态网页爬取了,在这之前还有一两个知识点要了解,就如本文要讲的json及其数据提取 JSON 是什么   json是轻量级...

    2bdenny 评论0 收藏0
  • python爬虫抓取纯静态网站及其资源

    摘要:下面跟大家详细分享一下写爬虫抓取静态网站的全过程。而我们上面说的元字符都代表一定的规则和占据一定的字符。 遇到的需求 前段时间需要快速做个静态展示页面,要求是响应式和较美观。由于时间较短,自己动手写的话也有点麻烦,所以就打算上网找现成的。 中途找到了几个页面发现不错,然后就开始思考怎么把页面给下载下来。 由于之前还没有了解过爬虫,自然也就没有想到可以用爬虫来抓取网页内容。所以我采取的办...

    daydream 评论0 收藏0
  • Python 正则达式

    摘要:今天就专门看看正则表达式。下面是一个正则表达式最简单的使用例子。这个例子使用了正则表达式模块的函数,它会返回所有符合模式的列表。查询标志让正则表达式具有不同的行为。,按给定正则表达式分割字符串。,正则表达式中捕获组的数量。 最近研究Python爬虫,很多地方用到了正则表达式,但是没好好研究,每次都得现查文档。今天就专门看看Python正则表达式。本文参考了官方文档 re模块。 模式 首...

    FrancisSoung 评论0 收藏0

发表评论

0条评论

novo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<