Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >写爬虫,怎么可以不会正则呢?

写爬虫,怎么可以不会正则呢?

作者头像
数据森麟
发布于 2019-09-27 07:16:36
发布于 2019-09-27 07:16:36
40000
代码可运行
举报
文章被收录于专栏:数据森麟数据森麟
运行总次数:0
代码可运行

本文转自公众号『大龄码农的Python之路』

很多人觉得正则很难,在我看来,这些人一定是没有用心。其实正则很简单,根据二八原则,我们只需要懂 20% 的内容就可以解决 80% 的问题了。我曾经有几年几乎每天都跟正则打交道,刚接手项目的时候我对正则也是一无所知,花半小时百度了一下,然后写了几个 demo,就开始正式接手了。三年多时间,我用到的正则鲜有超出我最初半小时百度到的知识的。

1、正则基础

1.1、基础语法

(1)常用元字符

语法

描述

\b

匹配单词的开始或结束

\d

匹配数字

\s

匹配任意不可见字符(空格、换行符、制表符等),等价于[ \f\n\r\t\v]。

\w

匹配任意 Unicode 字符集,包括字母、数字、下划线、汉字等

.

匹配除换行符(\n)以外的任意字符

^ 或 \A

匹配字符串或行的起始位置

$ 或 \Z

匹配字符串或行的结束位置

(2)限定词(又叫量词)

语法

描述

*

重复零次或更多次

+

重复一次或更多次

?

重复零次或一次

{n}

重复 n 次

{n,}

重复 n 次或更多次

{n,m}

重复 n 到 m 次

(3)常用反义词

语法

描述

\B

匹配非单词的开始或结束

\D

匹配非数字

\S

匹配任意可见字符, [^ \f\n\r\t\v]

\W

匹配任意非 Unicode 字符集

[^abc]

除 a、b、c 以外的任意字符

(4)字符族

语法

描述

[abc]

a、b 或 c

[^abc]

除 a、b、c 以外的任意字符

[a-zA-Z]

a 到 z 或 A 到 Z

[a-d[m-p]]

a 到 d 或 m 到 p,即 [a-dm-p](并集)

[a-z&&[def]]

d、e 或 f(交集)

[a-z&&[^bc]]

a 到 z,除了 b 和 c:[ad-z](减去)

[a-z&&[^m-p]]

a 到 z,减去 m 到 p:[a-lq-z](减去)

以上便是正则的基础内容,下面来写两个例子看下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = '123abc你好'
re.search('\d+', s).group()
re.search('\w+', s).group()

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
123
123abc你好

是不是很简单?

1.2、修饰符

修饰符在各语言中也是有差异的。

Python 中的修饰符:

修饰符

描述

re.A

匹配 ASCII字符类,影响 \w, \W, \b, \B, \d, \D

re.I

忽略大小写

re.L

做本地化识别匹配(这个极少极少使用)

re.M

多行匹配,影响 ^ 和 $

re.S

使 . 匹配包括换行符(\n)在内的所有字符

re.U

匹配 Unicode 字符集。与 re.A 相对,这是默认设置

re.X

忽略空格和 # 后面的注释以获得看起来更易懂的正则。

(1)re.A

修饰符 A 使 \w 只匹配 ASCII 字符,\W 匹配非 ASCII 字符。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = '123abc你好'
re.search('\w+', s, re.A).group()
re.search('\W+', s, re.A).group()

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
123abc
你好

但是描述中还有 \d\D,数字不都是 ASCII 字符吗?这是什么意思?别忘了,还有 全角和半角

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = '0123456789'    # 全角数字
re.search('\d+', s, re.U).group()

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0123456789

(2)re.M 多行匹配的模式其实也不常用,很少有一行行规整的数据。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = 'aaa\r\nbbb\r\nccc'

re.findall('^[\s\w]*?$', s)
re.findall('^[\s\w]*?$', s, re.M)

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
['aaa\r\nbbb\r\nccc']        # 单行模式
['aaa\r', 'bbb\r', 'ccc']    # 多行模式

(3)re.S 这个简单,直接看个例子。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = 'aaa\r\nbbb\r\nccc'

re.findall('^.*', s)
re.findall('^.*', s, re.S)

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
['aaa\r']
['aaa\r\nbbb\r\nccc']

(4)re.X 用法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
rc = re.compile(r"""
\d+ # 匹配数字
# 和字母
[a-zA-Z]+
""", re.X)
rc.search('123abc').group()

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
123abc

注意,用了 X 修饰符后,正则中的所有空格会被忽略,包括正则里面的原本有用的空格。如果正则中有需要使用空格,只能用 \s 代替。

(5)(?aiLmsux) 修饰符不仅可以代码中指定,也可以在正则中指定。(?aiLmsux) 表示了以上所有的修饰符,具体用的时候需要哪个就在 ? 后面加上对应的字母,示例如下,(?a)re.A 效果是一样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = '123abc你好'
re.search('(?a)\w+', s).group()
re.search('\w+', s, re.A).group()

结果是一样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
123abc
123abc

1.3、贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = 'aabab'
re.search('a.*b', s).group()    # 这就是贪婪
re.search('a.*?b', s).group()   # 这就是懒惰

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
aabab
aab

简单来说:

  • 所谓贪婪,就是尽可能 的匹配;
  • 所谓懒惰,就是尽可能 的匹配。
  • *+{n,} 这些表达式属于贪婪;
  • *?+?{n,}? 这些表达式就是懒惰(在贪婪的基础上加上 ?)。

2、正则进阶

2.1、捕获分组

语法

描述

(exp)

匹配exp,并捕获文本到自动命名的组里

(?Pexp)

匹配exp,并捕获文本到名称为 name 的组里

(?:exp)

匹配exp,不捕获匹配的文本,也不给此分组分配组号

(?P=name)

匹配之前由名为 name 的组匹配的文本

注意:在其他语言或者网上的一些正则工具中,分组命名的语法是 (?<name>exp)(?'name'exp) ,但在 Python 里,这样写会报错:This named group syntax is not supported in this regex dialect。Python 中正确的写法是:(?P<name>exp)

示例一:

分组可以让我们用一条正则提取出多个信息,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = '姓名:张三;性别:男;电话:138123456789'
m = re.search('姓名[::](\w+).*?电话[::](\d{11})', s)
if m:
    name = m.group(1)
    phone = m.group(2)
    print(f'name:{name}, phone:{phone}')

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
name:张三, phone:13812345678

示例二:

(?P<name>exp) 有时还是会用到的, (?P=name) 则很少情况下会用到。我想了一个 (?P=name) 的使用示例,给大家看下效果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = '''
<name>张三</name>
<age>30</age>
<phone>138123456789</phone>
'''

pattern = r'<(?P<name>.*?)>(.*?)</(?P=name)>'
It = re.findall(pattern, s)

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[('name', '张三'), ('age', '30'), ('phone', '138123456789')]

2.2、零宽断言

语法

描述

(?=exp)

匹配exp前面的位置

(?<=exp)

匹配exp后面的位置

(?!exp)

匹配后面跟的不是exp的位置

(?<!exp)

匹配前面不是exp的位置

注意:正则中常用的前项界定 (?<=exp) 和前项否定界定 (?<!exp) 在 Python 中可能会报错:look-behind requires fixed-width pattern,原因是 python 中 前项界定的表达式必须是定长的,看如下示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(?<=aaa)        # 正确
(?<=aaa|bbb)    # 正确
(?<=aaa|bb)     # 错误
(?<=\d+)        # 错误
(?<=\d{3})      # 正确

2.3、条件匹配

这大概是最复杂的正则表达式了。语法如下:

语法

描述

(?(id/name)yes|no)

如果指定分组存在,则匹配 yes 模式,否则匹配 no 模式

此语法极少用到,印象中只用过一次。

以下示例的要求是:如果以 _ 开头,则以字母结尾,否则以数字结尾。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s1 = '_abcd'
s2 = 'abc1'

pattern = '(_)?[a-zA-Z]+(?(1)[a-zA-Z]|\d)'

re.search(pattern, s1).group()
re.search(pattern, s2).group()

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
_abcd
abc1

2.4、findall

Python 中的 re.findall 是个比较特别的方法(之所以说它特别,是跟我常用的 C# 做比较,在没看注释之前我想当然的掉坑里去了)。我们看这个方法的官方注释:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Return a list of all non-overlapping matches in the string.

If one or more capturing groups are present in the pattern, return 
a list of groups; this will be a list of tuples if the pattern 
has more than one group.

Empty matches are included in the result.

简单来说,就是

  • 如果没有分组,则返回整条正则匹配结果的列表;
  • 如果有 1 个分组,则返回分组匹配到的结果的列表;
  • 如果有多个分组,则返回分组匹配到的结果的元组的列表。

看下面的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
s = 'aaa123bbb456ccc'

re.findall('[a-z]+\d+', s)          # 不包含分组
re.findall('[a-z]+(\d+)', s)        # 包含一个分组
re.findall('([a-z]+(\d+))', s)      # 包含多个分组
re.findall('(?:[a-z]+(\d+))', s)    # ?: 不捕获分组匹配结果

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
['aaa123', 'bbb456']
['123', '456']
[('aaa123', '123'), ('bbb456', '456')]
['123', '456']

零宽断言中讲到 Python 中前项界定必须是定长的,这很不方便,但是配合 findall 有分组时只取分组结果的特性,就可以模拟出非定长前项界定的效果了。

结语

其实正则就像是一个数学公式,会背公式不一定会做题。但其实这公式一点也不难,至少比学校里学的数学简单多了,多练习几次也就会了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据森麟 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Python】教你彻底了解Python中的正则表达式
正则表达式(Regular Expression,简称regex)是一种强大的字符串匹配和操作工具,用于搜索、匹配和替换字符串。在Python中,re模块提供了正则表达式的支持。本文将深入探讨Python中的正则表达式,涵盖正则表达式的基本概念、常用正则表达式模式、Python中正则表达式的使用方法、常见操作与应用场景,以及一些实际应用示例。
E绵绵
2025/05/25
1300
正则表达式
很多人觉得正则很难,在我看来,这些人一定是没有用心。其实正则很简单,根据二八原则,我们只需要懂 20% 的内容就可以解决 80% 的问题了。我曾经有几年几乎每天都跟正则打交道,刚接手项目的时候我对正则也是一无所知,花半小时百度了一下,然后写了几个 demo,就开始正式接手了。三年多时间,我用到的正则鲜有超出我最初半小时百度到的知识的。
Crossin先生
2019/09/05
5230
正则表达式
五、解析库之re模块
re模块 一:什么是正则? 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。 生活中处处都是正则:     比如我们描述:4条腿       你可能会想到的是四条腿的动物或者桌子,椅子等     继续描述:4条腿,活的           就只剩下四条腿的动物这一类了 二:常用匹配模式(元
用户1214487
2018/01/24
1.2K0
五、解析库之re模块
强烈推荐!Python 这个宝藏库 re 正则匹配
Python 的 re 模块(Regular Expression 正则表达式)提供各种正则表达式的匹配操作。
Wu_Candy
2022/07/05
1.6K0
【Python爬虫实战】正则:从基础字符匹配到复杂文本处理的全面指南
正则表达式作为一种强大的文本处理工具,广泛应用于编程、文本编辑和数据处理等领域。通过定义一系列字符和符号的组合,正则表达式能够快速识别、搜索、替换和操作文本中的特定模式,极大地提高了文本处理的效率。在 Python 中,re 模块提供了对正则表达式的支持,使得开发者能够轻松处理字符串中的复杂匹配问题。本篇文章将详细介绍正则表达式的基本作用、常用符号及其在 Python re 模块中的应用,帮助读者掌握如何利用正则表达式进行高效的文本处理。
易辰君
2024/11/07
2790
Python正则re模块学习笔记
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
没有故事的陈师傅
2019/07/28
6270
python基础学习14----正则表达
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
py3study
2020/01/19
3930
PYTHON正则学习记录
1.本文内容来自个人编写、python官方文档、参考菜鸟教程和网上部分解析。 2.本文加入大部分个人理解,并删去部分官方解释。可能存在理解错误,造成本文存在错误。
布衣者
2021/09/07
5970
re正则表格式
# coding=utf-8 # "正则表达式学习" import re # "match方法的工作方式是只有当被搜索字符串的开头匹配模式的时候它才能找到匹配对象" match = re.match(r'dog', 'dogsdf cat dog') print match.group() # "开头没有匹配cat,将返回None" match = re.match(r'cat', 'dog cat dog') print match # "使用re.search查找匹配任意位置,search方法不会
用户1733462
2018/06/01
6680
Python 学习之正则表达式
相信你此刻已经感受到了它的强大之处,接下来就让我们开始正则表达式的学习。先来介绍一下 re 模块。
用户4872888
2019/03/17
6510
Python正则表达式(下)
(1)match()从string首字母开始匹配,string如果包含pattern子串,则匹配成功,返回Match对象,失败则返回None;一般用于:完全匹配,用于严格的校验
小雨coding
2020/07/27
1.4K0
python中的正则表达式
则表达式, 是一门独立的搜索和匹配字符串的语言,只不过在各种编程语言中得到了实现,其中perl语言的正则表达式堪称是范本,很多其他编程语言都参考perl的正则语法来实现。python中的正则表达式通过内置模块re来实现,与perl的正则表达式操作类似,如果你熟悉perl语言的话,对于python的正则也可以轻松上手。
生信修炼手册
2020/05/07
1.1K0
Python正则表达式
前文介绍了正则表达式的定义和使用方法,今天我们就正式讲解Python中是如何使用正则表达式的,最后,通过一个简单的正则表达式运用,爬取网络中的网页数据。
罗罗攀
2021/01/29
4090
Python正则表达式
python3--re模块:正则表达式
根据手机号码一共11位并且只以13,14,15,18开头的数字这些特点,写了一段代码如下:
py3study
2018/08/02
8550
re模块和正则表达式
re模块 讲正题之前我们先来看一个例子:https://reg.jd.com/reg/person?ReturnUrl=https%3A//www.jd.com/ 这是京东的注册页面,打开页面我们就看
用户1214487
2018/01/23
7560
一文搞懂 Python 正则表达式用法
作者:枫叶云 来源:见文末 Python 正则表达式 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。 Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。 re 模块使 Python 语言拥有全部的正则表达式功能。 compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。 re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
小小科
2018/06/20
1.1K0
python re模块
正则表达式(可以称为REs,regex,regex pattens)是一个小巧的,高度专业化的编程语言,它内嵌于python开发语言中,可通过re模块使用。正则表达式的pattern可以被编译成一系列的字节码,然后用C编写的引擎执行。
py3study
2018/08/02
5870
【Python】正则表达式的艺术:轻松驾驭 Python 的re库
本文将会先介绍什么是正则表达式,然后在介绍正则表达式在python中的应用。 下方图片及案例思路来自:正则表达式
Yui_
2024/12/20
1890
【Python】正则表达式的艺术:轻松驾驭 Python 的re库
Python3 正则表达式特殊符号及用法.md
正则表达式(Regular expressions 也称为 REs,或 regexes 或 regex patterns)本质上是一个微小的且高度专业化的编程语言。 它被嵌入到 Python 中并通过 re 模块提供给程序猿使用;而且Python 的正则表达式引擎是用 C 语言写的,所以效率是极高的。
全栈工程师修炼指南
2020/10/23
2.7K0
【Python爬虫实战】正则:多字符匹配、开头与结尾定位、分组技术详解
正则表达式是一种灵活且强大的工具,用于匹配和操作文本。它广泛应用于编程、文本处理、数据清理和验证等领域。在 Python 中,通过内置的 re 模块,开发者可以轻松使用正则表达式来解决复杂的文本匹配问题。本篇文章详细介绍了正则表达式中的多字符匹配、开头和结尾匹配、分组匹配等重要概念及其应用。通过这些示例与技巧,读者将能够掌握如何在 Python 中运用正则表达式处理多种场景下的文本操作需求。
易辰君
2024/11/07
8570
相关推荐
【Python】教你彻底了解Python中的正则表达式
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验