爬虫基础:正则表达式

什么是正则表达式

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、以及这些特定字符的组合,组成一个“规则字符串”,这个规则字符串用来表达对字符串的一种过滤逻辑

Python用re模块实现

在线正则表达式工具

其中有许多常用的正则表达式,非常好用。

一般的网页可以用beautifulsoup等解析库来提取,不过有的网页卸载js的变量中,只能使用正则表达式来提取。正则表达式可以用来筛选和清洗。非常有用。

python中的正则表达式讲解

  • 常见匹配模式
模式描述
w 匹配字母数字及下划线
W 匹配非字母数字下划线
s 匹配任意空白字符、等价于[ f]
S 匹配任意非空字符
d 匹配任意数字,等价于[0-9]
D 匹配任意非数字
A 匹配字符串的开始
 匹配字符串结束,如果存在换行,只匹配到换行前的结束字符串
z 匹配字符串结束
G 匹配最后匹配完成的位置
匹配一个换行符
匹配一个制表符
^ 匹配字符串的开头
$ 匹配字符串的结尾
. 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符
[...] 用来表示一组字符,单独列出:[osi]匹配‘o’,'s','j'
[^...] 匹配除括号中内容之外的字符
* 匹配0个过多个表达式
+ 匹配1个或多个表达式
匹配0个或者1个表达式
{n} 精确匹配n个前面的表达式
{n,m} 匹配n到m此有前面的正则表达式定义的片段,贪婪方式
a|b 匹配a或b
() 匹配括号内的表达式,也表示一个组
  • re.match

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

re.match(pattern,string,flags=0)

sample

1.常规的匹配

import re
content = 'Hello 3232 4324 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hellosd{4}sd{4}sw{10}.*mo$',content)
print(result)
print(result.group())#匹配结果
print(result.span())#匹配结果在content中的范围

2.泛匹配--用.* 表示任意字符

import re
content = 'Hello 3232 4324 World_This is a Regex Demo'
result = re.match('^Hello.*mo$',content)
print(result)
print(result.group())
print(result.span())

3.匹配目标

一般我们把匹配目标用小括号括起来,然后指定左右端点,才能找到。

import re
content = 'Hello 3232 4324 World_This is a Regex Demo'
result = re.match('^Hellos(d{4})s(d+)s.*mo$',content)
print(result)
print(result.group(1))#第一个小括号括起来匹配的内容
print(result.group(2))#第二个小括号括起来的内容
print(result.span())

4.贪婪匹配

import re
content = 'Hello 3232 4324 World_This is a Regex Demo'
result = re.match('^He.*(d+).*mo$',content)
print(result)
print(result.group(1))
print(result.span())

*结果是4,因为.*表示任意字符,默认贪婪模式会匹配尽量多的任意字符,而d+至少要匹配一个数字,所以就一直匹配到最后一个数字之前。

5.非贪婪模式

import re
content = 'Hello 3232 4324 World_This is a Regex Demo'
result = re.match('^He.*?(d+).*mo$',content)
print(result)
print(result.group(1))
print(result.span())

.*?是非贪婪模式,匹配尽可能少字符。

6.匹配模式

import re
content = "Hello 3232 4324 World_This 
is a Regex Demo
"
result = re.match('^He.*?(d+).*mo$',content)
print(result)

*结果为none,原因是.不能匹配换行符,修改之后可以匹配

import re
content = "Hello 3232 4324 World_This 
is a Regex Demo
"
result = re.match('^He.*?(d+).*mo$',content,re.S)
print(result)

添加re.S后即可

7.转义

正则表达式中的许多特殊字符如果不做转义就无法匹配,会被认为是关键字使用,比如*.[]等等。以下就是不转义的例子

import re
content = 'price $50.09'
result = re.match('price $50.09',content)
print(result)

结果返回none,没匹配到。

转义之后才能匹配

import re
content = 'price $50.09'
result = re.match('price $50.09',content)
print(result)

最常见用法总结,尽量使用泛匹配模式,使用括号得到匹配目标,尽量使用非贪婪模式,使用re.S,因为HTML中有大量的换行符这样.就能匹配任意字符了。

  • re.search

re.match从字符串的开头匹配,比如pattern无法匹配content的第一个字符,那么直接返回none。而re.search会搜索整个字符串,只要搜索到符合pattern的内容就返回第一个成功的匹配。以下是sample。

import re
content = "jlljjljh Hello 1234 World_This is a Regex Demo,Don't forget!$"
result = re.match('Hello.*?(d+).*?',content)
print(result)#用match的话,result返回none
result = re.search('Hello.*?(d+).*?',content)
print(result)#可以匹配
print(result.group(1))#返回1234

总结,尽量用re.search方法,尽量使用re.S,用非贪婪模式

练习

import re
html = '<div class="songList songList960 clearfix"><ol id="f1"><li><input type="checkbox" value="11417@" name="Url" class="check"> <span class="songNum topRed">01.</span> <a target="_1" href="/play/11417.htm" class="songName cBlue">大海</a></li><li><input type="checkbox" value="64541@" name="Url" class="check"> <span class="songNum topRed">02.</span> <a target="_1" href="/play/64541.htm" class="songName">天路</a></li><li><input type="checkbox" value="65937@" name="Url" class="check"> <span class="songNum topRed">03.</span> <a target="_1" href="/play/65937.htm" class="songName">再回首</a></li><li><input type="checkbox" value="59930@" name="Url" class="check"> <span class="songNum">04.</span> <a target="_1" href="/play/59930.htm" class="songName cBlue">突然的自我</a></li><li><input type="checkbox" value="1462@" name="Url" class="check"> <span class="songNum">05.</span> <a target="_1" href="/play/1462.htm" class="songName">甘心情愿</a></li></ol></div>'
result = re.search('songName.*?>(.*?)</a>.*',html,re.S)
print(result)
print(result.group(1))

匹配结果:大海

  • re.findall--搜索字符串,以列表形式返回全部能匹配的子串
import re
html = '<div class="songList songList960 clearfix"><ol id="f1"><li><input type="checkbox" value="11417@" name="Url" class="check"> <span class="songNum topRed">01.</span> <a target="_1" href="/play/11417.htm" class="songName cBlue">大海</a></li><li><input type="checkbox" value="64541@" name="Url" class="check"> <span class="songNum topRed">02.</span> <a target="_1" href="/play/64541.htm" class="songName">天路</a></li><li><input type="checkbox" value="65937@" name="Url" class="check"> <span class="songNum topRed">03.</span> <a target="_1" href="/play/65937.htm" class="songName">再回首</a></li><li><input type="checkbox" value="59930@" name="Url" class="check"> <span class="songNum">04.</span> <a target="_1" href="/play/59930.htm" class="songName cBlue">突然的自我</a></li><li><input type="checkbox" value="1462@" name="Url" class="check"> <span class="songNum">05.</span> <a target="_1" href="/play/1462.htm" class="songName">甘心情愿</a></li></ol></div>'
result = re.findall('songName.*?>(.*?)</a>.*?',html)
print(result)

返回值:['大海', '天路', '再回首', '突然的自我', '甘心情愿'] *

  •  re.sub---替换字符串中每一个匹配的子串后返回替换后的字符串。
import re
content = 'Hello 3232 4324 World_This is a Regex Demo'
content = re.sub('d+','',content)#把数字替换为空
print(content)
import re
content = 'Hello 3232 4324 World_This is a Regex Demo'
content = re.sub('d+','Replacement',content)#数字部分都替换成‘replacement’
print(content)

如果替换的结果包含想替换的内容怎么办,比如像把这2段数字前面加上No.,但数字要保留,怎么办?

import re
content = 'Hello 3232 4324 World_This is a Regex Demo'
content = re.sub('(d+)',r'No.1',content)#用r''中间的是原生字符串不用转义了。先把patten小括号括起来,替换内容加
.这个n表示第几个小括号的内容替换成这样。
print(content)

结果:Hello No.3232 No.4324 World_This is a Regex Demo

  • re.compile---将正则字符串编译成正则表达式对象

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

import re
content = 'Hello 3232 4324 World_This is a Regex Demo'
result = re.match('^He.*?(d+).*mo$',content,re.S)#用正则字符串匹配
myPatten = re.compile('^He.*?(d+).*mo$',re.S)#编译正则表达式对象。
result = re.match(mypatten,content)#2种方法一样
print(result)
  • 例子

爬取豆瓣读书

读取 https://book.douban.com 新书速递中的书名、作者、出版社

import requests
import re
content = requests.get('https://book.douban.com/').text
#print(content)
pattern = re.compile('<li.*?cover.*?href="(.*?)".*?title="(.*?)".*?more-meta.*?author">(.*?)</span>.*?year">(.*?)</span>.*?</li>',re.S)
#print(pattern)
results = re.findall(pattern,content)
print(results)
原文地址:https://www.cnblogs.com/x00479/p/14249703.html