众多语言都能进行爬虫,但基于python的爬虫显得更加简洁,方便。爬虫也成了python语言中必不可少的一部分。爬虫的解析方式也是多种多样。
上一篇给大家讲解的是爬虫的解析方式二:Beautifulsoup,今天给带给大家的是正则表达式。
正则表达式
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。就是 事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符”,这个“规则字符” 来表达对字符的一种过滤逻辑。
正则并不是python独有的,其他语言也都有正则。
python中的正则,封装了re模块
Python中常用的正则表达式处理函数
re.match函数
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
函数语法:
re.match(pattern, string, flags=0)
函数参数说明:
参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串。
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
匹配成功re.match方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法 描述
group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,
在这种情况下它将返回一个包含那些组所对应值的元组。
groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
import re print(re.match('www', 'www.baidu.com').span()) # 在起始位置匹配 print(re.match('com', 'www.baidu.com')) # 不在起始位置匹配
以上实例运行输出结果为:
(0, 3) None
import re content = "Cats are smarter than dogs" result = re.match( r'(.*) are (.*?) .*', content) print(result.group()) print(result.group(1)) print(result.group(2))
以上实例执行结果如下:
Cats are smarter than dogs Cats smarter result.group()获取匹配的结果 result.span()获去匹配字符串的长度范围
泛匹配
其实相对来说上面的方式并不是非常方便,其实可以将上述的正则规则进行更改
import re content = "Cats are smarter than dogs" result = re.match( r'Cats.*dogs$', content) print(result) print(result.group()) print(result.span())
匹配目标
如果为了匹配字符串中具体的目标,则需要通过()括起来,例子如下:
import re content = "Cats are 1234567 smarter than dogs" result = re.match( r'(.*)\sare\s(\d+)\s(.*?)\s.*', content) #\s匹配空格符 \d+匹配数字 print(result.group()) print(result.group(1)) print(result.group(2))
以下为执行结果:
Cats are smarter than dogs
Cats
1234567
贪婪匹配
先看下面代码:
import re content = "Cats are 1234567 smarter than dogs" result = re.match( r'Cats.*(\d+).*dogs', content) print(result.group()) print(result.group(1))
从结果中可以看出只匹配到了7,并没有匹配到1234567,出现这种情况的原因是前面的.* 给匹配掉了, .*在这里会尽可能的匹配多的内容,也就是我们所说的贪婪匹配,
如果我们想要匹配到1234567则需要将正则表达式改为:
result = re.match( r'Cats.*?(\d+).*dogs', content)
这样结果就可以匹配到1234567
匹配模式
很多时候匹配的内容是存在换行的问题的,这个时候的就需要用到匹配模式re.S来匹配换行的内容
import re content = """Cats are 1234567 smarter than dogs dogs are wangwangwang""" result = re.match( r'Cats.*(\d+).*wangwangwang', content,re.S) print(result.group()) print(result.group(1))
转义
当我们要匹配的内容中存在特殊字符的时候,就需要用到转移符号\,例子如下:
import re content= "price is $5.00" result = re.match('price is \$5\.00',content) print(result.group())
注意:
对上面的一个小结:
尽量使用泛匹配,使用括号得到匹配目标,尽量使用非贪婪模式,有换行符就用re.S
强调re.match是从字符串的起始位置匹配一个模式
re.search方法
re.search 扫描整个字符串并返回第一个成功的匹配。
函数语法:
re.search(pattern, string, flags=0)
函数参数说明:
参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串。
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
匹配成功re.search方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法 描述
group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,
在这种情况下它将返回一个包含那些组所对应值的元组。
groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
import re content = "extra things hello 123455 world_this is a Re Extra things" result = re.search("hello.*?(\d+).*?Re",content) print(result.group()) print(result.group(1)
其实这个时候我们就不需要在写^以及$,因为search是扫描整个字符串
注意:所以为了匹配方便,我们会更多的用search,不用match,match必须匹配头部,所以很多时候不是特别方
re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
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> <li 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> </li> </ul> </div>'''
import re result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S) print(result.group(1), result.group(2))
观察到
首先我们尝试提取class为active的
所以我们需要提取第三个
所以正则表达式可以以
另外由于代码有换行,所以这里第三个参数需要传入re.S
注意:在上面两次匹配中,search()方法的第三个参数我们都加了re.S,使得.*?可以匹配换行,所以含有换行的
re.findall
搜索整个字符串然后返回匹配正则表达式的所有内容
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> <li 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> </li> </ul> </div>'''
import re results = re.findall('<li.*?href="/(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S) for result in results: print(result) print(result[0], result[1], result[2])
运行结果:
('2.mp3', '任贤齐', '沧海一声笑')
2.mp3 任贤齐 沧海一声笑
('3.mp3', '齐秦', '往事随风')
3.mp3 齐秦 往事随风
('4.mp3', 'beyond', '光辉岁月')
4.mp3 beyond 光辉岁月
('5.mp3', '陈慧琳', '记事本')
5.mp3 陈慧琳 记事本
('6.mp3', '邓丽君', '但愿人长久')
6.mp3 邓丽君 但愿人长久
results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>',html,re.S) for result in results: #print(result) print(result[0], result[1], result[2])
运行结果:
一路上有你
\s*? 这种用法其实就是为了解决有的有换行,有的没有换行的问题
(
检索和替换
Python 的re模块提供了re.sub用于替换字符串中的匹配项。
语法:
re.sub(pattern, repl, string, count=0)
参数:
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
import re phone = "2004-959-559 # 这是一个电话号码" # 删除注释 num = re.sub(r'#.*$', "", phone) print ("电话号码 : ", num) # 移除非数字的内容 num = re.sub(r'\D', "", phone) print ("电话号码 : ", num)
在这里我们只需要在第一个参数传入\D来匹配所有的数字,然后第二个参数“”是替换成的字符串,要去掉的话就可以赋值为空,第三个参数phone就是原字符串。
re.compile
将正则表达式编译成正则表达式对象,方便复用该正则表达式
import re content= "hello world fan" pattern =re.compile("hello.*fan",re.S) result1 = re.match(pattern,content) result2 = re.search(pattern,content) result3 = re.sub(pattern, '', content) print(result1, result2, result3)
compile()还可以传入修饰符,例如re.S等修饰符,这样在search()、findall()等方法中就不需要额外传了。所以compile()方法可以说是给正则表达式做了一层封装,以便于我们更好地复用。
正则表达式修饰符 - 可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
正则表达式模式
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 \\t )匹配相应的特殊字符。
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
模式 描述
^ 匹配字符串的开头
$
. 任意字元。
[...] 中 #[^...] []中的字元:[^abc] 符合除了a,b,c之外的字元。
re* 時中使用
re 時使用
re?
re{ n,} n個前面表達式。
re{ n, m} 中使用 之後上使用中配備「「配備「」「」」與「」」(re)」(re)’ G 正規表示中上一個順序中所包含三種選擇標記:i, m, 或x 。只影響括號中的區域。
(?-imx) 時中使用中 x只影響括號中的區域。
(?: re) 括號中使用i, m, 或x 選購標誌
(?-imx: re) 作用中。
##(?= re ) 若所含正規表示式,以 ... 表示,在目前位置成功配對時成功, 但一旦所含表達式已經嘗試,匹配引擎根本沒有提高;中使用
(?! re) 與肯定界定符相反;當所含表達式不能在字串當前位置匹配時成功
(?> re)
\w 非字母中使用 依任意空格,等價於[\t\n\r\f].
\S 依任任非數位上配
#\A 中中結束,若是存在換排,且只符合至換行前的結束字串。 c
\z 中使用中完成的位置。
\b
匹配 "verb" 中的 'er'。
\B 'er\B' 能符合 "verb" 中的 'er',但不能符合 "never" 中的 'er'。
\n, \t, 等。 匹配一個製表符。等等
\1...\9
\10 時中使用否則指的是八進位碼的表達式。
#正規表示式實例
字元符合
實例 ##o 配對"python".
# 字符類別 實例配對"Python" 或"python"
rub[ye] 搭配"ruby" 或"rube"
[aeiou] 1 c 搭配任何數字中使用。類似[0123456789]
[a-z] 搭配任何小寫字母# 配任何大寫字母
[a-zA-Z0-9] 與任何字母與數字
[^aeiou] 除了所有關於aeiou字母以外的所有字元
[^0-9] #
特殊字元類別
實例 說明
. 外的任何單一字元。若要符合包括 '\n' 在內的任何字符,請使用象 '[.\n]' 的模式。
\d 時上建立數位字元。等價於 [0-9]。
\D 時搭配上使用非數位字元。等價於 [^0-9]。
\s 時中使用任何空格字元,包括空格、資料表符號、排符號等。等價於 [ \f\n\r\t\v]。
\S 等價於 [^ \f\n\r\t\v]。
\w 作用中與所有底線中所包含的任何單字。等價於'[A-Za-z0-9_]'。
\W 時上與任何非其中使用字元字元。等價於 '[^A-Za-z0-9_]'。
以上是爬蟲的解析方式三:正規表示式的詳細內容。更多資訊請關注PHP中文網其他相關文章!