【爬虫教程】数据解析03

目录

3.1re(正则)

3.1.1符号

3.1.3函数

3.1.3.1匹配函数

3.1.3.2其他函数

3.1.2函数参数

3.1.3分组

3.2xpath

3.3beautifulSoup

3.3.1基础入门

3.3.2Soup的四个对象(解析方式一)

3.3.3子节点

3.3.4搜索文档树(解析方式二)

3.3.5CSS选择器(解析方式三)

3.4jsonpath库


3.1re(正则)

3.1.1符号

  • '.':1个任意字符,除换行符
  • '?':[0,1]任意字符
  • '+':[1:] 任意字符
  • '*':[0,:] 任意字符
  • \s:空字符;
  • \S:非空字符
  • \w:字母数字下划线
  • \W:非字母数字下划线
  • \d:任意数字
  • \D:任意非数字
  • ^:匹配字符串的开头(加上这个就和match一样)
  • $:匹配字符串的结尾
  • '[]':匹配方括号中的任意字符.[abc],[a-zA-Z]
  • '{n}'匹配大括号前面的字符n次,{n,}大于n次;{,n}小于n次;{n,m}n-m次之间
  • '*? +? ?? {m,n}?':这些都是懒惰模式
  • \b:边界字符
  • 注意:在写正则的时候要加上字符r,为的是不让其和转义字符冲突.]

3.1.3函数

3.1.3.1匹配函数

re.match()函数

从头进行匹配,一旦匹配成功一个就返回结果对象,我们可以通过group()函数进行提取,如果没有匹配到结果我们返回None.

  • 参数1:正则表达式
  • 参数2:目标文本
  • 参数3:可以忽略
import re
match_obj = re.match('abc', 'abc123', re.I)
print(match_obj.group())

fullmatch()函数

从头开始匹配,要求文本与字符串完全匹配,没有匹配到结果则返回None,匹配到结果可以使用group()函数对内容进行提取.

  • 参数1:正则表达式
  • 参数2:目标文本
  • 参数3:可以忽略
try:
    match_obj = re.fullmatch(r'abc\w+', 'abc123', re.I)
    print(match_obj.group())
except Exception as ex:
    print('没有匹配成功')

search()函数

扫描整个字符串,查找匹配整个正则格式的内容,找到就返回Match对象,通过group()对内容进行提取

  • 参数1:正则表达式
  • 参数2:目标文本
  • 参数3:可以忽略
match_obj = re.search('abc', 'xyzABCdef', re.I)  # re.I表示忽略大小写
print(match_obj)
print(match_obj.group())  # 匹配的内容
print(match_obj.span())   # 匹配内容的位置
print(match_obj.start())  # 从开始匹配

findall()函数

查找匹配到的所有内容,,返回值是一个列表,如果没有找到,返回的是一个空列表.

  • 参数1:正则表达式
  • 参数2:目标文本
  • 参数3:可以忽略
try:
    list1= re.findall('\d+','123abc456cdb34jfn456')
    print(list1)
except Exception as ex:
    print('没有匹配成功')

3.1.3.2其他函数

compile()函数

通过该函数包裹的内容会生成一个正则对象,我们可以直接通过该对象调用正则匹配相关函数

import re
pattern = re.compile('abc')  # 正则对象
match_obj = pattern.match('abcdef')
# 匹配对象调用group获取匹配的内容
print(match_obj.group())

group()函数

从对象内容中提取数据

sub()函数

通过该函数可以将字符串中的空白字符替换掉.

  • 参数1:正则
  • 参数2:将匹配到的字符串填充成该字符串
  • 参数3:要匹配的文本
  • 参数4:要匹配的最大个数

将文本数据替换成自己的想要的内容

import re
text=re.sub(r'\\n','',r'1q2\nw3\n45r6\nf7f\n#89#f0',5)
print(text)

split()函数

通过pattern字符集切割string,如果有多个字符要进行切割,可以放在[]中进行选择,如果想要保留分隔符,可以放置在括号中,如果不想保留分隔符,可以放置在括号中,使用这种格式"?:[]"

import re
result1=re.split('(\d+)','123sjfh2345kfj89d')  #  ['', '123', 'sjfh', '2345', 'kfj', '89', 'd']
result2=re.split('\d+','123sjfh2345kfj89d')  #  ['', 'sjfh', 'kfj', 'd']
print(result1,result2)

3.1.2函数参数

  • re.I:大小写忽略
  • re.M:多行匹配,对^和$有影响
  • re.S:使点匹配包括换行在内的所有字符

3.1.3分组

\number  引用number组内容

import re
s = '<div aaaaa>lalala</div><div hahahaha>lelelelele</div>'
m = re.match(r'<(.+?) .+?>.+?</\1>', s)
print(m.group())
print(m.group(1))

?P<name>pattern)  使用名: (?P=name)

s = '<div aaaaa>lalala</div><div hahahaha>lelelelele</div>'
m = re.match(r'<(?P<name>.+?) .+?>.+?</(?P=name)>', s)
print(m.group())
print(m.group(1))

这种起别名的方式一定要注意,不能将其他的字符放置在?P的前面,我们在使用?P的时候要将其用括号包裹起来.前者和后者是同一个东西,只不过用别名将其代替了而已

() 表示分组关系

s = '<div class="breadcrumb">布鲁斯</div>'
m = re.fullmatch(r'<(.+) class="breadcrumb">(.+)</\1>', s)  #
print(m)
print(m.group(2))

|  表示或者关系

s = 'hi linda'
m_obj = re.search('(hi|hello) (Jack|Tom|Lucy|Linda)', s, re.I)  #
print(m_obj)
print(m_obj.group())
print(m_obj.group(1))
print(m_obj.group(2))

使用圆括号将其包裹,然后字符串之间用|分开表示整个字符串之间是或者关系,[]表示从中选取一个字符进行匹配,但是使用()就表示匹配的是字符串.

3.2xpath

安装lxml库:

pip3.6 install lxml

文本内容

books = '''
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>  
    <author>Giada De Laurentiis</author>  
    <year>2005</year>  
    <price>30.00</price>
  </book>  
  <book category="children">
    <title lang="en">Harry Potter</title>  
    <author>J K. Rowling</author>  
    <year>2005</year>  
    <price>29.99</price>
  </book>  
  <book category="web">
    <title lang="en">XQuery Kick Start</title>  
    <author>James McGovern</author>  
    <author>Per Bothner</author>  
    <author>Kurt Cagle</author>  
    <author>James Linn</author>  
    <author>Vaidyanathan Nagarajan</author>  
    <year>2003</year>  
    <price>50</price>
  </book>
  <book category="web1" cover="paperback">
    <title lang="en">Learning XML</title>  
    <author>Erik T. Ray</author>  
    <year>2003</year>  
    <price>39.95</price>
  </book>
    <book category="web2" cover="paperback">
    <title lang="en">Learning XML</title>  
    <author>Erik T. Ray</author>  
    <year>2003</year>  
    <price>40</price>
  </book>
    <book category="web3" cover="paperback">
    <title lang="en">Learning XML</title>  
    <author>Erik T. Ray</author>  
    <year>2003</year>  
    <price>39.95</price>
  </book>
</bookstore>
'''
html=etree.HTML(books)  # 封装成html对象
etree.tostring(html,encoding='utf-8').decode('utf-8')  # 对对象进行编码
html.xpath('//book')  # 获取标签对象
html.xpath('//book/@category')  # 获取指定属性的值
html.xpath('//book')  # 获取标签对象
books[0].xpath('./year/text()')  # 当前标签下某个标签的文本内容
books[0].xpath('..//year/text()')  # 上一级标签下某个标签的文本内容
html.xpath('//book[position() <= 3]/title/text()')  # 限制标签范围
html.xpath('//book[last()]')  #匹配最后一个book对象
html.xpath('//book[first()]')  # 匹配第一个book对象
html.xpath('//book[@cover="paperback"]/title/text()')  # 指定属性的book对象的文本内容
html.xpath('//book[@cover="paperback"][@category="web2"]/title/text()')  # 指定一个对象的多个属性
html.xpath('//book[contains(@category,"web")][@cover="paperback"]/@category')  # book对象属性category的值模糊匹配web,并且属性cover匹配paperback
html.xpath('//book|//title')  # book对象或者title对象
html.xpath('//@*')  # 匹配所有函数属性的属性值
html.xpath('//book[price mod 2 = 0]/title/text()')  # book标签下属性price的文本值为偶数的tiitle标签的文本值

3.3beautifulSoup

3.3.1基础入门

安装:pip3.6 install bs4

效率低于xpath和正则,但是比前两个都要简单许多,Python标准中的html解析器,支持lxml的lxml解析器.BeautifulSoup将html转换成一个树形结构,每个结点都是一个Python对象,所有对象可以归纳为4类。Tag对象、文本内容对象、Comment注释对象、文档内容对象。

soup = BeautifulSoup(data,'lxml')

  • 参数1:要进行解析的数据
  • 参数2:解析器lxml

3.3.2Soup的四个对象(解析方式一)

文档对象

soup = BeautifulSoup(data,'lxml')
print(soup)
print(type(soup))

<html>
    ...
</html>
<class 'bs4.BeautifulSoup'>

标签对象

t = soup.title
print(t)
print(type(t))

# 结果
<title>soup测试</title>
<class 'bs4.element.Tag'>

文本对象

s = soup.title.string
print(s)
print(type(s))

# 结果
soup测试
<class 'bs4.element.NavigableString'>

注释对象

# 原文
<li class="hello" id="world"><a id="world" href="http://www.baidu.com" title="出塞"><!--秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山--></a></li>

程序
s = soup.li.string
print(s)
print(type(s))

结果
秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山
<class 'bs4.element.Comment'>

3.3.3子节点

直接子节点

cs = soup.body.div.ul.children
print(cs)  # 可迭代对象
for item in cs:
    print(item)  # ul中的html内容

所有子孙结点

d = soup.body.div.ul.descendants # 一个可迭代对象
for item in d:
    print(item)

异同点:

  • children只是获取ul下的html内容,但是descendants会将当前对象下每一层分开。举个例子ul*2>li*3>a*2,只获取第一个ul下的内容,children获取的是li*3>a*2这部分内容,但是descendants会获取li*3>a*2和a*2这些内容.

3.3.4搜索文档树(解析方式二)

获取单个元素:

  • soup.find(name='标签',id='id值')
  • soup.find(name='标签',attrs={'class':'hello','id':'world'})

获取元素列表:

  • soup.find_all(name='标签',class_='hello')将其放在列表中

实际举例:

print(soup.find(name = 'li',id = 'wo'))
print(soup.find(name = 'li',attrs={'class':'hello','id':'world'}))
lis = soup.find_all('li',class_ = 'hello')
print(lis)

3.3.5CSS选择器(解析方式三)

和find_all()有相同的功能,写css的时候标签名不加任何修饰,类名外直接加点,id名前直接加#,在这里我们可以用类似的方法筛选元素,用到的方法有soup.select()返回的是list

标签查找和属性查找

  • 空格表示下一个元素
print(len(soup.select('li')))  # 通过标签查找
print(len(soup.select('.hello')))  # 通过类名查找
print(len(soup.select('#h2')))  # 通过id进行查找
print(soup.select('div[class="cao"][id="h2"] > ul > li')[0])  # 不支持下标,但是我们可以将下标写在外层

组合查找

ret = soup.select('li#wo')  # id为wo的li标签的html包括li标签
ret = soup.select('lists.hello a')  # 类名为hello的lists标签下的a标签

print(soup.select('li#world'))  # 包括li标签的html内容
print(soup.select('li #world'))  # 不包括li标签,为li标签下的html内容

soup.select('div>ol>pl,zl')  # 获取div下的ol下的pl和div下的ol下的zl,这里的pl和zl是同一级的

获取内容

tag = soup.find_all(name='title')[1]  # 通过find_all获取到的是一个列表
print(tag)  # 获取标签的html
print(tag.name)  # 获取某个标签的name值
print(tag.attrs)  # 获取标签的所有属性和属性值,并且是存放在字典中的
print(tag.attrs['href'])  # 获取标签对象具体属性的值
print(tag.string)  # 获取标签的内容
print(tag['href'])  # 直接获取标签的某个属性
print(tag.get_text())  # 获取标签的内容

get_text()和string()的区别

tag = soup.find_all(name='title')[1]
tag.get_text()  递归获取该标签下的所有文本内容
tag.string()  # 如果该标签的内容是文本内容则获取,如果是html内容,则返回None

3.4jsonpath库

简单介绍

  • 上面提到的都是处理html或者xml格式的数据的,如果遇到json格式的数据,就需要我们使用jsonpath进行解析,尽管我们使用序列化和反序列化也可以解决这种问题,但是过于麻烦,因为我们可以使用jsonpath更加快捷方便。

jsonpath和xpath的对比

实际应用

注意点:

  • book[?(@.isbn)]该属性存不存在
  • book[(@.length -1)]该对象的个数
  • book[?(@.price>12)]该对象的属性满不满足某个条件
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值