美文网首页Python爬虫从入门到放弃
python爬虫从入门到放弃之七:正则表达式

python爬虫从入门到放弃之七:正则表达式

作者: 52d19f475fe5 | 来源:发表于2019-07-28 14:16 被阅读2次

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

正则、Xpath、BeautifulSoup对比
正则表达式的语法

正则的语法很多,这里列出常用的



re模块的常用方法
  • match()方法用于从字符串的第一个字符开始匹配,如果匹配成功,则返回Match对象,否则返回None

  • search()方法用于在整个字符串中搜索第一个匹配的值,如果匹配成功,则返回Match对象,否则返回None

  • findall()方法用于在整个字符串中搜索所有符合正则表达式的字符串,如果匹配成功,返回包含匹配结构的列表,否则返回空列表

  • sub()方法用于替换字符串

  • split()方法用于根据正则表达式分割字符串,并以列表的形式



范例代码一:

import re 
string = '小明:20岁,小红:19岁'
pattern = '\d{2}'

result = re.match(pattern,string)
print(result)

result = re.search(pattern,string)
print(result)
print(result.group())

result = re.findall(pattern,string)
print(result)

运行结果

None
<re.Match object; span=(3, 5), match='20'>
20
['20', '19']
>>> 

match()方法得到的结果是None,原因在于match()方法是从字符串第一个字符开始去匹配的,这里因string第一个字符不是数字,所以直接返回None,如果直接print(result.group())是会报错的。

group()方法是Match对象获取匹配的内容


范例代码二:

import re

content = '发布于2019/7/28,发布人:小明'
result =re.match('.*?(\d.*\d).*:(.*)',content)
print(result.group())
print(result.group(0))
print(result.group(1))
print(result.group(2))
print('')
result =re.findall('.*?(\d.*\d).*:(.*)',content)
print(result)
print(result[0])
print(result[0][0])
print(result[0][1])

运行结果:

发布于2019/7/28,发布人:小明
发布于2019/7/28,发布人:小明
2019/7/28
小明

[('2019/7/28', '小明')]
('2019/7/28', '小明')
2019/7/28
小明
>>> 

可以发现,group是针对()来说的,group(0)就是指的整个字符串,group(1)指的是第一个括号里的内容,group(2)指的第二个括号里的内容。

findall()方法匹配多个字符时,返回列表的元素为元组

.*?非贪婪模式,它匹配到'于'之后就停止了

把上面的代码修改一下,我们希望提取发布时间,即2019/7/28


范例代码三:

import re

content = '发布于2019/7/28,发布人:小明'

result =re.findall('.*?(\d.*\d)',content)
print(result)

result =re.findall('.*(\d.*\d)',content)
print(result)

result =re.findall('.*(\d.*?\d)',content)
print(result)

result =re.findall('.*?(\d.*?\d)',content)
print(result)

运行结果:

['2019/7/28']
['28']
['28']
['20', '19', '7/2']
>>> 

.*?是非贪婪模式,尽可能少量地去匹配

.*是贪婪模式,尽可能大量地去匹配

我们先看括号内的内容,前后都是\d,说明()内的匹配结果必须包含两个数字,并且一前一后,范围在2019/7/28之内

对于规则字符串.*?(\d.*\d).*?只要满足它的后面有两个数字它就不管了,所以它取到字就停止了,因此.*?匹配为发布于,这样第一个\d匹配为20192.*是贪婪匹配,它只要满足它后面有一个数字就继续取值,所以.*匹配为019/7/2,所以第二个\d就是8

对于规则字符串.*(\d.*\d),第一个.*实行贪婪匹配,它发现它直接取到发布于2019/7/,剩下28留给\d.*\d去匹配依然满足,所以它就这么干了

对于规则字符串.*(\d.*?\d),和上面一样

以上三条,由于整个规则字符串只能成功匹配一次,因此返回一个元素的列表

对于规则字符串.*?(\d.*?\d),第一个.*?取到字就不管了,剩下\d.*?\d去匹配2019/7/28,而.*?是非贪婪匹配,也叫懒惰匹配,当第一个\d匹配为20192时,它发现它不去匹配字符也行(其实是匹配为空值,即*=0),所以第二个\d匹配为0,就是\d.*?\d第一次匹配为20,剩下19/7/28还可以继续匹配;因为findall()方法是要获取所有匹配成功的结果,所以还得继续匹配,第二次匹配为19,剩下/7/28,只能从7开始匹配,第三次匹配为7/2,剩下8,无法继续匹配了


范例代码四:

import re

string = '香辣口水鸡        卤肉饭        蒜蓉烤生蚝'
result = re.sub('\s+',' ',string)
print(result)

运行结果:

香辣口水鸡 卤肉饭 蒜蓉烤生蚝
>>> 



范例代码五:

import re

url = 'https://zhidao.baidu.com/list?cid=110&fr=daohang'
pattern = r'[?|&]'
result = re.split(pattern,url)
print(result)

运行结果:

['https://zhidao.baidu.com/list', 'cid=110', 'fr=daohang']
>>> 



范例代码六:

import re

pattern = r'china_\w+'
string = 'CHINA_666 china_666'
reult  = re.match(pattern,string,re.I)
print(reult.group())

运行结果:

CHINA_666
>>> 

上面,匹配字符串是否以"china_"开头,不区分大小写

re.I是标志参数,表示执行不区分字母大小写的匹配

常用的标志如下:

re.I 表示执行不区分字母大小写的匹配

re.S 匹配所有字符,包括换行符

re.X 忽略规则字符串中未转义的空格和注释

re通用匹配公式

用这个通用匹配公式实现对html页面快速提取数据

reult = re.findall(r'~~(.*?)~~',string,re.S)

波浪线部分代表有标识型一串字符


实例展示:

目标网站:豆瓣图书 Top 250 https://book.douban.com/top250

提取数据:书名、评分、推荐语、链接

  • 分析url:


通过多次翻页发现:第i页对应的url = 'https://book.douban.com/top250?start='+str(i*25)

  • 分析网页:


每本书的信息在<tr class="item">标签下,用re通用匹配公式得出单个html页面的所有书books = re.findall(r'<tr class="item">(.*?)</tr>',html,re.S)

再用for语句遍历,for book in booksbook就是每本书所有信息,对book用re公式提取标签的内容,将返回包含一个元素的列表

为了防止某个书的信息不全,可以写个if判断语句

代码实现:

import requests
import re

# 如果匹配不成功,返回空字符串,成功则取值
def info(list_name):
    if list_name==[]:
        return ''
    else:
        return list_name[0]

# 用正则提取数据
def get_data(url,headers):
    html = requests.get(url,headers = headers).text
    books = re.findall(r'<tr class="item">(.*?)</tr>',html,re.S)
    for book in  books:
        title = re.findall(r'title="(.*?)"',book,re.S)
        num = re.findall(r'<span class="rating_nums">(.*?)</span>',book,re.S)
        introduce= re.findall(r'<span class="inq">(.*?)</span>',book,re.S)
        link = re.findall(r'class="nbg" href="(.*?)"',book,re.S)
        print(info(title),info(num),info(introduce),info(link))

if __name__ == "__main__":
    for i in range(10):
        url = 'https://book.douban.com/top250?start='+str(i*25)
        headers = {'User-Agent': 'Mozilla/5.0'}
        get_data(url,headers)



>>>阅读更多文章请点击以下链接:

python爬虫从入门到放弃之一:认识爬虫
python爬虫从入门到放弃之二:HTML基础
python爬虫从入门到放弃之三:爬虫的基本流程
python爬虫从入门到放弃之四:Requests库基础
python爬虫从入门到放弃之五:Requests库高级用法
python爬虫从入门到放弃之六:BeautifulSoup库
python爬虫从入门到放弃之七:正则表达式
python爬虫从入门到放弃之八:Xpath
python爬虫从入门到放弃之九:Json解析
python爬虫从入门到放弃之十:selenium库
python爬虫从入门到放弃之十一:定时发送邮件
python爬虫从入门到放弃之十二:多协程
python爬虫从入门到放弃之十三:Scrapy概念和流程
python爬虫从入门到放弃之十四:Scrapy入门使用

相关文章

网友评论

    本文标题:python爬虫从入门到放弃之七:正则表达式

    本文链接:https://www.haomeiwen.com/subject/fyyurctx.html