Beautiful Soup

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。

 Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml 。

推荐使用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格式的文档
  • 速度慢
  • 不依赖外部扩展

 

 

html_doc = """
<html>
  <head>
    <title>The Dormouse's story</title>
  </head>
  <body>
    <p class="title">
      <b>The Dormouse's story</b> 
        <span>eng</span>
      <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>
    </p>
    <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 class="story">...</p>
"""
 
标签选择器
选择元素
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
soup.title#返回是一个tag对象
# <title>The Dormouse's story</title>
print(soup.head)
# <head>
# <title>The Dormouse's story</title>
# </head>
print(soup.p)
# <p class="title">
#<b>The Dormouse's story</b>
#<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
#</p>
print(soup.a)
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

 

获取标签名称
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.title.name)
# title

 

获取标签属性
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.a['href'])
# http://example.com/elsie
print(soup.a.attrs['href'])
# http://example.com/elsie

 

获取标签文本内容
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.title.string)
# The Dormouse's story

 如果tag中包含多个字符串 ,可以使用 .strings 来循环获取:

for string in soup.strings:
    print(repr(string))
    # u"The Dormouse's story"
    # u'\n\n'
    # u"The Dormouse's story"
    # u'\n\n'
    # u'Once upon a time there were three little sisters; and their names were\n'
    # u'Elsie'
    # u',\n'
    # u'Lacie'
    # u' and\n'
    # u'Tillie'
    # u';\nand they lived at the bottom of a well.'
    # u'\n\n'
    # u'...'
    # u'\n'
#输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容
for string in soup.stripped_strings:
    print(repr(string))

 

嵌套选择
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.head.title.string)#返回是一个tag对象,可以在此之上继续选择
# The Dormouse's story

 

子节点
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.p.contents)#返回含有所有子节点tag对象的一个列表
#['\n', <b>The Dormouse's story</b>, '\n', <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, '\n']

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.p.children)#返回含有所有子节点tag对象的一个列表迭代器
#<list_iterator object at 0x037F8FE8>

for i, child in enumerate(soup.p.children):
    print(i,child)

#0

#1 <b>The Dormouse's story</b>
#2

#3 <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
#4

 

子孙节点
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.p.contents)#返回含有所有子孙节点tag对象的一个列表
#['\n', <b>The Dormouse's story</b>, '\n', <span>eng</span>, '\n', <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, '\n']

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.p.descendants)#返回含有所有子节点tag对象的一个列表迭代器
#<generator object Tag.descendants at 0x0130B808>
for i, child in enumerate(soup.p.descendants):
    print(i,child)

#0

#1 <b>The Dormouse's story</b>
#2 The Dormouse's story
#3

#4 <span>eng</span>
#5 eng
#6

#7 <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
#8 Elsie
#9

 

兄弟节点
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.a.next_sibling)#下一个兄弟节点tag对象
print(soup.a.next_siblings)#下面所有兄弟节点tag对象
print(list(enumerate(soup.a.next_siblings)))

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.a.previous_sibling)#上一个兄弟节点tag对象
print(soup.a.previous_siblings)#上面所有兄弟节点tag对象
print(list(enumerate(soup.a.previous_siblings)))

 

搜索文档树

用来查找到想要查找的文档内容,着重介绍2个: find() 和 find_all()

 

过滤器

字符串

soup.find_all('b')#查找与字符串完整匹配的内容
# [<b>The Dormouse's story</b>]

 

正则表达式

import re
for tag in soup.find_all(re.compile("^b")):#通过正则表达式的 search() 来匹配内容
    print(tag.name)
# body
# b

 

列表

soup.find_all(["a", "b"])#如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回
# [<b>The Dormouse's story</b>,
#  <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

 

True

#True 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
for tag in soup.find_all(True):
    print(tag.name)
# html
# head
# title
# body
# p
# b
# p
# a
# a
# a
# p

 

方法

#如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,
#如果这个方法返回 True 表示当前元素匹配并且被找到,
#如果不是则反回 False
def has_class_but_no_id(tag): return tag.has_attr('class') and not tag.has_attr('id') soup.find_all(has_class_but_no_id) # [<p class="title"><b>The Dormouse's story</b></p>, # <p class="story">Once upon a time there were...</p>, # <p class="story">...</p>]

 

 

标准选择器
find_all( name , attrs , recursive , string , **kwargs )
 
name
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.find_all("a"))#返回所有a标签的tag对象的列表
#[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
print(soup.find_all('a')[0])
#<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

 

attrs
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.find_all("a"))#返回所有a标签的ta
print(soup.find_all(attrs = {'id':'link2'}))#定义一个字典参数来搜索包含特殊属性的ta
print(soup.find_all(id = 'link2'))#id、class_可以简写,class要加_
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

 

string
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.find_all("a", string="Elsie"))#返回所有字符串与 string 参数值相符的tag
# [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]

soup.find_all(string=["Tillie", "Elsie", "Lacie"]) # 列表
# ['Elsie', 'Lacie', 'Tillie']

soup.find_all(string=re.compile("Dormouse")) #正则表达式
# ["The Dormouse's story", "The Dormouse's story"]

#find( name , attrs , recursive , string , **kwargs )#返回第一个
#find_parents() 和 find_parent()
#find_next_siblings() 和 find_next_sibling()
#find_previous_siblings() 和 find_previous_sibling()
#find_all_next() 和 find_next()
#find_all_previous() 和 find_previous()

 

CSS选择器
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.select("title"))#传入字符串参数,返回是列表
# [<title>The Dormouse's story</title>]

print(soup.select("p:nth-of-type(3)"))
# [<p class="story">...</p>]

 

通过tag标签逐层查找
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.select("p a"))
#[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

 

找到某个tag标签下的直接子标签
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.select("p > a"))
#[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

 

获取属性
rom bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.select('a[href]'))
#[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
for a in soup.select('a'):
    print(a['id'])
    print(a.attrs['id'])#另外一种写法

#link1
#link2
#link3

 

获取文本内容
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
for a in soup.select('a'):
    print(a.get_text())

#Elsie
#Lacie
#Tillie

 

 

 

posted @ 2020-08-23 22:28  稽否  阅读(104)  评论(0)    收藏  举报