bs4的使用
bs4的使用
作用: Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4, 移植到BS4
补充:python中xml格式是用的比较少,但是java的配置文件可能会使用的比较多,比如在自动化运维中涉及到修改java 的配置文件就需要了解xml格式的配置文件,会用到内置的xml.etree.ElementTree这个包,bs4也可以用
#安装 Beautiful Soup
pip install beautifulsoup4
#安装解析器
Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml:
$ apt-get install Python-lxml
$ easy_install lxml
$ pip install lxml
另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:
$ apt-get install Python-html5lib
$ easy_install html5lib
$ pip install html5lib
#使用
from bs4 import BeautifulSoup
下表列出了主要的解析器,以及它们的优缺点,官网推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
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格式的文档 | 速度慢不依赖外部扩展 |
中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
示例:
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><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>
"""
#基本使用:容错处理,文档的容错能力指的是在html代码不完整的情况下,使用该模块可以识别该错误。使用BeautifulSoup解析上述代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml') #具有容错功能
res=soup.prettify() #处理好缩进,结构化显示
print(res)
遍历文档树
-
1.通过句点符.来查找标签,但是只能找到第一个
#通过.获取head标签
head = soup.head
print(head)
# <head><title>The Dormouse's story</title></head>
# 还是tag属性
print(type(head))
# <class 'bs4.element.Tag'>
title = head.title
print(title)
# <title>The Dormouse's story</title>
print(type(title))
# <class 'bs4.element.Tag'>
# 只能找到第一个p
p = soup.p
print(p)
# <p class="title"><b>The Dormouse's story</b></p>
-
2.获取标签的名字和属性
a = soup.a
print(type(a))
# 内部源码写了__getattr__和__getitem__方法,可以通过.name和[]来获取属性
print(a.name)
print(a['href'])
# <class 'bs4.element.Tag'>
# a
# http://example.com/elsie
# 获取属性第一种方法
p= soup.p
print(type(p))
# 内部源码写了__getattr__和__getitem__方法,可以通过.name和[]来获取属性
print(p['class'])
# 获取class属性是列表格式,因为clss属性是可以存在多个的,而id属性只能有一个
# ['title']
print(p['id'])
# 1
print(p.get('id'))
#1
# 获取属性第二种方法
# 通过attrs可以获得tag的属性值字典
print(p.attrs)
# {'class': ['title'], 'id': '1'}
print(p.attrs['class'])
#['title']
print(p.attrs.get('class'))
#['title']
-
3.获取标签文本内容
p= soup.p
print(p.text)
# The Dormouse's story
print(type(p.text))
# <class 'str'>
print(p.string)
# The Dormouse's story
print(type(p.string))
# <class 'bs4.element.NavigableString'>
print(p.strings)
# <generator object _all_strings at 0x00000134CFC48A98>
print(type(p.strings))
# <class 'generator'>
print(list(p.strings))
#["The Dormouse's story"]
#若标签内有多个嵌套内容,则上面的text和strings可以获取到内容
p= soup.p
print(p.text)
# 我在外层The Dormouse's story
print(type(p.text))
# <class 'str'>
print(p.string)
# None
print(type(p.string))
# <class 'NoneType'>
print(p.strings)
# <generator object _all_strings at 0x0000014D48688A98>
print(type(p.strings))
# <class 'generator'>
print(list(p.strings))
#['我在外层', "The Dormouse's story"]
-
4.嵌套选择(都是tag属性)
title = soup.head.title
print(title)
# <title>The Dormouse's story</title>
print(type(title))
# <class 'bs4.element.Tag'>
-
5.子节点和子孙节点
p1 = soup.p.children
p2 = soup.p.contents
print(p1) # 生成了一个迭代器
# <list_iterator object at 0x0000029F001B8940>
print(type(p1))
# <class 'list_iterator'>
print(list(p1)) # 对迭代器list就能取出里面的值
# [<b>The Dormouse's story</b>]
print(p2)
# [<b>The Dormouse's story</b>]
print(type(p2))
# <class 'list'>
-
6.父节点和祖先节点
p1 = soup.p.parent # 拿到p的父标签body标签的内容
p2 = soup.p.parents # 拿到p的父标签body和html标签以及body的父标签html标签
print(p1)
# print(type(p1))
# print(list(p1))
print(p2)
# print(type(p2))
print(list(p2))
-
7.兄弟节点
a = soup.a
print(soup.a.next_sibling) # 下一个兄弟
print(type(soup.a.next_sibling))
#<class 'bs4.element.NavigableString'>
print(list(soup.a.next_sibling))
print(soup.a.previous_sibling) # 上一个兄弟
查找文档树
查找文档树(以find和find_all为例),速度比遍历文档树要慢一点
-
字符串查找
# 以find为例
# 字符串查找(引号里面的内容)
p = soup.find(name='p')
print(p)
body = soup.find(name='body')
print(body)
# 通过属性类名class来查找,由于class是关键字,用class_来表示
# ret = soup.find_all(class_='title')
# print(ret)
#[<p class="title" id="1"><b>The Dormouse's story</b></p>, <p class="title" >我在外层<b>The Dormouse's story</b></p>]
# 通过id来查找,由于class是关键字,用class_来表示
ret = soup.find_all(id='1')
print(ret)
# [<p class="title" id="1"><b>The Dormouse's story</b></p>]
-
正则表达式查找
import re
# 编译一个以b开头的标签
reg = re.compile('^b')
ret = soup.find_all(name=reg)
print(ret)
-
列表查找
ret1 = soup.find_all(name=['body', 'b'])
ret2 = soup.find_all(id=['link1', 'link2'])
ret3 = soup.find_all(class=['title', 'story'])
print(ret)
# and关系
ret = soup.find_all(class_ ='title',name='p')
-
通过True
# 所有有名字的标签
ret = soup.find_all(name=True)
# 所有有id的标签
r et = soup.find_all(id=True)
# 所有有herf属性的
ret = soup.find_all(href=True)
-
通过自定义方法
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
print(soup.find_all(has_class_but_no_id))
-
其他方法
ret = soup.find_all(attrs={'class':'title','id':'id_pl'})
print(ret)
注意:拿到标签取属性用text
# find_all拿到的是列表
ret = soup.find_all(attrs={'class':'title','id':'id_pl'})
print(ret[0].text)
-
limt(限制获取数据的条数)
ret = soup.find_all(name=True,limt=2)
print(len(ret))
#2
-
recursive (是否递归查找,默认为Ture,改为False则只找第一层)
ret = soup.find_all(name=True,recursive=False)