使用BeautifulSoup进行爬虫
BeautifulSoup 是 Python 的一个库,它主要用于网页解析,从 HTML 或 XML 文件中提取数据。
BeautifulSoup的安装
pip install beautifulsoup4
beautifulsoup4被移植到了bs4模块中,所以需要使用from bs4 import BeautifulSoup
来导入
解析器
Beautifulsoup支持Pyhton标准库包含的HTML解析器,也支持许多第三方Python解析器,如"lxml", “html5lib”, 下面是各个解析器的比较
解析器 | 用法 | 优点 | 缺点 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, “html.parser”) | 在Python标准库中,不需要额外安装 | 文档容错能力差 |
lxml的HTML解析器 | BeautifulSoup(markup, “lxml”) | 速度快,容错能力强 | 需要安装C语言库 |
lxml的XML解析器 | BeautifulSoup(markup, “xml”) | 速度快,支持xml格式 | 需要安装C语言库 |
html5lib | BeautifulSoup(markup, “html5lib”) | 容错性好,以浏览器的方式解析文档,生成HTML5格式的文档 | 速度慢,不依赖外部扩展 |
简单应用
解析HTML代码
from bs4 import BeautifulSoup
import requests
url = "https://www.baidu.com"
response = requests.get(url)
response.encoding = "utf-8"
html = response.text
soup = BeautifulSoup(html, "lxml")
# soup = BeautifulSoup(open('index.html'),"lxml") 可以解析本地HTML文件
print(soup.prettify()) # prettify()方法可以进行代码的格式化
调用属性获取节点内容
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag
, NavigableString
, BeautifulSoup
, Comment
.
对象是可以被修改的,但是会影响所有通过当前Beautiful Soup对象生成的HTML文档,在爬虫中不建议这么做
获取节点对应代码
soup.tag
print("head节点内容为",soup.head)
print("title节点内容为",soup.title)
print("p节点内容为",soup.p) # 只返回第一个搜索到的节点内容
print("a节点内容为",soup.a)
print("a节点的名称",soup.a.name) # 使用.name获取节点名称
获取节点对应属性
soup.tag.attrs
返回字典类型,使用下标索引可以获取指定的属性值,并省略attrs
如:
from bs4 import BeautifulSoup
html_doc = """
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>A Test in HTML</title> <script src="./test.js"></script></head>
<body>
<h1 class="h" id="h1">Hello World</h1> <div id="1">1one一壹</div> <div id="2">2two二贰</div> <p>你们好</p></body>
</html>
"""
soup = BeautifulSoup(html_doc, "lxml")
print("meta节点中的属性:", soup.meta.attrs) # meta节点中的属性: {'charset': 'UTF-8'}
print("h1节点中的类属性:", soup.h1['class']) # h1节点中的类属性: ['h']
获取节点包含文本内容
soup.tag.string
返回字符串
嵌套获取节点内容
soup.tag.children
返回指定标签的指定子节点,如soup.body.div.a
div_1 = soup.body.div # 类型:<class 'bs4.element.Tag'>
a_div = div_1.a # 类型:<class 'bs4.element.Tag'>
print(a_div) # 返回第一个div标签下的第一个a标签对应代码
关联获取
属性 | 功能 | 数据类型 |
---|---|---|
contents | 获取所有子节点内容 | list |
children | 获取所有子节点内容 | list_iterator |
descendants | 获取所有子孙节点内容 | generator |
parent | 获取父节点内容 | <class ‘bs4.element.Tag’> (String) |
parents | 获取从父节点开始的以上内容 | generator |
next_sibling | 获取该节点的下一个兄弟节点 | <class ‘bs4.element.NavigableString’> |
previous_sibling | 获取该节点的上一个兄弟节点 | <class ‘bs4.element.NavigableString’> |
next_siblings | 获取该节点后面的所有兄弟节点 | generator |
previous_siblings | 获取该节点前面的所有兄弟节点 | generator |
调用方法获取节点内容
获取所有符合条件的内容
find_all(name=None, attrs=Noe, recursive=True, text=None, limit=None, **kwargs)
- name: 节点名称
- attrs: 指定属性,字典类型,其中class属性需要用"class_"来实现,因为class在Python中是关键字
- recursive: 搜索tag的子孙节点或者直接子节点
- text: 指定文本内容,可以用字符串或正则表达式
- limit: 限制返回数量
返回一个bs4.element,ResultSet类型数据,与列表数据相似,其中元素是<class ‘bs4.element.Tag’>类型
获取第一个匹配条件的内容
方法 | 功能 |
---|---|
find() | 获取第一个匹配到的节点内容 |
find_parent() | 获取父节点内容 |
find_next_sibling() | 获取后面一个兄弟节点内容 |
find_previous_sibling() | 获取前面一个兄弟节点内容 |
find_next() | 获取当前节点的下一个第一个符合条件的节点内容 |
find_previous() | 获取当前节点的上一个第一个符合条件的节点内容 |
其他方法
方法 | 功能 |
---|---|
find_parents() | 获取所有祖先节点内容 |
find_next_siblings() | 获取后面所有兄弟节点内容 |
find_previous_siblings() | 获取前面所有兄弟节点内容 |
find_all_next() | 获取当前节点的下一个所有符合条件的节点内容 |
find_all_previous() | 获取当前节点的上一个所有符合条件的节点内容 |
CSS选择器
如果是Tag或BeautifulSoup对象都可以直接调用select()方法,填写指定参数即可通过CSS选择器来获取节点内容,依旧返回一个bs4.element,ResultSet类型数据
示例:
from bs4 import BeautifulSoup
html_doc = """
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>A Test in HTML</title> <script src="./test.js"></script></head>
<body>123
<h1 class="h" id="h1">111</h1> <div id="div_1">1one一壹</div> <div id="div_2">2two二贰</div> <p>你们好</p></body>
</html>
"""
soup = BeautifulSoup(html_doc, "lxml")
print(soup.select("div")[0].get_text()) # 获取第一个div节点内的文本内容
print(soup.select("#div_1")[0]) # 获取id为'div_1'的节点内容
具体请参考CSS选择器参考手册,来自w3school。