python爬虫入门——Day02(正则表达式)
正则表达式
Regular Expression, 正则表达式, ⼀种使⽤表达式的⽅式对字符串进⾏匹配的语法规则 我们抓取到的⽹⻚源代码本质上就是⼀个超⻓的字符串, 想从⾥⾯提取内容.⽤正则再合适不过了. 正则的优点: 速度快, 效率⾼, 准确性⾼ 正则的缺点: 新⼿上⼿难度有点⼉⾼. 不过只要掌握了正则编写的逻辑关系, 写出⼀个提取⻚⾯内容的正则其实并不复杂 正则的语法: 使⽤元字符进⾏排列组合⽤来匹配字符串 在线测试正则 表达式https://tool.oschina.net/regex/
元字符: 具有固定含义的特殊符号 常⽤元字符:
列名 | 列名 |
---|---|
. | 匹配除换⾏符以外的任意字符, 未来在python的re模块中是⼀个坑 |
\w | 匹配字⺟或数字或下划线 |
\s | 匹配任意的空⽩符 |
\d | 匹配数字 |
\n | 匹配⼀个换⾏符 |
\t | 匹配⼀个制表符 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结尾 |
\W | 匹配⾮字⺟或数字或下划线 |
\D | 匹配⾮数字 |
\S | 匹配⾮空⽩符 |
a|b | 匹配字符a或字符b |
() | 匹配括号内的表达式,也表示⼀个组 |
[...] | 匹配字符组中的字符 |
[^...] | 匹配除了字符组中字符的所有字符 |
\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个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
量词: 控制前⾯的元字符出现的次数
列名 | 列名 |
---|---|
* | 匹配0个或多个的表达式。 |
+ | 匹配1个或多个的表达式。 |
? | 匹配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 次由前面的正则表达式定义的片段,贪婪方式 |
贪婪匹配和惰性匹配
列名 | 列名 |
---|---|
.* | 贪婪匹配, 尽可能多的去匹配结果 |
.*? | 惰性匹配, 尽可能少的去匹配结果 -> 回溯 |
(?imx) | 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。 |
(?-imx) | 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。 |
(?: re) | 类似 (...), 但是不表示一个组 |
(?imx: re) | 在括号中使用i, m, 或 x 可选标志 |
(?-imx: re) | 在括号中不使用i, m, 或 x 可选标志 |
(?#...) | 在括号中不使用i, m, 或 x 可选标志 |
(?= re) | 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。 |
(?! re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功 |
(?> re) | 匹配的独立模式,省去回溯。 |
这两个要着重的说⼀下. 因为我们写爬⾍⽤的最多的就是这个惰性匹配. 先看案例
str: 玩⼉吃鸡游戏, 晚上⼀起上游戏, ⼲嘛呢? 打游戏啊
reg: 玩⼉.*?游戏
此时匹配的是: 玩⼉吃鸡游戏
reg: 玩⼉.*游戏
此时匹配的是: 玩⼉吃鸡游戏, 晚上⼀起上游戏, ⼲嘛呢? 打游
戏
str: <div>胡辣汤</div>
reg: <.*>
结果: <div>胡辣汤</div>
str: <div>胡辣汤</div>
reg: <.*?>
结果:
<div>
</div>
str: <div class="abc"><div>胡辣汤</div><div>饭团
</div></div>
reg: <div>.*?</div>
结果:
<div>胡辣汤</div>
<div>饭团</div>
所以我们能发现这样⼀个规律: .*? 表示尽可能少的匹配, .*表示尽可 能多的匹配, 暂时先记住这个规律. 后⾯写爬⾍会⽤到的哦
re模块
怎么在python程序中使⽤正则呢? 答案是re模块
findall
findall 查找所有. 返回list
lst = re.findall("m", "mai le fo len, mai ni
mei!")
print(lst) # ['m', 'm', 'm']
lst = re.findall(r"\d+", "5点之前. 你要给我5000
万")
print(lst) # ['5', '5000']
search
search 会进⾏匹配. 但是如果匹配到了第⼀个结果. 就会返回这个结果. 如果匹配不上search返回的则是None
ret = re.search(r'\d', '5点之前. 你要给我5000
万').group()
print(ret) # 5
match
match 只能从字符串的开头进⾏匹配
ret = re.match('a', 'abc').group()
print(ret) # a
finditer
finditer, 和findall差不多. 只不过这时返回的是迭代器(重点)
it = re.finditer("m", "mai le fo len, mai ni
mei!")
for el in it:
print(el.group()) # 依然需要分组
compile() 预加载
compile() 可以将⼀个⻓⻓的正则进⾏预加载. ⽅便后⾯的使⽤
obj = re.compile(r'\d{3}') # 将正则表达式编译成为
⼀个 正则表达式对象, 规则要匹配的是3个数字
ret = obj.search('abc123eeee') # 正则表达式对象调
⽤search, 参数为待匹配的字符串
print(ret.group()) # 结果: 123
正则中的内容如何单独提取? 单独获取到正则中的具体内容可以给分组起名字
s = """
<div class='⻄游记'><span id='10010'>中国联通
</span></div>
"""
obj = re.compile(r"<span id='(?P<id>\d+)'>(?P<name>\w+)</span>", re.S)
result = obj.search(s)
print(result.group()) # 结果: <span id='10010'>中国联通</span>
print(result.group("id")) # 结果: 10010 # 获取id组的内容
print(result.group("name")) # 结果: 中国联通 #获取name组的内容
这⾥可以看到我们可以通过使⽤分组. 来对正则匹配到的内容进⼀步的进⾏筛选.
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 沐呓耳总的碎碎念
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果