python爬虫:BeautifulSoup 库 的基本函数用法及框架
安装:
Win平台: “以管理员身份运行”cmd 执行
pip install beautifulsoup4
Beautiful Soup 库的理解:
Beautiful Soup 库解析器:
Beautiful Soup 库的基本元素:
基于bs4库的HTML内容遍历方法:
下行遍历:
soup = BeautifulSoup(url,"html.parser")
#遍历儿子节点
for child in soup.body.children:
print(child)
#遍历子孙节点
for child in soup.body.descendants:
print(child)
标签树的上行遍历:
标签树的平行遍历:
#遍历后续节点
for sibling in soup.a.next_sibling:
print(sibling)
#遍历前续节点
for sibling in soup.a.previous_sibling:
print(sibling)
小结:
函数调用:
soup = BeautifulSoup(open("index.html"))
# 打开当前目录下 index.html 文件
soup.prettify()
函数的作用是打印整个 html 文件的 dom 树
解析 BeautifulSoup 对象
想从 html 中获取到自己所想要的内容,我归纳出三种办法:
1)利用 Tag 对象
从上文得知,BeautifulSoup 将复杂 HTML 文档转换成一个复杂的树形结构,每个节点都是Python对象。跟安卓中的Gson
库有异曲同工之妙。节点对象可以分为 4 种:Tag
, NavigableString
, BeautifulSoup
, Comment
。
Tag 对象可以看成 HTML 中的标签。这样说,你大概明白具体是怎么回事。我们再通过例子来更加深入了解 Tag 对象。以下代码是以 prettify() 打印的结果为前提。
- 例子1
获取head
标签内容
print(soup.head)
# 输出结果如下:
<head><title>The Dormouse's story</title></head>
- 例子2
获取title
标签内容
print(soup.title)
# 输出结果如下:
<title>The Dormouse's story</title>
- 例子3
获取p
标签内容
print(soup.p)
# 输出结果如下:
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
如果 Tag 对象要获取的标签有多个的话,它只会返回所以内容中第一个符合要求的标签。
对象一般含有属性,Tag 对象也不例外。它具有两个非常重要的属性, <font color='red'>name</font> 和 <font color='red'>attrs</font>。
name
name 属性是 Tag 对象的标签名。不过也有特殊的,soup 对象的 name 是 [document]
print(soup.name)
print(soup.head.name)
# 输出结果如下:
[document]
head
attrs
attrs 属性是 Tag 对象所包含的属性值,它是一个字典类型。
print(soup.p.attrs)
# 输出结果如下:
{'class': ['title'], 'name': 'dromouse'}
其他三个属性也顺带介绍下:
- NavigableString
说白了就是:Tag 对象里面的内容
print(soup.title.string)
# 输出结果如下:
The Dormouse's story
- BeautifulSoup
BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象。它是一个特殊的 Tag。
print(type(soup.name))
print(soup.name)
print(soup.attrs)
# 输出结果如下:
<type 'unicode'>
[document]
{} 空字典
- Comment
Comment 对象是一个特殊类型的 NavigableString 对象。如果 HTML 页面中含有注释及特殊字符串的内容。而那些内容不是我们想要的,所以我们在使用前最好做下类型判断。例如:
if type(soup.a.string) == bs4.element.Comment:
... # 执行其他操作,例如打印内容
2)利用过滤器
过滤器其实是一个find_all()
函数, 它会将所有符合条件的内容以列表形式返回。它的构造方法如下:
find_all(name, attrs, recursive, text, **kwargs )
name 参数可以有多种写法:
- (1)节点名
print(soup.find_all('p'))
# 输出结果如下:
[<p class="title" name="dromouse"><b>The Dormouse's story</b></p>, <p class="story">Once upon a time there were three little sisters; and their names were</p>]
- (2)正则表达式
print(soup.find_all(re.compile('^p')))
# 输出结果如下:
[<p class="title" name="dromouse"><b>The Dormouse's story</b></p>, <p class="story">Once upon a time there were three little sisters; and their names were</p>]
- (3)列表
如果参数为列表,过滤标准为列表中的所有元素。看下具体代码,你就会一目了然了。
print(soup.find_all(['p', 'a']))
# 输出结果如下:
[<p class="title" name="dromouse"><b>The Dormouse's story</b></p>, <p class="story">Once upon a time there were three little sisters; and their names were</p>, <a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>]
另外 attrs 参数可以也作为过滤条件来获取内容,而 limit 参数是限制返回的条数。
3)利用 CSS 选择器
以 CSS 语法为匹配标准找到 Tag。同样也是使用到一个函数,该函数为select()
,返回类型也是 list。它的具体用法如下, 同样以 prettify() 打印的结果为前提:
- (1)通过 tag 标签查找
print(soup.select(head))
# 输出结果如下:
[<head><title>The Dormouse's story</title></head>]
- (2)通过 id 查找
print(soup.select('#link1'))
# 输出结果如下:
[<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>]
- (3)通过 class 查找
print(soup.select('.sister'))
# 输出结果如下:
[<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>]
- (4)通过属性查找
print(soup.select('p[name=dromouse]'))
# 输出结果如下:
[<p class="title" name="dromouse"><b>The Dormouse's story</b></p>]
print(soup.select('p[class=title]'))
# 输出结果如下:
[<p class="title" name="dromouse"><b>The Dormouse's story</b></p>]
- (5)组合查找
print(soup.select("body p"))
# 输出结果如下:
[<p class="title" name="dromouse"><b>The Dormouse's story</b></p>,
<p class="story">Once upon a time there were three little sisters; and their names were</p>]
print(soup.select("p > a"))
# 输出结果如下:
[<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>]
print(soup.select("p > .sister"))
# 输出结果如下:
[<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>]
5 处理上下关系
从上文可知,我们已经能获取到节点对象,但有时候需要获取其父节点或者子节点的内容,我们要怎么做了?这就需要对parse tree
进行遍历
(1)获取子节点
利用.children
属性,该属性会返回当前节点所以的子节点。但是它返回的类型不是列表,而是迭代器
(2)获取所有子孙节点
使用.descendants
属性,它会返回所有子孙节点的迭代器
(3)获取父节点
通过.parent
属性可以获得所有子孙节点的迭代器
(4)获取所有父节点.parents
属性,也是返回所有子孙节点的迭代器
(5)获取兄弟节点
兄弟节点可以理解为和本节点处在统一级的节点,.next_sibling
属性获取了该节点的下一个兄弟节点,.previous_sibling
则与之相反,如果节点不存在,则返回 None
注意:实际 HTML 中的 tag 的.next_sibling
和 .previous_sibling
属性通常是字符串或空白,因为空白或者换行也可以被视作一个节点,所以得到的结果可能是空白或者换行
(5)获取所有兄弟节点
通过.next_siblings
和.previous_siblings
属性可以对当前节点的兄弟节点迭代输出