【re正则表达式】------- PYTHON爬虫基础1

【re正则表达式】------- PYTHON爬虫基础1

我们在爬虫过程中经常需要检索那些符合某个模式(规则)的特定文本,这个时候可以用re正则表达式来帮忙。
正则表达式是对字符串操作的一种逻辑公式,就是用一些定义好的特定字符,及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑。

新手入门干货

在线正则表达式测试链接

文章开始之前先推荐一个在线正则表达式测试链接(https://tool.oschina.net/regex )
在线正则表达式测试链接

re 基础表达式

模式 描述
^ 匹配字符串的开头
$ 匹配字符串的末尾
* 匹配0个或多个的表达式
+ 匹配1个或多个的表达式
. 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符
[…] 用来表示一组字符,单独列出:[amk] 匹配 ‘a’,‘m’或’k’
[^…] 不在[]中的字符:abc 匹配除了a,b,c之外的字符
? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
{n} 精确匹配 n 个前面表达式。例如, o{2} 不能匹配 “Bob” 中的 “o”,但是能匹配 “food” 中的两个 o
{n,} 匹配 n 个前面表达式。例如, o{2,} 不能匹配"Bob"中的"o",但能匹配 "foooood"中的所有 o。“o{1,}” 等价于 “o+”。“o{0,}” 则等价于 “o*”。
{n,m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a b
(re) 匹配括号内的表达式,也表示一个组
(?imx) 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?-imx) 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?: re) 类似 (…), 但是不表示一个组
(?imx: re) 在括号中使用i, m, 或 x 可选标志
(?-imx: re) 在括号中不使用i, m, 或 x 可选标志
(?#…) 注释.
(?= re) 前向肯定界定符。如果所含正则表达式,以 … 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
(?! re) 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
(?> re) 匹配的独立模式,省去回溯。
\w 匹配字母数字及下划线
\W 匹配非字母数字及下划线
\s 匹配任意空白字符,等价于 [\t\n\r\f].
\S 匹配任意非空字符
\d 匹配任意数字,等价于 [0-9].
\D 匹配任意非数字
\A 匹配字符串开始
\Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。
\z 匹配字符串结束
\G 匹配最后匹配完成的位置。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
\B 匹配非单词 边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
\n, \t, 等. 匹配一个换行符。匹配一个制表符。等
\1…\9 匹配第n个分组的内容。
\10 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。

正文

1.匹配函数 re.match

尝试从字符串的起始位置匹配一个模式,如果不是起始位置就匹配成功的话,match()就返回None。
语法:re.match(pattern,string,flags())

1.1 最常规的匹配

python3环境下输入:

import re
content = "Hello 123 4567 World_This is a Regex Demo"
print(len(content))
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$',content)  #匹配整个content
print(result)
print(result.group())  #匹配结果
print(result.span())   #匹配结果的范围

结果输出为:

41
<re.Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
Hello 123 4567 World_This is a Regex Demo
(0, 41)

知识点

  • 1)len(content) :计算content的长度,注意空格也算一个长度
  • 2)匹配细节
    ^匹配字符串的开头
    \s匹配任意空白字符,这里匹配空格
    \d匹配任意数字,等价于 [0-9];\d\d\d这里连续3个数字123;\d{4}匹配连续4个数字4567;
    \w匹配字母数字及下划线,w{10}这里匹配World_This;
    . 匹配任意字符,除了换行符。*匹配0个或多个的表达式。
    .*这里匹配 is a Regex ;注意这里是包含空格的。
    $:匹配字符串的末尾。

1.2 泛匹配

python3环境下输入:

import re
content = "Hello 123 4567 World_This is a Regex Demo"
result = re.match('^Hello.*Demo$',content)
print(result)
print(result.group())  
print(result.span())  

结果输出为:

<re.Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
Hello 123 4567 World_This is a Regex Demo
(0, 41)

知识点

  • .*这里匹配 123 4567 World_This is a Regex

1.3 匹配目标(提取部分)

python3环境下输入:

import re
content = "Hello 1234567 World_This is a Regex Demo"
result = re.match('^Hello\s(\d+)\sWorld.*Demo$',content)
print(result)
print(result.group(1))  #匹配第一个括号内的结果
print(result.span())   

结果输出为:

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567
(0, 40)

知识点

  • 匹配1个或多个的表达式。\d+这里匹配1234567。
  • 将提取部分加上括号,eg: (\d+)。对应地 result.group(1)) #返回第一个括号内的结果

1.4 贪婪匹配.*

python3环境下输入:

import re
content = "Hello 1234567 World_This is a Regex Demo"
result = re.match('^He.*(\d+).*Demo$',content)   # .*会匹配尽可能多的字符
print(result)
print(result.group(1)) 
print(result.span())  

结果输出为:

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
7
(0, 40)

知识点

  • 贪婪匹配.*会匹配尽可能多的字符。
  • 这里.*(\d+).*中第一个.*匹配到llo 123456,(\d+)匹配到7,第二个.*匹配到 World_This is a Regex 。

1.5 非贪婪匹配.*?

python3环境下输入:

import re
content = "Hello 1234567 World_This is a Regex Demo"
result = re.match('^He.*?(\d+).*Demo$',content)   # .*?会匹配尽可能少的字符
print(result)
print(result.group(1)) 
print(result.span())  

结果输出为:

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567
(0, 40)

知识点

  • .*?会匹配尽可能少的字符

1.6 换行符

python3环境下输入:

import re
content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\d+).*Demo$',content)    #.*无法匹配换行符  
print(result)

结果输出为:

None

python3环境下输入:

import re
content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\d+).*Demo$',content,re.S)     #re.S 代替换行符 
print(result)
print(result.group(1))  
print(result.span()) 

结果输出为:

<re.Match object; span=(0, 40), match='Hello 1234567 World_This\nis a Regex Demo'>
1234567
(0, 40)

知识点

  • .*无法匹配换行符
  • re.S 代替换行符

1.7 转义(匹配特殊字符)?

python3环境下输入:

import re
content = 'price is $5.00'
result = re.match('price is $5.00',content)      #包含特殊字符不能直接全部输入
print(result)

结果输出为:

None

python3环境下输入:

import re
content = 'price is $5.00'
result = re.match('price is \$5\.00',content)       #给特殊字符加双斜杆即可
print(result)

结果输出为:

<re.Match object; span=(0, 14), match='price is $5.00'>

知识点

  • 包含特殊字符不能直接全部输入
  • 给特殊字符加双斜杆即可

总结
尽量使用泛匹配,使用括号得到匹配目标,尽量使用非贪婪模式,有换行符就用re.S

2.匹配函数 re.search

re.search 更推荐使用, 扫描整个字符串并返回第一个成功的匹配

python3环境下输入:

import re
content = "Extra stings Hello 1234567 World_This is a Regex Demo Extra stings"
result = re.match('Hello.*?(\d+).*?Demo',content)   # re.match必须是从头开始匹配
print(result)

结果输出为:

None

python3环境下输入:

iimport re
content = "Extra stings Hello 1234567 World_This is a Regex Demo Extra stings"
result = re.search('Hello.*?(\d+).*?Demo',content)   # re.search不是必须从头开始匹配
print(result)

结果输出为:

<re.Match object; span=(13, 53), match='Hello 1234567 World_This is a Regex Demo'>

知识点

  • re.match必须是从头开始匹配
  • re.search不是必须从头开始匹配

python3环境下输入:

import re
html = '''*<div id="songs-list">
<h2 class=title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class"list -group">
<li data -view="2">一路上有你</li>
<li data -view="7" >
<a href="/2.mp3" singer="任贤齐">沧海声笑</a>
</li>
<li data -view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<ll data-view="6"><a href="*/4.mp3" singer="beyond">光辉岁月</a></li>
<li data _view="5"><a href-=*/5.mp3" singer="陈慧琳">记事本</a></li>
<li data -view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</i>
</ul>
</div>'''
result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S)   #!!!re.S很重要
if result:
    print(result.group(1),result.group(2))   ##  返回第一个满足条件的结果
result = re.search('<li.*?singer="(.*?)">(.*?)</a>',html,re.S)   #删掉.*?active
if result:
    print(result.group(1),result.group(2))  

结果输出为:

齐秦 往事随风
任贤齐 沧海声笑

3.匹配函数 re.findall

re.findall 搜索字符串,以列表形式返回全部能匹配的字段

python3环境下输入:

import re
html = '''*<div id="songs-list">
<h2 class=title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class"list -group">
<li data -view="2">一路上有你</li>
<li data -view="7" >
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data -view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<ll data-view="6"><a href="*/4.mp3" singer="beyond">光辉岁月</a></li>
<li data _view="5"><a href-=*/5.mp3" singer="陈慧琳">记事本</a></li>
<li data -view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</i>
</ul>
</div>'''
# results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>',html,re.S) 
# print(results)
# print(type(results))
# for result in results:
#     print(result)
#     print(result[0],result[1])     # 匹配到的是从第二个开始的
    
#如果想要把第一个"一路上有你"和其他歌名匹配到 
# #方法一:
# results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>',html,re.S) 
# # \s*?  换行空白字符可能有可能没有   (<a.*?>)?  a标签可能有可能没有   (\w+)歌名字符串   (</a>)?  </a>可能有可能没有
# print(results)
# for result in results:
#     print(result[1]) 
    
#方法二:
html=re.sub("<a.*?>|</a>","",html)
# print(html)
results=re.findall('<li.*?>(.*?)</li>',html,re.S)
print(results)   #有的有换行符,有的没有
for result in results:
    print(result.strip())   #strip()把换行符去掉

结果输出为:

['一路上有你', '\n沧海一声笑\n', '\n往事随风\n', '记事本']
一路上有你
沧海一声笑
往事随风
记事本

4.匹配函数 re.sub

re.sub 替换字符串中每一个匹配的子串后返回替换后的字符串

python3环境下输入:

import re
content = "Extra stings Hello 1234567 World_This is a Regex Demo Extra stings"
result = re.sub('\d+','',content)   # 将数字部分变为空
print(result)

结果输出为:

Extra stings Hello  World_This is a Regex Demo Extra stings

python3环境下输入:

import re
content = "Extra stings Hello 1234567 World_This is a Regex Demo Extra stings"
result = re.sub('\d+','Replacement',content)   # 将数字部分变为替换字符串
print(result)

结果输出为:

Extra stings Hello Replacement World_This is a Regex Demo Extra stings

python3环境下输入:

import re
content = "Extra stings Hello 1234567 World_This is a Regex Demo Extra stings"
result = re.sub('(\d+)',r'\1 8910',content)   # 将数字部分继续添加,加括号,再r'\1 注意这里有空格,\1
print(result)

结果输出为:

Extra stings Hello 1234567 8910 World_This is a Regex Demo Extra stings

5.匹配函数 re.compile

re.compile 将正则字符串编译成正则表达式对象,以便于复用该匹配模式

python3环境下输入:

import re
content = '''Hello 1234567 World_This
is a Regex Demo
'''
pattern = re.compile('Hello.*Demo',re.S)     #re.S 代替换行符 
result = re.match(pattern,content)
print(result)
print(result.group())  
print(result.span()) 

结果输出为:

<re.Match object; span=(0, 40), match='Hello 1234567 World_This\nis a Regex Demo'>
Hello 1234567 World_This
is a Regex Demo
(0, 40)

6. 实战练习

练习一:提取网页发布时间
python3环境下输入:

import re
html="""<span class="info">
                选择字体:[<span class="set-font" data-font="lg">大</span>-<span class="set-font" data-font="md">中</span>-<span class="set-font" data-font="sm">小</span>]
              </span>
<span class="info">发布时间:2021-06-09 08:48:16</span>
<span class="info share-box" id="toShare">
"""
publishDate = re.findall('<span.*?class="info">发布时间:(.*?)</span>',html,re.S)
# publishDate = re.findall('<span.*?class="info.*?share-box".*?id="(.*?)">',html,re.S)
print(publishDate)

结果输出为:

['2021-06-09 08:48:16']

练习二:提取发件附件名称
python3环境下输入:

import re
html='''
<td align="center" style="padding:5px 10px;"><strong>发证附件:</strong></td>
<td style="padding:5px 10px;"><p><a href="/picture/lslzfl/picture/old/a78fb67a-e02f-4a58-9499-f0a847254660.jpg" style="font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; font-size: 16px; font-family: sans-serif; white-space: normal;" target="_blank">发证附件.pdf</a></p></td>
</tr>
</div>
'''
publishDate = re.findall('发证附件:.*?href="(.*?)"',html,re.S)
# publishDate = re.findall('<span.*?class="info.*?share-box".*?id="(.*?)">',html,re.S)
print(publishDate)

结果输出为:

['/picture/lslzfl/picture/old/a78fb67a-e02f-4a58-9499-f0a847254660.jpg']

练习二:提取土拍部分信息
python3环境下输入:

import re
html="""
<div class="land-name-title">

                    温岭市石桥头镇下宅吴村石桥头学工路北侧、振兴南路东侧地块                    <span class="tag-guipai">招标</span>
<span class="tag-deal tag-deal__wait">待成交</span>
</div>
"""
title = re.findall('<div.*?class="land-name-title">(.*?)<span',html,re.S)
aaa = re.findall('<span.*?class="tag-guipai">(.*?)</span>',html)
bbb = re.findall('<span.*?class="tag-deal.*?tag-deal__wait">(.*?)</span>',html)
print(title)
print(aaa)
print(bbb)

结果输出为:

['\n\n                    温岭市石桥头镇下宅吴村石桥头学工路北侧、振兴南路东侧地块                    ']
['招标']
['待成交']

猜你喜欢

转载自blog.csdn.net/weixin_47296493/article/details/129525470