概念:Beautiful Soup 是什么?
- Beautiful Soup是一个可以从HTML或XML文件中提取数据的python库,它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。
- 目前Beautiful Soup3已经停止开发,推荐使用Beautiful Soup4
解析器
- Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, “html.parser”) | Python的内置标准库 执行速度适中 文档容错能力强 | Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
lxml HTML 解析器 | BeautifulSoup(markup, “lxml”) | 速度快 文档容错能力强 | 需要安装C语言库 |
lxml XML 解析器 | BeautifulSoup(markup, [“lxml”, “xml”])BeautifulSoup(markup, “xml”) | 速度快 唯一支持XML的解析器 | 需要安装C语言库 |
html5lib | BeautifulSoup(markup, “html5lib”) | 最好的容错性 以浏览器的方式解析文档 生成HTML5格式的文档 | 速度慢 不依赖外部扩展 |
对象的种类
Beautiful Soup将复杂的HTML文档转换成一个复杂的树形结构,每个节点都是python对象,所有对象可以归纳为4种:tag , NavigableString , Beautfulsoup, Coment
tag : 简单的讲就是HTML中的一个个标签
NavigableString :tag中的字符串
- BeautifulSoup :是一个文档的全部内容,大部分的时候,可以把他当做tag对象,是一个特殊的tag。因为BeautifulSoup对象并不是真正的HTML或XML的tag对象所有没有name和attribute属性,但有时查看它的.name属性是很方便的,所有BeautifulSoup对象包含了一个值为“[ducument]” 的特殊属性.name
- Comment : 是一个特殊类型的 NavigableString 对象,其实输出的内容仍然不包括注释符号
遍历文档树
(1)获取子节点
.contents 列表形式
.children 返回的是一个生成器,需要遍历查看
(2)获取所有子孙节点
.descendants 对所有tag的子孙节点进行递归循环,和children类似
(3) 节点内容
.string
如果一个标签里面没有标签了,那么.string 就会返回标签里面的内容。
如果标签里面只有唯一的一个标签了,那么.string 也会返回最里面的内容。
如果tag包含了多个子节点,tag就无法确定,string方法应该调
用哪个子节点的内容,string的输出结果是None
(4)多个内容
.strings 获取多个内容,不过需要遍历
find,find_all, select方法的使用
对于我们写爬虫基本上用的只有查找,大部分我们用的时候也就是这几个方法:find,find_all, select
find_all()讲解
find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件
以下是find_all()方法以及参数的用法
find_all(self, name=None, attrs={}, recursive=True, text=None,
limit=None, **kwargs)
name :
可以查找所有名字为name的tag,字符串对象会被自动忽略掉。内容可以是(字符串,正则,列表,Ture)Ture可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点,还可以传一个方法: 如果没有一个合适的过滤器,那么还可以定义一个方法,方法只接受一个元素参数,如果 这个方法返回True表示匹配成功,否者False
attrs :
规定tag中的属性,传入的是一个字典recursive :
默认是True 查找当前tag下的所有子孙节点。如果设置False那么只查找tag的直接子节点text :
查找节点中的内容字符串,与name参数的可选值一样。这个可以用定向查找某一个节点,获取节点的属性limit :
限制符合搜索条件的个数,比如符合条件的有5个,但是我们设置2个那么就只返回符合条件的前两个。和sql中的limit类似。kwarys :
如果一个指定名字的参数不是find_all()函数内置的参数,搜索时会把该参数当做指定名字tag的属性来搜索形式可以是: id =‘link’或 id =re.compile()。但是有些特殊的tag属性是不可以使用的。比如h5中data-*。 所以一般情况下都会在attrs中规定查找tag的属性。
看十遍不如动手做一遍,废话不多说直接实例着手。
实例
我把网页源代码放在了一个文件当中了
import sys
import codecs
from bs4 import BeautifulSoup
reload(sys)
sys.setdefaultencoding('utf-8')
data = codecs.open('2.html','r',encoding= 'utf-8').read()
#创建beautifulSoup 对象
soup = BeautifulSoup(data, 'lxml')
#获取每部小说链接
li = soup.find('div',class_='listBox').find('ul').find_all('li')
for i in li:
url = i.find('a',recursive=False).get('href')
print url
输出:
/36171.html
/36169.html
/36161.html
/36151.html
/36148.html
limit值的设定
#获取下面页数链接
dia = soup.find('div',class_='tspage').find_all('a',limit=1)
print dia
print type(dia)
for i in dia:
print i.get_text() #获取节点内容
print i.get('href') #获取节点某一属性
输出:
[<ahref="/soft/sort01/index_2.html">\u4e0b\u4e00\u9875</a>]
<class 'bs4.element.ResultSet'>
下一页
/soft/sort01/index_2.html
text的使用
一般知道节点内容,用来获取节点属性
# 知道节点内容,获取节点属性
di = soup.find('div',class_='wrap header')\
.find('a',text=u'首页').get('class')
print di
输出:
['nav-cur']
recursive值的设定
# div -> select ->option
option = soup.find('div',class_='tspage').find_all('option',limit=2)
for i in option:
print i.text
option = soup.find('div',class_='tspage').find_all('option',limit=2,recursive=False)
print option
if option:
for i in option:
print i.text
else:
print u'没有找到'
输出:
第 1 页
第 2 页
[]
没有找到
find() 用法和find_all()一样。
find(self, name=None, attrs={}, recursive=True, text=None,
**kwargs)
select()方法
css选择器—-soup.select() ,返回类型是list
select(self, selector, _candidate_generator=None, limit=None)
查找方法:
(1)通过标签名查找 tag标签
(2)通过类名查找 .类名
(3)通过id名查找 #id
(4)组合查找(标签,类名,id组合查找,直接子标签查找)
(5)属性查找
(6)通过语言设置来查找
soup.select('a[href]'
multilingual_soup.select('p[lang|=en]')
# [<p lang="en">Hello</p>,
# <p lang="en-us">Howdy,y'all</p>,
# <p lang="en-gb">Pip-pip, old fruit</p>]
我们在写css样式时,标签名不加任何修饰,类名前加点,id前加#,在这里我们可以利用类似的方法来筛选,通过tag标签逐层查找。
ul = soup.select(".listBox > ul > li > a")
for u in ul:
print u.text
输出:
《我是大玩家》全集
《仙武至尊》全集
《从主播到主神》全集
《都市之重返人间》全集
总结
发现我们在使用Beautiful Soup时主要使用的也就是find,find_all(),select这三个方法。
写一下我用Beautiful Soup查找时的思路
(1)用find定位到要查找的节点的父节点位置。
(2)如果这个父节点下的所有子节点都是我们想要的,那么就用find_all查找,如果只有一个使我们想要的就用find查找
(3)查找到某个节点后,获得内容用.text或string或get_text(),获取节点属性用.get()或者"节点名['属性名']"
**参考文档
Beautiful Soup 4.2.0 文档:
https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id47