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

如果你在课后有勤加练习,那么你对于字符串的查找应该是已经深恶痛绝了,你发现下载一个网页是很容易的,但是要在网页中查找到你需要的内容,那就是困难的,你发现字符串查找并没有你想象的那么简单,并不是说直接使用 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 如何优雅地使用正则表达式

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Matlab】基于粒子群优化算法优化BP神经网络的数据回归预测(Excel可直接替换数据)

【Matlab】基于粒子群优化算法优化 BP 神经网络的数据回归预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理2.数学公式3.文件结构4.Excel数据5.分块代码5.1 fun.m5.2 main.m 6.完整代码6.1 fun.m6.2 main.m 7.运行结果 1.模型原理 基于粒子群优化算法&#xff08;…

3个能免费使用的AI绘画软件,效果精致

通过AI绘画软件&#xff0c;设计小白也能轻松创作出精美的图画创作。本文将为大家介绍3款能免费使用的AI绘画软件&#xff0c;它们能帮助设计小白或者经验丰富的设计师快速设计出精美的图画作品&#xff0c;一起来看看吧&#xff01; 1、即时灵感 即时灵感是国产的AI绘画软件…

[JAVAee]synchronized关键字

目录 1.synchronized的特性 ①互斥性 ②可重入性 2.synchronized的使用示例 ①修饰普通方法 ②修饰静态方法 ③修饰代码块 1.synchronized的特性 ①互斥性 互斥性,就像是给门上锁了一样. 当A线程使用了被synchronized修饰的代码块并对其上锁,其他线程(B线程,C线程)想要使…

C. Maximum Set

Problem - 1796C - Codeforces 思路&#xff1a;这个题在做的时候基本的思路是对的&#xff0c;但是没有想到O(1)求答案&#xff0c;枚举的然后T了&#xff0c;我们能够知道&#xff0c;假设前面的数小&#xff0c;那么每个数一定是前面的倍数&#xff0c;所以至少乘以2&#x…

vue3.2 + elementPlus + Windi CSS + ts创建一个好用的可兼容不同宽高的login页面

1.效果预览 2. 代码准备 导入windiCSS&#xff1a; npm i -D vite-plugin-windicss windicss windiCSS官网&#xff1a; https://cn.windicss.org/integrations/vite.html 使用vite创建好你的vue工程 sass版本为&#xff1a; 1.49.9 3.Windi CSS在页面中使用 apply 二次定义类名…

AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表

单链表. AcWing. 826.单链表 import java.util.Scanner; public class Main{static int[] e new int[100010];//结点i的值static int[] ne new int[100010];//结点i的next指针static int idx,head;//head是头结点&#xff0c;idx存当前已经用到了哪个点public static void i…

thinkphp6 验证码验证结果失败,可能是session开启位置错了!!!

搞了一下下午&#xff0c;始终提示验证码不正确 然后百度得到的结果都是&#xff1a;开启session&#xff0c;但是我开启了就是管用 <?php // 全局中间件定义文件 return [// 全局请求缓存// \think\middleware\CheckRequestCache::class,// 多语言加载// \think\middle…

【前端设计】使用Verdi查看波形时鼠标遮住了parameter值怎么整

盆友&#xff0c;你们在使用Verdi的时候&#xff0c;有没有遇到过鼠标遮挡着了parameter数值的场景&#xff1f;就跟下面这个示意图一样&#xff1a; 最可恨的是这个参数值他会跟着你的鼠标走&#xff0c;你想把鼠标移开看看看这个例化值到底是多大吧&#xff0c;这个数他跟着你…

单线程与多线程的理解与学习(入门到深入)

文章目录 一、在Java中&#xff0c;有多种方式可以创建线程。以下是几种常用的方法&#xff1a;二、线程的调度线程的调度分为两种调度模型分时调度模型抢占式调度模型 三、线程传值四、什么是线程同步五、线程安全六、线程的同步机制七、线程控制 一、在Java中&#xff0c;有多…

8.4Java EE——基于注解的AOP实现

Spring AOP的注解 元素 描述 Aspect 配置切面 Pointcut 配置切点 Before 配置前置通知 After 配置后置通知 Around 配置环绕方式 AfterReturning 配置返回通知 AfterThrowing 配置异常通知 下面通过一个案例演示基于注解的AOP的实现&#xff0c;案例具体实现…

全志F1C200S嵌入式驱动开发(调整cpu频率和dram频率)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 f1c200s默认的cpu频率是408M,默认的dram频率是156M。这两个数值,坦白说,都算不上特别高的频率。因为我们的晶振是24M输入,所以408/24=17,相当于整个cpu的频率只是晶振倍频了17…

node.js 爬虫图片下载

主程序文件 app.js 运行主程序前需要先安装使用到的模块&#xff1a; npm install superagent --save axios要安装指定版,安装最新版会报错&#xff1a;npm install axios0.19.2 --save const {default: axios} require(axios); const fs require(fs); const superagent r…

别在找git报错的解决方案啦,多达20条git错误解决方案助你学习工作

1. 找不到Git命令 $ sudo apt-get update $ sudo apt-get install git2. 无法克隆远程仓库 $ git clone https://github.com/username/repo.git3. 无法拉取或推送到远程仓库 $ git pull origin master $ git add . $ git commit -m "Resolve conflicts" $ git pus…

StableDiffusion 换脸实现

先看效果&#xff1a; 想要换的脸&#xff1a; 想要把脸放到的目标图片&#xff1a; 实现方案&#xff1a; StableDiffusionroop&#xff08;本次实验基于roopV0.02版本&#xff09; 1/安装SD&#xff0c;模型选择 DreamShaper,Sampler使用 Euler a 2/安装roop插件 roop插…

【隐式动态求解】使用非线性纽马克方法的隐式动态求解研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【ARM Coresight 系列文章 10.2 - ARM Coresight STM Trace packets】

文章目录 Trace protocolpacket的种类Error packetsVERSION Packets同步 packet 上篇文章&#xff1a;ARM Coresight 系列文章 10.1 - ARM Coresight STM 介绍及使用 下篇文章&#xff1a;ARM Coresight 系列文章 10.3 - ARM Coresight STM 寄存器介绍 及STM DMA 传输介绍 Trac…

【数据结构】树状数组和线段树

树状数组和线段树 下文为自己的题解总结&#xff0c;参考其他题解写成&#xff0c;取其精华&#xff0c;做以笔记&#xff0c;如有描述不清楚或者错误麻烦指正&#xff0c;不胜感激&#xff0c;不喜勿喷&#xff01; 树状数组 需求&#xff1a; 能够快速计算区间和保证在修改…

CSS背景虚化

.mark{background-color: rgba(0,0,0,.1);-webkit-backdrop-filter: blur(3px);backdrop-filter: blur(3px); }backdrop-filter CSS 属性可以让你为一个元素后面区域添加图形效果&#xff08;如模糊或颜色偏移&#xff09;。 因为它适用于元素背后的所有元素&#xff0c;为了看…

到底什么是前后端分离

目录 Web 应用的开发主要有两种模式&#xff1a; 前后端不分离 前后端分离 总结 Web 应用的开发主要有两种模式&#xff1a; 前后端不分离 前后端分离 理解它们的区别有助于我们进行对应产品的测试工作。 前后端不分离 在早期&#xff0c;Web 应用开发主要采用前后端不…

【C#】并行编程实战:异步流

本来这章该讲的是 ASP .NET Core 中的 IIS 和 Kestrel &#xff0c;但是我看了下这个是给服务器用的。而我只是个 Unity 客户端程序&#xff0c;对于服务器的了解趋近于零。 鉴于我对服务器知识和需求的匮乏&#xff0c;这里就不讲原书&#xff08;大部分&#xff09;内容了。本…