Title

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)

 

 

 

 

posted @ 2020-04-12 22:06  Mr江  阅读(315)  评论(0编辑  收藏  举报