使用Beautiful-Soup

前面介绍了正则表达式的相关用法,但是一旦正则表达式写的有问题,得到的可能就不是我们想要的结果了,而且对于一个网页来说都有一定的特殊的结构和层级关系,而且很多节点都有id或class来做区分,所以我们就可以通过他们的结构和属性来提取。

解析工具beautiful Soup

在《python网络数据采集》一书中的第一章节介绍的表示BeautifulSoup。一下是引用书中的开篇语。
BeautifulSoup 库的名字来自刘易斯卡罗尔在《爱丽丝梦游仙境》里同名的诗歌。
BeautifulSoup尝试化平淡为神奇,他通过定位HTML标签来格式化和组织复杂的网络信息,用简单易用的Python对象,为我们展现去XML结构信息。

简介

简单来说,Beautiful Soup就是Python的一个HTML或XML的解析库,可以用来方便的从网页中提取数据。
如果使用lxml,初始化Beautiful Soup时,可以把第二个参数改为lxml即可。

from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>Hello</p>','lxml')
print(soup.p)
print(soup.p.string)

输出去结果为:

<p>Hello</p>
Hello

基本用法

from bs4 import BeautifulSoup
html = '''<html><head><title>The Dormous story </title></head>
<body>
<p class="title" name = "dromouse"><b>The Demone story</b></p>
<p class="story">Once upon a time there were three litter ststers and their names were
and they lived at the bottom of a well.</p>
<p class="story">...</p>
'''
soup = BeautifulSoup(html,'lxml')
print(soup.prettify())
print(soup.title.string)

首先声明变量html,这并不是一个完整的HTML字符串,因为有的结点并没有闭合,之后建立一个BeatutifulSoup对象的初始化,然后将这个对象赋值给soup变量。
接下来就可以调用soup的各个属性解析这串HTML代码。调用prettify()方法,这个方法可以把要解析的字符串以标准的缩进格式输出。对于不标准的HTML字符串BeautifulSoup会自动更正,这是在初始化BeautifulSoup时做到的而不是prettify()方法。
调用soup.title可以选出HTML中的title节点,在调用string属性就可以得到里面的文本了,所以我们可以通过简单几个属性完成文本提取。

选择元素

from bs4 import BeautifulSoup
html = '''<html><head><title>The Dormous story </title></head>
<body>
<p class="title" name = "dromouse"><b>The Demone story</b></p>
<p class="story">Once upon a time there were three litter ststers and their names were
and they lived at the bottom of a well.</p>
<p class="story">...</p>
'''
soup = BeautifulSoup(html,'lxml')
print(soup.title)
print(type(soup.title))
print(soup.title.string)
print(soup.head)
print(soup.p)

输出结果:

<title>The Dormous story </title>
<class 'bs4.element.Tag'>
The Dormous story 
<head><title>The Dormous story </title></head>
<p class="title" name="dromouse"><b>The Demone story</b></p>

如果有多个结点存在这里只会调用第一个结点的内容而会忽略别的结点。

提取信息

(1)可以利用name属性获取结点的名称。

print(soup.title.name)
#title

(2)获取属性
每一个结点可能有多个属性可以调用atters获取所有的属性。

print(soup.p.attrs)
print(soup.p.attrs["name"])

输出结果为:

{'class':['title'],'name':'dromouse'}
dromouse

attrs返回的是一个由属性和属性值构成的一个字典。然后通过属性名来获取属性值。
也可以在结点元素后面加中括号,传入属性名就可以获取属性值了。

print(soup.p['name'])
print(soup.p['class'])

(获取内容)
可以利用string属性获取属性节点元素包含的文本内容,比如要获取第一个p结点的文本。
print(soup.p.string)。

嵌套选择

print(soup.head.title)
print(type(soup.head.title))
print(doup.head.title.string)

方法选择器

前面讲过的选择的方法都是通过属性来选择的,这种方法十分的快,如果需要进行复杂的选择的话这里有find_all()和,find()方法。
find_all
find_all,顾名思义,就是查询所有符合条件的元素,给它传入一些属性或文本,就可以得到符合条件的元素,它的功能十分强大。
API:
find_all(name, attrs, recursive, text, **kwargs)
(1)name
传入name参数,其值为url,也就是说,我们想要查询所有ul节点,也就是说,我们想要查询所有的ul节点,返回结果是列表类型,

html =  '''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class ="list" id="list">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html,'lxml')
print(soup.find_all(name='ul'))
print(type(soup.find_all(name='ul')[0]))

输出结果为:

[<ul class="list" id="list">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>, <ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>]
<class 'bs4.element.Tag'>

这里我们调用了find_all()方法,传入name参数,其参数值为ul,我们想要查询所有ul节点,返回结果是列表类型,并且列表中的每一个元素都是bs4.element.Tag类型,因为都是Tag类型因此依然可以进行嵌套查询,

for ul in soup.find_all(name='ul'):
	print(ul.find_all(name=''li))

运行结果为:

[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
[<li class="element">Foo</li>, <li class="element">Bar</li>]

当然也是可以遍历每一个文本的:

for ul in soup.find_all(name='li'):
	print(ul.find_all(name='li'))
	for li in ul.find_all(name='li')
		print(li.string)

输出结果为:

[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
Foo
Bar
Jay
[<li class="element">Foo</li>, <li class="element">Bar</li>]
Foo
Bar

除了根据节点查询,我们也可以通过属性来查询,

html =  '''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class ="list" id="list-1" name='elements'>
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
</div>
</div>'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html,'lxml')
print(soup.find_all(attrs={'id':'list-1'}))
print(soup.find_all(attrs={'name':'elements'}))

输出结果为:

[<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
[<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]

这里查询的时候是通过attrs参数,参树的类型是字典类型。
(3)text
text参数可用来匹配关键字的文本,传入的形式可以是字符串,可以是正则表达式对象,实例如下:

import re
html = '''
<div class='panel'>
<div class='panel-body'>
<a>Hello,this is a link</a>
<a>Hello,this is a link too</a>
</div>
<div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html,'lxml')
print(soup.find_all(text=re.compile('link')))

输出结果为:

['Hello,this is a link', 'Hello,this is a link too']

返回结果是所有匹配的正则表达式的节点文本主成的列表。
find()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值