bs4
bs4
BS4全称是Beatiful Soup,它提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为tiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编一下原始编码方式就可以了。
所以,它能处理html、xml,可以提取,也可以修改。
一种简单的常见的爬虫策略,requests + bs4,前者完成http请求下载,后者能完成html的解析。另外,用re库也能完成网页解析。
资源
- https://www.jb51.net/article/179145.htm
- https://www.zhihu.com/question/42181509/answer/455722802
- https://www.cnblogs.com/fu-yong/p/9226008.html
- https://blog.csdn.net/qq_43194257/article/details/87786316
- https://blog.csdn.net/dongyu1703/article/details/82022549
- https://zhuanlan.zhihu.com/p/35354532?utm_source=qq 优质文档
官方文档
安装
pip install beautifulsoup4
建议使用 -i参数,指定国内的镜像源。
相关的解析器
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格式的文档
速度慢
不依赖外部扩展
使用
最常用的还是BeautifulSoup对象和Tag对象,解析主要靠Tag对象,所以需要掌握bs4.element.Tag 的系列方法
对象
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳以下4种:
- Tag对象:是html中的一个标签,用BeautifulSoup就能解析出来Tag的具体内容,与XML或HTML原生文档中的tag相同。
- BeautifulSoup对象:整个html文本对象,可当作Tag对象
- NavigableString对象:标签内的文本对象
- Comment对象:是一个特殊的NavigableString对象,如果html标签内存在注释,那么它可以过滤掉注释符号保留注释文本
参数,第一个参数为html文本。选择解析器features="lxml"或者默认features="html.parser"。返回的对象。
from bs4 import BeautifulSoup
res = requests.get(链接)
# 使用默认的解析器
# soup = BeautifulSoup(res.text, features="html.parser")
# 或者
# 需要pip install lxml
soup = BeautifulSoup(res.text,"lxml")
soup = BeautifulSoup(res.text, features="lxml")
for ul in soup.find_all(name='ul'):
for li in ul.find_all(name='li'):
查找三板斧
说句实话,我比较钟爱select方法,灵活、而且基本上不会增加额外的学习成本。
- select
注意返回的是列表,不能直接get(‘属性名’)**。如果只有一个元素,也要用[0]来取**。也可遍历
soup.select("div.content h4 a")
soup.select("div.content h4 a")[0]
soup.select("div.content h4 a").select("")
soup.select("div.content h4 a").find("")
find
快捷方式 tag.find(‘a’) => tag.a 无法带搜索条件。
这个返回的是一个元素。
soup.find(name="div",class_='content').find()
soup.find(name="div",class_=re.complie(r'\d+')).find()
# 如果不需要参数,只通过 name就能找到,可以简写
soup.find(name="div",class_='content').a
find_all
快捷方式 tag.find_all(‘a’) => tag(‘a’)
加上limit=1 find_all 等价于 find。 如 tag.find_all(‘a’,limit=1)
注意返回的是一个列表。也可遍历
soup.find(name="div",class_='content')
参数说明:
find、find_all的参数如下,对与参数,主要有tag或属性来搜索。
而利用tag.name或tag.attrs属性来进行过滤,(即过滤器)属性的取值可以有:
- 字符串,完全匹配
- 正则表达式,按正则的方式来匹配
- 列表,匹配多个。
- True,只要有就行。
- 方法, 如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回
True表示当前元素匹配并且被找到,如果不是则反回False
| 参数 | 名称 | 示例 |
|---|---|---|
| name | html节点名称,如div、h3、a、article等 | div |
| id | 节点的id | id=”main-btn” |
| class_ | 节点的类。估计是为了防止跟关键字重名 | 字符串或正则 |
| text | 文本内容。但是需要将结果转换str | 字符串或正则 |
| limit | 限制返回数量。 | 2 |
| recursive | tag_all方法时,控制是否要遍历子孙节点。 | |
补充示例:
movieCommentNum = str(detail.find(text=re.compile('\d+人评价')))
movieName = detail.find('span', class_='title').get_text()
# 根据内容来匹配
# 找到标签内的文本为story的文本内容
print(soup.find_all(text='story'))
# 找到标签内的文本含有story的文本内容
print(soup.find_all(text=re.compile(r'.*?story.*?')))
由于结果多数都是bs4.element.Tag或者 bs4.element.Tag数组。主要参考下面
取值
即掌握下面的内容
bs4.element.Tag
soup = BeautifulSoup(...)
soup.b 返回第一个标签
- 获取Tag的name
tag.name
# 修改
tag.name = "p"
- Tag的Attributes属性
# 获取单个属性 ,注意返回 list
tag['class'] # ['active']
# 获取所有属性
tag.attrs # {'class': ['active']}
# 像字典那样操作
tag.get('class')
# 添加属性
tag['class'] = 'inactive'
tag['class'] = ['inactive','content'] # 注意,赋值多个class 属性
tag['id'] = 10
# 删除属性
del tag['id']
- 文本内容
string得到标签下的文本内容,只有在此标签下没有子标签,或者只有一个子标签的情况下才能返回其中的内容,否则返回的是None;
get_text()可以获得一个标签中的所有文本内容,包括子孙节点的内容,这是最常用的方法
print(soup.a.string) # 标签里面的内容
print(soup.a.get_text())
html
# 能返回html,也能修复缺失的内容
soup.prettify()
可遍历
获取html的内容
li_list = ul.find_all('li')
for li in li_list:
print(type(li))
html = li.prettify()
print(type(html))
print(html)
其他方法
find_parents()和find_parent(): 前者返回所有祖先节点 后者返回直接父节点
find_next_sibings()和find_next_sibling(): 前者返回所有兄弟节点 后者返回后面第一个兄弟节点
find_previous_siblings()和find_previous_siblings(): 前者返回前面所有的兄弟节点 后者返回前面第一个兄弟节点