《零基础入门学习Python》第057讲:论一只爬虫的自我修养5:正则表达式

news2025/1/18 20:54:36

如果你在课后有勤加练习,那么你对于字符串的查找应该是已经深恶痛绝了,你发现下载一个网页是很容易的,但是要在网页中查找到你需要的内容,那就是困难的,你发现字符串查找并没有你想象的那么简单,并不是说直接使用 find 方法找到匹配字符串的位置就可以了。

我们来举个例子,学习了前面几节课你应该已经尝试过写一个脚本来自动获取最新的代理 ip 地址,但是呢,你肯定会遇到困难,我现在来重现一下大家会遇到的困难。

大家肯定会先踩点,在 https://www.xicidaili.com/wt 网点审查元素,找一下代理 ip 前后有什么标签,例如:

ip 为 61.135.217.7 前后的标签为 td ,但是呢,别的地方也会有 td,但是里面包括的不是 ip 地址,你可能会费了九牛二虎之力,先找 table,再找 tbody,再找td,终于找到了 ip 地址的唯一特性,找到了一个 ip 地址,但是这样写不仅麻烦,而且不具有通用性,你在这个网站可行,在另外一个网站就不可行了,而且,万一站长哪天心血来潮,改了一下网页,那你更是心塞啊。

这时候你就会琢磨,可不可以按照我们需要的内容特征来进行自动查找呢?也就是说,如果我要找一个 ip 地址,那 ip 地址的特征是什么呢?

就是由 4 段数字组成,每段数字的范围是 0-255,分别是由3个点号隔开,这就是 ip 地址的特征嘛。根据这个特征,它去网页里面查找。

很抱歉,字符串所附带的方法你无法做到。

但是呢,我们遇到的问题,计算机老前辈们也早就已经想到了,并且已经帮我们设计出了非常优秀的解决方案,就是我们今天要讲的 正则表达式。

今天,我们将来学习使用 正则表达式来匹配 ip 地址。

关于正则表达式有一个非常经典的美式笑话:

有些人面临一个问题的时候会想:“我知道,可以使用正则表达式来解决这个问题。”于是,现在他就有两个问题了。

没错,正则表达式的确是很难学,但却非常有用。在编写字符串网页或程序的时候,经常会有查找某些符合复杂规则字符串的需求,例如,我们需要查找的 ip 地址的规则。那么,使用  Pythob 自带的字符串方法,你一定会恼羞成怒,那么这时候,如果你懂得正则表达式,你会发现,这真是灵丹妙药啊。

因为 正则表达式就是为了描述这些复杂规则的工具。正则表达式本身就是用于描述这些规则的。不同的语言均有使用正则表达式的方法,但各不相同,Python 是使用 re 模块来实现的,因为这一部分比较难,所以我们边举例子边讲解。

 
  1. >>> import re

  2. >>> re.search(r'Python', 'I love Python')

  3. <_sre.SRE_Match object; span=(7, 13), match='Python'>

  4. >>> re.search(r'Python', 'I love Python').span()

  5. (7, 13)

re.search方法

re.search 扫描整个字符串并返回正则表达式模式第一次成功匹配的位置。

函数语法:

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

函数参数说明:

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

匹配成功re.search方法返回一个匹配的对象,否则返回None。

有人就会认为,你说了这么多,和 find() 方法也没有什么区别啊,使用 find() 方法也可以实现上面的功能啊。如下:

 
  1. >>> ("I love Python".find('Python'), "I love Python".find('Python') + len('Python'))

  2. (7, 13)

那我们来一个 find() 方法没办法实现的:

大家都知道 通配符 (就是我们实际中经常使用的 * 和 ?这一类可以表示任何字符的符号),例如我们想找到 word 类型的文件的时候,我们就会搜索 *.docx。

正则表达式也有所谓的通配符,这里是使用点号(.),它可以匹配除了 换行符 以外的任何字符。

 
  1. >>> re.search(r'.', 'I love Python')

  2. <_sre.SRE_Match object; span=(0, 1), match='I'>

这里它就匹配到了字符串中的 ‘I’。

 
  1. >>> re.search(r'Pytho.', 'I love Python')

  2. <_sre.SRE_Match object; span=(7, 13), match='Python'>

这里 点号(.) 就匹配到了‘c’,然后正则表达式就匹配到了 ‘Python’。

看了上面的例子,会思考的小伙伴们就有了一个问题了,既然 点号(.)可以匹配任何字符,那我如果想要匹配 点号(.)字符本身,那你要怎么办?

正如 Python 的字符串规则一样,想要消除一个字符串的特殊功能,就在前面加上 反斜杠(\),如:

 
  1. >>> re.search(r'\.', 'I love Python.com')

  2. <_sre.SRE_Match object; span=(13, 14), match='.'>

这里 ‘\.’ 匹配的就是 点号(.)本身了,这时候,点号不代表任何其他字符,它只代表点号,前面的反斜杠已经将其解译了。

也就是说,在正则表达式中,反斜杠同样具有剥夺元字符的特殊功能的能力,什么是元字符,就是这个字符它本身代表着其他含义、有特殊功能的字符,例如 点号(.)。

同样呢,反斜杠还可以使得普通的字符具有特殊能力,例如 我们想要匹配数字,我们可以使用 ‘\d’ 来匹配任何数字,如:

 
  1. >>> re.search(r'\d', 'I love Python35.com')

  2. <_sre.SRE_Match object; span=(13, 14), match='3'>

 
  1. >>> re.search(r'\d\d', 'I love Python35.com')

  2. <_sre.SRE_Match object; span=(13, 15), match='35'>

OK,我们结合以上两点知识,就可以匹配一个 ip 地址大概会这么写:

 
  1. >>> re.search(r'\d\d\d\.\d\d\d\.\d\d\d\.\d\d\d', '192.168.111.123')

  2. <_sre.SRE_Match object; span=(0, 15), match='192.168.111.123'>

大家会看到,匹配成功了,但是我们这么写是有问题的。首先,\d 表示匹配的数字是 0~9,但是 ip 地址的约定范围每组数字的范围是 0~255,那你这里 \d\d\d 最大匹配数字是 999 ,而 ip 地址的最大范围是 255;然后,你这里要求 ip 地址每组必须是三位数字,但实际上有些 ip 地址中的某组数字只有 1 位或者 2 位,像这种情况,我们就匹配不了了。

那我们怎么解决呢?

为了表示一个字符串的范围,我们可以创建一个叫做 字符类 的东西,使用中括号[] 来创建一个字符类,字符类的含义就是你只要匹配字符类中的一个字符,那么就算匹配,举例:

我们想要匹配 元音字母(aeiou),我们就可以这样写:

 
  1. >>> re.search(r'[aeiou]', 'I love Python')

  2. <_sre.SRE_Match object; span=(3, 4), match='o'>

我们匹配到了 ‘o’,那大家可能会有疑惑了,为什么没有匹配大写字母 ‘I’ 呢,这是因为 正则表达式 是默认开启 大小字母敏感 模式的,所以 大写 ‘I’ 和小写 ‘i’ 会区分开来。解决的方案有两种,一种是关闭大小写敏感模式(后边进行讲解),另一种是修改我们的字符类[aeiou]为[aeiouAEIOU]。

你还可以在字符类中使用 横杆 ‘-’ 表示一个范围,例如:

 
  1. >>> re.search(r'[a-z]', 'I love Python')

  2. <_sre.SRE_Match object; span=(2, 3), match='l'>

 
  1. >>> re.search(r'[0-9]', 'I love 123 Python')

  2. <_sre.SRE_Match object; span=(7, 8), match='1'>

 
  1. >>> re.search(r'[2-9]', 'I love 123 Python')

  2. <_sre.SRE_Match object; span=(8, 9), match='2'>

数字范围的问题我们解决了,那接下来我们处理的第二个问题就是匹配个数的问题:

限定重复匹配的次数,我们可以使用 大括号 来解决,举例:

 
  1. >>> re.search(r'ab{3}c', 'abbbc')

  2. <_sre.SRE_Match object; span=(0, 5), match='abbbc'>

因为这个大括号里面的数字表示前面要匹配的字符要重复多少次。上面的 {3} 就表示前面的 b 匹配时要重复3次,即匹配 abbbc。

 
  1. >>> re.search(r'ab{3}c', 'abbbbc') #这样子就匹配不了,返回 None

  2. >>>

大括号里还可以给出重复匹配次数的范围,例如{a, b} 表示匹配 a 到 b 次。

 
  1. >>> re.search(r'ab{3,10}c', 'abbbbbbbc')

  2. <_sre.SRE_Match object; span=(0, 9), match='abbbbbbbc'>

接下来我们来考虑一下,如何使用正则表达式来匹配 0~255 ?

有些人想都不用想,就写给你看:

 
  1. >>> re.search(r'[0-255]', '188')

  2. <_sre.SRE_Match object; span=(0, 1), match='1'>

本来我们想匹配 188 ,结果只是匹配到了 1。

还有的同学会这样写:

 
  1. >>> re.search(r'[0-2][0-5][0-5]', '188')

  2. >>>

结果匹配不到。

跟你想象的不一样啊,要记住,正则表达式 匹配的是字符串,所以呢,数字对于字符来说,只有 0~9,例如 188,就是由1、8、8 这三个字符来组成的,并没有说 百十千 这些单位。所以呢,[0-255] 这个字符类(其中0-2,就是 0 1 2,后面两个 5 重复了)表示的是[0125]这四个数字中的某一个,所以 re.search(r'[0-255]', '188') 就只匹配到了一个 1。

所以呢,要匹配 0~255 这个范围里的数字,我们使用正则表达式应该这么写:

 
  1. >>> re.search('[01]\d\d|2[0-4]\d|25[0-5]', '188')

  2. <_sre.SRE_Match object; span=(0, 3), match='188'>

这里写的匹配的正则表达式就是 [01]\d\d 或者 2[0-4]\d 或者 25[0-5],这其中任何一个成立都是 ok 的。这里的 “或 ” 和 C语言中的 “或” 是一样的。

但是上面的写法还是存在问题,要求匹配的数字必须是 3 位的,例如:

 
  1. >>> re.search('[01]\d\d|2[0-4]\d|25[0-5]', '8')

  2. >>>

  3. >>> re.search('[01]\d\d|2[0-4]\d|25[0-5]', '18')

  4. >>>

可以像下面这样改写,让前面的两位可以重复 0 次(因为默认是重复1次嘛):

 
  1. >>> re.search('[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]', '8')

  2. <_sre.SRE_Match object; span=(0, 1), match='8'>

  3. >>> re.search('[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]', '80')

  4. <_sre.SRE_Match object; span=(0, 2), match='80'>

  5. >>> re.search('[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]', '118')

  6. <_sre.SRE_Match object; span=(0, 3), match='118'>

按照这样的话,我们就可以来匹配一个 ip 地址啦:

 
  1. >>> re.search('(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]', '192.168.42.1')

  2. <_sre.SRE_Match object; span=(0, 12), match='192.168.42.1'>

上面的小括号的意思就是分组,首先 ([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]) 作为一个组,然后加上 点号,(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.) 作为新的组,然后这个组重复3次,然后再加一组数字。这样就完成了对 ip 地址的匹配啦。

现在应该可以充分理解,“当你发现一个问题可以使用正则表达式来解决的时候,于是你就会有两个问题。”这句话的含义了。

但是大家也充分理解到掌握正则表达式的重要性,因为我们这里主要是讲 python爬虫,所以并没有花太多时间来讲正则表达式的隐藏技能,大家可以看一下Python正则表达式更深层次的知识:-> Python3 如何优雅地使用正则表达式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/779824.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

macOS mysql 8.0 忘记密码

╰─➤ mysql -V mysql Ver 8.0.33 for macos13.3 on arm64 (Homebrew)mysql.server status mysql.server stopskip-grant-tables 启动mysql ─➤ /opt…

Elemui表单合并

原代码形式 <template><el-table:data"tableData"borderstyle"width: 100%"><el-table-columnprop"date"label"日期"width"180"></el-table-column><el-table-columnprop"name"label…

Qt6 Qt Quick UI原型学习QML第五篇

文章目录 效果QML语法父文件 MyQML.qmlQML语法子文件 TLineEditV1.qmlQML语法子文件 TTextEdit.qml 效果 QML语法父文件 MyQML.qml import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.12Window {id: windowvisible: truewidth: 600height: 600title:…

【043】解密C++ STL:深入理解并使用 list 容器

解密C STL&#xff1a;深入理解并使用list容器 引言一、list 容器概述二、list容器常用的API2.1、构造函数2.2、数据元素插入和删除操作2.3、大小操作2.4、赋值操作2.5、数据的存取2.6、list容器的反转和排序 三、使用示例总结 引言 &#x1f4a1; 作者简介&#xff1a;一个热爱…

详细解析python视频选择--【思维导图知识范围】

C ,JAVA JAVAWEB ,微信小程序等 都有视频选择的分析。 语言视频选择收录专辑链接C张雪峰推荐选择了计算机专业之后-在大学期间卷起来-【大学生活篇】JAVA黑马B站视频JAVA部分的知识范围、学习步骤详解JAVAWEB黑马B站视频JAVAWEB部分的知识范围、学习步骤详解SpringBootSpringB…

Linux QT通过NFS挂载到Linux开发板上

Linux QT通过NFS挂载到Linux开发板上 说明&#xff1a;这里使用的Linux开发板是正点原子的阿尔法开发板 创建NFS 环境 NFS简介 网络文件系统&#xff0c;英文 Network File System(NFS)&#xff0c;是由 SUN 公司研制的 UNIX 表示层协议 (presentation layer protocol)&…

机器学习术语解析与应用(二)

文章目录 &#x1f340;目标函数&#xff08;Objective Function&#xff09;&#x1f340;GPU加速&#xff08;GPU Acceleration&#xff09;&#x1f340;迁移学习&#xff08;Transfer Learning&#xff09;&#x1f340;自然语言处理&#xff08;Natural Language Processi…

opencv 之 外接多边形(矩形、圆、三角形、椭圆、多边形)使用详解

opencv 之 外接多边形&#xff08;矩形、圆、三角形、椭圆、多边形&#xff09;使用详解 本文主要讲述opencv中的外接多边形的使用&#xff1a; 多边形近似外接矩形、最小外接矩形最小外接圆外接三角形椭圆拟合凸包 将重点讲述最小外接矩形的使用 1. API介绍 #多边形近似 v…

EasyUI Datagrid 应用

两种为 datagrid 赋值表格 number 1 <div class"easyui-layout" data-options"fit:true"><div data-options"region:center"><table id"storeTable" class"easyui-datagrid" style"width:100%;height:…

STM32(HAL库)驱动(2.0寸)TFT-LCD彩屏(240*320)

目录 1、简介 2、CubeMX初始化配置 2.1 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 屏幕引脚配置 2.3 项目生成 3、KEIL端程序整合 3.1 LCD驱动添加 3.2 函数修改 3.2.1 lcd.h修改 3.2.2 lcd_innit.h 修改 3.2.3 lcd.c修改 3.2.4 lcd_inut.c修改 3.3 主函数代码 3.3…

重新思考半监督医学图像分割:方差减少的视角

文章目录 Rethinking Semi-Supervised Medical Image Segmentation: A Variance-Reduction Perspective摘要本文方法实验结果 Rethinking Semi-Supervised Medical Image Segmentation: A Variance-Reduction Perspective 摘要 在医学图像分割中&#xff0c;对比学习是通过对…

Flink简介及部署模式

文章目录 1、Flink简介2、Flink部署2.1 本地模式2.1 Standalone模式部署2.2 Standalone模式下的高可用2.3 Yarn模式Yarn模式的高可用配置&#xff1a;yarn模式中三种子模式的区别&#xff1a; 3、并行度4、提交命令执行指定任务Application Mode VS yarn per-job 5、注意事项5、…

1 请使用js、css、html技术实现以下页面,表格内容根据查询条件动态变化。

1.1 创建css文件&#xff0c;用于编辑style 注意&#xff1a; 1.背景颜色用ppt的取色器来获取&#xff1a; 先点击ppt的形状轮廓&#xff0c;然后点击取色器&#xff0c;吸颜色&#xff0c;然后再点击形状轮廓的其他轮廓颜色&#xff0c;即可获取到对应颜色。 2.表格间的灰色线…

二,创建支付微服务提供者 第二章

<dependencies><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--监控--><dependency><groupId>org.springframewor…

微信小程序瀑布流组件

1.创建文件夹 /components/waterfall/ 文件夹结构如图 各文件内容&#xff1a; .wxml<view class"waterfallView"><view wx:for"{{resultData}}" wx:for-item"i" wx:for-index"iIndex" wx:key"iIndex" class&…

Idea 设置类和方法的注释(获取参数)

Idea 添加注释&#xff1a;类注释、方法注释 类注释 方法注释 类注释 File–Setting–Editor–File and Code Templates–Class: 注释模板&#xff1a; /** **description: *author: fqtang*time: ${DATE} ${TIME}* */ 操作截图&#xff1a; 效果&#xff1a; 方法注释 为了…

06.计算机网络——IP协议

文章目录 网络层IP协议基本概念协议头格式如何解包如何交付网段划分子网掩码特殊的IP地址IP地址的数量限制私有IP地址和公网IP地址路由 网络层 IP协议 IP协议提供一种将数据从A主机送达到B主机的能力&#xff0c;进行网络层的通信。 ​ IP协议 基本概念 主机 —— 配有IP地址…

HTML Audio对象属性、方法、事件及音乐播放器应用

分为两部分&#xff0c;前面主要介绍Html5为Audio对象提供了用于DOM操作的方法、属性和事件&#xff1b; 后面主要通过使用audio jquery bootstrap在浏览器底部实现的音乐播放器。 效果&#xff1a; 目录 Audio对象 常用方法 常用属性 常用事件 音乐播放器 Html页面 样式…

C进阶:内存操作函数

内存操作函数 memcpy 头文件&#xff1a;string.h 基本用途&#xff1a;进行不相关&#xff08;不重叠的内存&#xff09;拷贝。 函数原型&#xff1a;void* memcpy(void* destination,//指向目标数据的指针 const void* source,//指向被拷贝数据的指针 size_t num);//拷贝的数…

ES6解构对象、数组、函数传参

目录 1.对象解构 2.对象解构的细节处理 2.1.解构的值对象中不存在时 2.2.给予解构值默认参数 2.3.非同名属性解构 3.数组解构 3.1基础解构语法 3.2数组嵌套解构 4.函数解构传参 5.解构小练习 在ES6的新语法中新增了解构的方法&#xff0c;它可以让我们很方便的从数组或…