Beautiful Soup解析
阅读指导:
这篇文章详细讲解了Beautiful Soup解析的方法。每个方法都配有相应的代码示例,读者可以通过本文更深入地了解Beautiful Soup。由于文章篇幅较长,建议通过目录选择您感兴趣的部分进行学习。
2. Beautiful Soup
Beautiful Soup提供了简单易用的 API 来导航、搜索和修改解析树。Beautiful Soup 通过将复杂的 HTML 文档转换为一个树形结构,使得解析和操作 HTML 内容变得更加方便。
其优点是:
- 强大的文档解析能力
- 多种解析器支持
- 灵活的节点搜索和导航功能
2.1 初步使用
使用实例:
<!--假设这是某个网页页面的页面代码,页面链接为 URL -->
<html><head><title>The Dormouse's story</title></head>
<body>
<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
<a href="http://example.com/elsie" class="sister" id="link1">
<!--Elsie -->
</a>,
<a href="http://example.com/lacie" class="sister" id="link2">
Lacie
</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
获取代码:
from bs4 import BeautifulSoup
import requests
url = "URL"
html= requests.get(url)
soup = BeautifulSoup(html, 'lxml')
print(soup.prettify())
print(soup.title.string)
输出:
<html>
<head>
<title>
The Dormouse's story
</title>
</head>
<body>
<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
<a class="sister" href="http://example.com/elsie" id="link1">
<!-- Elsie -->
</a>
,
<a class="sister" href="http://example.com/lacie" id="link2">
Lacie
</a>
and
<a class="sister" href="http://example.com/tillie" id="link3">
Tillie
</a>
;
and they lived at the bottom of a well.
</p>
<p class="story">
...
</p>
</body>
</html>
The Dormouse's story
代码解释:
soup.prettify()该方法,将要解析的字符串以标准的缩进格式输出。
soup.title.string通过string属性,输出title标签里面的文字
2.2 节点选择器
使用 . 的方式依次按层级的向下访问,当出现有同样多个节点的时候,只会匹配到第一个节点而忽略后面的结点。
例:
<!--./html-->
<html><head><title>The Dormouse's story</title></head>
<body>
<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
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
获取代码:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.title)
print(type(soup.title))
print(soup.title.string)
print(soup.head)
print(soup.p)
输出:
<title>The Dormouse's story</title>
<class 'bs4.element.Tag'>
The Dormouse's story
<head><title>The Dormouse's story</title></head>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
输出解释:
<class ‘bs4.element.Tag’>这个类型是Beautiful Soup中一个很重要的数据结构,经过选择器的选择后,都是这种Tag类型,并且里面有很多属性也是很常用的,比如strig等。
以下的对数据的获取方式,都是基于<class ‘bs4.element.Tag’>这个Tag类型开展的。
2.2.1 节点选择器获取名称
利用name属性来获取节点的名称
注意:这个名称是标签名
例:
<!--html-->
<html><head><title>The Dormouse's story</title></head>
获取代码:
print(soup.title.name)
输出:
title
2.2.2 节点选择器获取属性
利用attars来获取一个元素的属性
返回的是一个字典,并且键值对里面的值部分,要注意其数据类型
例:
<!--./html-->
<html><head><title>The Dormouse's story</title></head>
<body>
<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
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
获取代码:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.p.attrs)
print(soup.p.attrs["name"])
print(soup.p.attrs["class"])
输出:
{'class': ['title'], 'name': 'dromouse'}
dromouse
['title']
2.2.3 节点选择器获取内容
使用string属性来获取元素的内容
例:
<!--html-->
<html><head><title>The Dormouse's story</title></head>
获取代码:
soup = BeautifulSoup(html, 'lxml')
print(soup.title.string)
输出:
The Dormouse's story
2.2.4 节点选择器的嵌套选择
使用 . 来对Tag类型的对象继续向下做进一步的选择或处理
<!--html-->
<html><head><title>The Dormouse's story</title></head>
<body>
获取代码:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.head.title)
print(type(soup.head.title))
print(soup.head.title.string)
输出:
<title>The Dormouse's story</title>
<class 'bs4.element.Tag'>
The Dormouse's story
2.3 方法选择器
find_all查询所有符合条件的元素
基本语法:
find_all(name, attrs, recursive, text, **kwarge)
下面进行深度讲解:
2.3.1 方法选择器获取名称
使用name属性来获取
例:
<!--html-->
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1">
<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()
print(type(soup.find_all(name='ul')[0]))
print()
for ul in soup.find_all(name='ul'):
print(ul.find_all(name='li'))
print()
for ul in soup.find_all(name='ul'):
print(ul.find_all(name='li'))
for li in ul.find_all(name='li'):
print(li.string)
输出:
[<ul class="list" id="list-1">
<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'>
[<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>]
[<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
2.3.2 方法选择器获取属性
第一种:使用attrs来对节点的属性进行查询,这是比较普遍使用的方式
例:
获取 id 属性值为 “list-1” 和 name 属性为 “eLements” 的节点
<!--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()
print(soup.find_all(attrs={'name': 'elements'}))
print()
输出:
[<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>]
第二种:对于class,id这种常用属性,可以直接使用
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(id='list-1'))
print()
print(soup.find_all(class_='element'))
输出:
[<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
[<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>]
2.3.3 方法选择器获取内容
在find_all中使用 string 参数,对 string 赋值为正则表达式来获取元素的文字,不要用text参数,这个已经被废除
例:
<!--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>
获取代码:
import re
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(string=re.compile("link")))
输出:
['Hello, this is a link', 'Hello, this is a link, too']
2.3.4 查询第一个符合的元素
采用 find方式 ,这与find_all的获取数据的方式相同,只是范围不同罢了,find只查询符合条件的第一个元素。
2.4 css选择器
使用select方式获取元素,其获取数据的方式也find_all类似
例:
我们要使用 CSS 选择器来提取所有链接和列表项
<!--html-->
<html>
<head>
<title>Example Page</title>
</head>
<body>
<div class="panel">
<div class="panel-body">
<a href="http://example.com/link1" class="link">Link 1</a>
<a href="http://example.com/link2" class="link">Link 2</a>
</div>
</div>
<ul id="list">
<li class="item">Item 1</li>
<li class="item">Item 2</li>
<li class="item">Item 3</li>
</ul>
</body>
</html>
获取代码:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
# 使用 CSS 选择器选择所有链接
links = soup.select('a.link')
for link in links:
print(link.get_text(), link['href'])
# 使用 CSS 选择器选择所有列表项
items = soup.select('ul#list li.item')
for item in items:
print(item.get_text())
输出:
Link 1 http://example.com/link1
Link 2 http://example.com/link2
Item 1
Item 2
Item 3
代码解释:
- soup.select(‘a.link’):选择所有带有class=“link” 的 < a > 标签。
- link.get_text():获取链接文本。
- link[‘href’]:获取链接的 href 属性值。
- soup.select(‘ul#list li.item’):选择
- 标签中带有 id=“list” 的所有
标签,并且这些- 标签带有 class=“item”。
常见的css选择器
表示 | 描述 | 例子 |
---|---|---|
tag | 选择所有指定标签的元素。 | 例如:div。 |
.class | 选择所有指定类的元素。 | 例如:.panel-body。 |
#id | 选择所有指定 ID 的元素。 | 例如:#list。 |
tag.class | 选择指定标签且带有指定类的元素。 | 例如:a.link。 |
tag#id | 选择指定标签且带有指定 ID 的元素。 | 例如:ul#list。 |
tag[attr=value] | 选择指定标签且带有指定属性值的元素。 | 例如:a[href=“http://example.com/link1”]。 |
parent > child | 选择所有指定父标签的直接子标签。 | 例如:div > a。 |
ancestor descendant | 选择所有指定祖先标签的后代标签。 | 例如:div a。 |