正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和字符串打交道,正则表达式更是不可或缺的技能,正则表达式的在不同的语言中使用方式可能不一样,不过只要学会了任意一门语言的正则表达式用法,其他语言中大部分也只是换了个函数的名称而已,本质都是一样的。
示例字符串:
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="referrer"><meta name="theme-color" content="#ffffff"><meta name="description" content="全球领先的中文搜索引擎、致力于让网民更便捷地获取信息,找到所求。百度超过千亿的中文网页数据库,可以瞬间找到相关的搜索结果。"><link rel="shortcut icon" href="
/favicon.ico
" type="image/x-icon" /><link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml
" title="百度搜索" /><link rel="icon" sizes="any" maskhref="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg
"><link rel="dns-prefetch" href="//dss0.bdstatic.com
"/><link rel="dns-prefetch" href="//dss1.bdstatic.com
"/><link rel="dns-prefetch" href="//ss1.bdstatic.com
"/><link rel="dns-prefetch" href="//sp0.baidu.com
"/><link rel="dns-prefetch" href="//sp1.baidu.com
"/><link rel="dns-prefetch" href="//sp2.baidu.com
"/><title>百度一下,你就知道</title><style index="newi" type="text/css">
<body>
<div class="c-tips-container" id="c-tips-container"></div>
<script>
var s_session={
"logId":"3614294667",
"seqId":"3614294907",
"sessionId":"",
"debug":false,
"userTips":"{}",
"curmod":"2",
"firstmod":"",
"logoCode":false,
"isFesLogo":false,
"sid":"36454_34813_36422_36166_36488_36055_36419_26350_36299_36468_36315_36447",
"mSid":"",
"sample_value":"",
"isLogin":false,
"agingVoice": "",
"卡卡": "632232258",
"Will": "1052949192",
"Phone": "18874922908"
};
window.__async_strategy = 2;
</script>
</body>
</html>
正则表达式基本语法
() :成对的小括号( )用来定义操作符的范围和优先度
+ :加号代表前面的字符必须至少出现一次(一次或多次)
res = re.findall('((<+)body>)',s)
print(res)
# 输出:[('<body>', '<')]
# body>必须出现异常<
? :问号代表前面的字符最多只可以出现一次(零次或一次)
res = re.findall('((<?)body>)',s)
print(res)
# 输出:[('<body>', '<'), ('body>', '')]
# body>前面可以不出现<
* :星号代表前面的字符可以不出现,也可以出现一次或者多次(零次、一次或多次)
res = re.findall('((<*)body>)',s)
print(res)
# 输出:[('<body>', '<'), ('body>', '')]
# body>前面可以不出现<,示例没有多个,所以表现为何问号一样
| :竖线|表示选择,具有最低优先级
res = re.findall('<body>|<html>',s)
print(res)
# 输出:['<html>', '<body>']
# 匹配<body>或者<html>
元字符 | 描述 |
\ | 将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,“\\n”匹配\n。“\n”匹配换行符。序列“\\”匹配“\”而“\(”则匹配“(”。即相当于多种编程语言中都有的“转义字符”的概念。 |
^ | 匹配输入字行首。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。 |
$ | 匹配输入行尾。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。 |
* | 匹配前面的子表达式任意次。例如,zo*能匹配“z”,也能匹配“zo”以及“zoo”。*等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。 |
? | 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”。?等价于{0,1}。 |
{n} | n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。 |
{n,} | n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。 |
{n,m} | m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o为一组,后三个o为一组。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。 |
? | 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少地匹配所搜索的字符串,而默认的贪婪模式则尽可能多地匹配所搜索的字符串。例如,对于字符串“oooo”,“o+”将尽可能多地匹配“o”,得到结果[“oooo”],而“o+?”将尽可能少地匹配“o”,得到结果 ['o', 'o', 'o', 'o'] |
.点 | 匹配除“\n”和"\r"之外的任何单个字符。要匹配包括“\n”和"\r"在内的任何字符,请使用像“[\s\S]”的模式。 |
[xyz] | 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。 |
[^xyz] | 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”任一字符。 |
[a-z] | 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。 注意:只有连字符在字符组内部时,并且出现在两个字符之间时,才能表示字符的范围; 如果出字符组的开头,则只能表示连字符本身. |
[^a-z] | 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。 |
更多基础语法可以参考:百度百科
Python正则模式
flags参数说明:
修饰符 | 描述 |
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
findall(pattern, string, flags=0) :找到并返回所有满足规则的字符串,需要得到匹配出来的数据
# 必须是[1-9]数字开头,然后是连续的5到13位数字
res = re.findall('[1-9][0-9]{5,13}',s)
print(res)
# 输出:['291521', '3614294667', '3614294907', '632232258', '1052949192', '18874922908']
search(pattern, string, flags=0) :查找第一次出现的位置
res = re.search('<html>',s)
print(res)
# 输出:<re.Match object; span=(1, 7), match='<html>'>
match(pattern, string, flags=0) :尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match() 就返回 none
res = re.match('<html>',s)
print(res)
# 输出:<re.Match object; span=(0, 6), match='<html>'>
Python正则应用大全
场景1:匹配两个字符串中间的字符
# 包含标志字符串
print(re.findall('<title>.*</title>',s))
# 输出:['<title>百度一下,你就知道</title>']
# 不包含标志字符串
print(re.findall('<title>(.*)</title>',s))
# 输出:['百度一下,你就知道']
场景2:提取两个字符串中间的字符,且包含换行
print(re.findall('<script>.*</script>',s,re.S))
场景3:提取json字符串
res = re.findall('s_session=({.*});',s,re.S)
print(res)
# 输出:['{\n\t\t"logId":"3614294667",\n\t\t"seqId":"3614294907",\n\t\t"sessionId":"",\n\t\t"debug":false,\n\t\t"userTips":"{}",\n\t\t"curmod":"2",\n\t\t"firstmod":"",\n\t\t"logoCode":false,\n\t\t"isFesLogo":false,\n\t\t"sid":"36454_34813_36422_36166_36488_36055_36419_26350_36299_36468_36315_36447",\n\t\t"mSid":"",\n\t\t"sample_value":"",\n\t\t"isLogin":false,\n\t\t"agingVoice": "",\n\t\t"卡卡": "632232258",\n\t\t"Will": "1052949192",\n\t\t"Phone": "18874922908"\n\t}']
场景4:去掉字符串中的空字符
res = re.findall('s_session=({.*});',s,re.S)
print(re.sub(r'\s{2,}', '', res[0]))
# 输出:{"logId":"3614294667","seqId":"3614294907","sessionId":"","debug":false,"userTips":"{}","curmod":"2","firstmod":"","logoCode":false,"isFesLogo":false,"sid":"36454_34813_36422_36166_36488_36055_36419_26350_36299_36468_36315_36447","mSid":"","sample_value":"","isLogin":false,"agingVoice": "","卡卡": "632232258","Will": "1052949192","Phone": "18874922908"}
场景5:提取连续数字
# 可以将7改成任意位数
print(re.findall('\d{7}',s,re.S))
# 输出:['3614294', '3614294', '6322322', '1052949', '1887492']
场景6:提取QQ号码,【1-9】开头的5位到14位数字
print(re.findall('[1-9][0-9]{4,13}',s,re.S))
# 输出:['291521', '3614294667', '3614294907', '36454', '34813', '36422', '36166', '36488', '36055', '36419', '26350', '36299', '36468', '36315', '36447', '632232258', '1052949192', '18874922908']
场景7:提取手机号码,[1-9][3-9]开头的11位数字
print(re.findall('[1-9][3-9][0-9]{9}',s))
# 输出:['18874922908']
场景8:获取link标签内容(贪心:会一直匹配到最后一个/>)
print(re.findall(r'<link .*/>',s,re.S))
# 输出:['<link rel="shortcut icon" href="\n\t/favicon.ico\n\t" type="image/x-icon" /><link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml\n\t" title="百度搜索" /><link rel="icon" sizes="any" maskhref="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg\n\t"><link rel="dns-prefetch" href="//dss0.bdstatic.com\n\t"/><link rel="dns-prefetch" href="//dss1.bdstatic.com\n\t"/><link rel="dns-prefetch" href="//ss1.bdstatic.com\n\t"/><link rel="dns-prefetch" href="//sp0.baidu.com\n\t"/><link rel="dns-prefetch" href="//sp1.baidu.com\n\t"/><link rel="dns-prefetch" href="//sp2.baidu.com\n\t"/>']
场景9:获取所有link标签内容(非贪心:匹配到第一个/>后停止)
print(re.findall(r'<link .*?/>',s,re.S))
# 输出:['<link rel="shortcut icon" href="\n\t/favicon.ico\n\t" type="image/x-icon" />', '<link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml\n\t" title="百度搜索" />', '<link rel="icon" sizes="any" maskhref="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg\n\t"><link rel="dns-prefetch" href="//dss0.bdstatic.com\n\t"/>', '<link rel="dns-prefetch" href="//dss1.bdstatic.com\n\t"/>', '<link rel="dns-prefetch" href="//ss1.bdstatic.com\n\t"/>', '<link rel="dns-prefetch" href="//sp0.baidu.com\n\t"/>', '<link rel="dns-prefetch" href="//sp1.baidu.com\n\t"/>', '<link rel="dns-prefetch" href="//sp2.baidu.com\n\t"/>']
未完,待续... ...