正则表达式 Regular Expression, 正则表达式, ⼀种使⽤表达式的⽅式对字符串进⾏匹配的语法规则。
我们抓取到的⽹⻚源代码本质上就是⼀个超⻓的字符串, 想从⾥⾯提取内容。⽤正则再合适不过了。
正则的优点:速度快, 效率⾼, 准确性⾼ 正则的缺点:新⼿上⼿难度有点⼉⾼。
不过只要掌握了正则编写的逻辑关系, 写出⼀个提取⻚⾯内容的正则其实并不复杂
正则的语法:使⽤元字符进⾏排列组合⽤来匹配字符串 在线测试正则表达式 https://tool.oschina.net/regex/
元字符:具有固定含义的特殊符号 常⽤元字符:
. 匹配除换⾏符以外的任意字符
\w 匹配字⺟或数字或下划线
\s 匹配任意的空⽩符 \d 匹配数字
\n 匹配⼀个换⾏符
\t 匹配⼀个制表符
^ 匹配字符串的开始 $ 匹配字符串的结尾
\W 匹配⾮字⺟或数字或下划线
\D 匹配⾮数字
\S 匹配⾮空⽩符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示⼀个组
[…] 匹配字符组中的字符
[^…] 匹配除了字符组中字符的所有字符
量词: 控制前⾯的元字符出现的次数
* 重复零次或更多次
+ 重复⼀次或更多次
? 重复零次或⼀次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
贪婪匹配和惰性匹配
.* 贪婪匹配 .*? 惰性匹配
这两个要着重的说⼀下,因为我们写爬⾍⽤的最多的就是这个惰性匹配。
先看案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 str : 玩⼉吃鸡游戏, 晚上⼀起上游戏, ⼲嘛呢? 打游戏啊reg: 玩⼉.*?游戏 此时匹配的是: 玩⼉吃鸡游戏 reg: 玩⼉.*游戏 此时匹配的是: 玩⼉吃鸡游戏, 晚上⼀起上游戏, ⼲嘛呢? 打游戏 str : <div>胡辣汤</div>reg: <.*> 结果: <div>胡辣汤</div> str : <div>胡辣汤</div>reg: <.*?> 结果: <div> </div> str : <div>胡辣汤</div><span>饭团</span>reg: <div>.*?</div> 结果: <div>胡辣汤</div>
那么接下来的问题是, 正则我会写了, 怎么在python程序中使⽤正则呢?答案是re模块
re模块中我们只需要记住这么⼏个功能就⾜够我们使⽤了。
1. findall 查找所有,返回list 1 2 3 4 5 import relst = re.findall("m" ," mai le for len,mai ni mei!" ) print (lst) lst = re.findall(r"\d+" ,"5点之前. 你要给我5000万" ) print (lst)
2. search 会进⾏匹配, 但是如果匹配到了第⼀个结果,就会返回这个结果。如果匹配不上search返回的则是None 1 2 ret = re.search(r"\d" ,"5点之前. 你要给我5000万" ).group() print (ret)
3. match 只能从字符串的开头进⾏匹配 1 2 ret = re.match ("a" ,"abc" ).group() print (ret)
4. finditer, 和findall差不多. 只不过这时返回的是迭代器(重点) 1 2 3 it = re.finditer("m" ," mai le for len,mai ni mei!" ) for el in it: print (el.group())
5. compile() 可以将⼀个⻓⻓的正则进⾏预加载. ⽅便后⾯的使⽤ 1 2 3 4 5 obj = re.compile (r'\d{3}' ) ret = obj.search('abc123eeee' ) print (ret.group())
6. 正则中的内容如何单独提取?这⾥可以看到我们可以通过使⽤分组。来对正则匹配到的内容进⼀步的进⾏筛选。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 s = """ <div class='⻄游记'><span id='10010'>中国联通</span></div> """ obj = re.compile (r"<span id='(?P<id>\d+)'>(?P<name>\w+)</span>" ,re.S) obj = re.compile (r"<span id='(?P<id>\d+)'>(?P<name>\w+)</span>" ,re.S) result = obj.search(s) print (result.group())print (result.group("id" ))print (result.group("name" ))
7.正式练习 下面一个案例,是练习用正则表达式提取豆瓣电影top250的数据并保存,一起来学一下吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import requestsimport reimport csvurl = "https://movie.douban.com/top250" headers = { "user-agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36" } resp = requests.get(url, headers=headers) page_content = resp.text obj = re.compile (r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)' r'</span>.*?<p class="">.*?<br>(?P<year>.*?) .*?<span ' r'class="rating_num" property="v:average">(?P<score>.*?)</span>.*?' r'<span>(?P<num>.*?)人评价</span>' , re.S) result = obj.finditer(page_content) f = open ("data.csv" , mode="w" ) csvwriter = csv.writer(f) for it in result: dic = it.groupdict() dic['year' ] = dic['year' ].strip() csvwriter.writerow(dic.values()) f.close() print ("over!" )