本期内容简介
我要我想要的,我们经常会有需要从一大堆文本中找到某个关键词以及他对应的前后左右的内容,同时也会碰到说想要找到符合某些规则的一些关键数据。比如,在安全场景下经常有的是,在网页中找到敏感数据(包括:手机号、身份证号、邮箱等敏感信息),在网页中找到敏感的链接/接口等等,这些东西是可以通过我们人眼去判断说哪些是符合我们想要的,但是很多时候这些文本又特别的长,让你无从下手,或者说会倒置需要花费过多的时间在这上面,得不偿失。本期的内容就是打算教会你怎么通过Python来帮你自动化、批量化地识别出这些数据,一步到位,实施”偷懒“行为。
Python正则匹配
本期内容主要讲的是Python的正则匹配(PS:正则表达式不是Python特有的,是Python中的re模块实现的正则),那正则表达式是什么?有什么用呢?
首先,正则表达式是使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。简单来说就是用来对字符串进行检索匹配和处理的。他的用处很多,只要是需要匹配字符串的场景我们都可能用到,举几个我在工作中用到的场景:
1、获取web页面源码后,提取页面里固定的信息(获取web页面源码在本专栏Python web编程里面会讲)
2、安全设备日志快速匹配想要的信息(在应急响应过程中可以使用,使用Notepad++编辑器提供正则表达式查找和替换文本的功能)
3、将文本内容进行匹配,存储到表格,可参考文章《“懒人”小工具之txt自动化写入excel脚本》。文章使用的是通过循环判断对应的内容,学完本章节,可以考虑使用正则匹配的方式去实现它。
Python正则表达式的使用方法
Python通过re模块提供对正则表达式的支持
导入模块:import re
模块方法:可以使用print(dir(re))进行查看,也可以通过官方文档进行查看,官方链接:http://docs.Python.org/
可以看到存在很多的函数和方法, 以下主要针对match和findall函数进行解释:
*1、match()*
用法:re.match(正则表达式,要匹配的字符串,flags=匹配模式),其中正则表达式和要匹配的字符串是必填的,匹配模式选填。匹配模式平时用的较少,有需要使用的情况可以自行查找。
使用re.match返回的是一个对象
如:
import re
word = 'hello word!'
h = re.match('hello',word)
print(h)
结果是:<re.Match object; span=(0, 5), match='hello'>,该对象返回的内容是匹配到的内容的开始位置和结束位置,以及匹配到的内容
match还存在以下几个方法:
group()返回匹配的字符串内容
span()返回一个元组包含匹配的开始和结束的位置,(开始,结束)
start()返回匹配开始的位置
end()返回匹配结束的位置
*2、findall()*
用法:与match()类似,re.findall(正则表达式,带匹配的字符串,flags=匹配模式)
使用re.findall返回的是一个数组
word = 'hello word!'
re.findall('hello',word)
结果是:['hello']
match和findall实际使用效果有所区别,具体使用哪个函数要根据实际场景进行选择。
正则表达式的基础知识:
了解了以上Python使用正则表达式的方法,接下来了解一下正则表达式怎么写。首先,需要知道正则表达式字符意义。
\1、******正则表达式字符意义:****
符号 | 含义 |
---|---|
^ | 以什么开头 |
$ | 以什么结尾 |
. | 匹配任意字符,除了换行符\n |
() | 标记组合 |
[…] | 用来表示一组字符,如[abc],表示匹配'a'或'b'或'c'。且可以使用-号代表x-x,如[0-9]表示0到9的所有数字,[a-z]表示a到z的所有字母。 |
[^…] | 取反 |
| | 表示或,匹配前面的或后面的字符 |
/ | 转义符,用于想要匹配预定义符号的时候 |
\d | 匹配任意数字,相当于[0-9] |
\D | 匹配任意非数字,相当于[^0-9] |
\w | 匹配字母、数字和下划线,相当于[0-9a-zA-Z_] |
\W | 匹配非字母、数字和下划线,相当于[^0-9a-zA-Z_] |
\s | 匹配任意的空白字符,相当于[\n\f\r\t\v] |
\S | 匹配任意的非空字符,相当于[^\n\f\r\t\v] |
\A | 匹配字符串开始 |
\z | 匹配字符串结束 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串 |
\G | 匹配最后匹配完成的位置 |
\b | 匹配单词边界 |
\B | 匹配非单词边界 |
? | 匹配1次或者0次 |
* | 匹配0次到无数次 |
+ | 匹配1次到无数次 |
{n,m} | 匹配n到m次 |
{n} | 匹配n次 |
{n+} | 匹配大于等于n次 |
普通字符 | 如a、B、1、>等,就匹配对应的字符 |
预定义字符 | 如:?、*、+、|等,代表的是以上的含义,当要匹配对应的字符时,可以使用转义符\,即要匹配“?”号时,使用”\?”进行匹配 |
2、贪婪模式和非贪婪模式
正则表达式通常用于在文本中查找匹配的字符串。Python里的数量词默认是贪婪的,意思是总是尝试尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。
数量词:?、*、+、{n,m}、{n+}
比如:表示0次到无数次,使用正则表达式“abc”(默认贪婪),如果用于查找“abcccccd”,将找到“abcccccd",而如果使用非贪婪方法”abc*?“,将找到”ab“
实战演练
讲了那么多的概念,终归还时要用在我们的实际环境中的,不要怕“概念那么多我记不住、字符那么多我记不住”,你记不住,你以为我就能记得住吗?不要怕,记不住就查,多用就能记住了。
案例开始,发现这样一个案例:手机靓号
拷贝的关于手机号的源码是以下这样的,分成了三个部分。
需求:将上面的手机号码拷贝下来;
提出解决方案:将三个部分都匹配下来,再将三个部分拼接起来,得到完整手机号
186-8253-5801
132-1920-0720
176-0825-3582
176-0825-6272
代码和结果如下:
正则表达式为:r'(\d{3}).?(\d{4}).?(\d{4})'
含义是:匹配数字3然后中间可以是任意字符,再匹配数字4中间再任意字符,再匹配数字*4。*(PS:以上正则表达式小括号的含义,用于标记你要匹配出来的结果)*
.表示任意字符,*表示任意次数,加上?表示非贪婪模式,也就是尽可能少。如果,没加问号会发生什么?
在每一行都有换行的时候,还是和上面的结果一样,因为默认是单行单行匹配的。再将换行符去掉的时候就会出来匹配错误的情况,匹配最开头和最结尾的情况。
动动手
看了那么多的知识和案例了,不妨动手来操作一下,不要怕写的程序不对,或者出问题,大胆尝试。可以的话,也可以自己找一找案例进行测试。
小案例:总所周知,我们手机号码的前三位是有一定的规则的,比如第一位为1
联通现有号段是:130、131、132、155、156、186、185,其中3G专属号段是:186、185。还有无线上网卡专属号段:145。
移动现有号段是:134、135、136、137、138、139、150、151、152、157、158、159、182、183、188、187。
电信现有号段是:133、153、180、181、189
查询百度得到如下结果,不一定准确,但是大家可以尝试一下以下的案例:
将以下号码符合要求的通过正则匹配匹配出来,再自行验证是否符合条件,也可以自行增加样例进行测试(ps:号码为虚构号码,如有雷同,纯属巧合。一个案例的正则表达式不是唯一的,能匹配到想要的字符串就是一个好的正则表达式)
*小提示:大家可以先尝试匹配出11位手机号,排除其他位数字符串的干扰,再对限定条件进行约束。*
01545872354
15823547854
19125487564
15566668888
1557236548
18925486548
189582415151
18888887777
168686855551
12152154824
13500001512