Beautiful Soup 4 笔记

Beautiful Soup 4

摘自BS4.20文档
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库

安装

$ pip install beautifulsoup4

解析器

  • python标准库 BeautifulSoup(markup, "html.parser")
    不需安装,速度适中,容错能力强
  • lxml HTML 解析器 BeautifulSoup(markup, "lxml")
    速度快,容错强
  • lxml XML 解析器,BeautifulSoup(markup, ["lxml", "xml"])或者BeautifulSoup(markup, "xml")
    唯一支持XML的解析器
$ apt-get install Python-lxml

$ easy_install lxml

$ pip install lxml
  • html5lib
    速度慢,最好的容错性,以浏览器的方式解析文档,生成HTML5格式的文档
$ pip install html5lib

快速上手

用到的html文本

<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>

使用

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc)  #构造对象

print(soup.prettify())  #这样会根据soup的解析按照标准缩进,可以根据这个判断soup是否正确解析了一些不太规范的文档

基本使用

soup.title
# <title>The Dormouse's story</title>

soup.title.name
# u'title'

soup.title.string
# u'The Dormouse's story'

soup.title.parent.name
# u'head'

soup.p
# <p class="title"><b>The Dormouse's story</b></p>

soup.p['class']
# u'title'

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

soup.find_all('a')
# [<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>]

soup.find(id="link3")
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>

从文档中获取所有文字内容:

print(soup.get_text())

查找

将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象, 可以传入一段字符串或一个文件句柄。
文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码。
然后,Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档。

对象种类

1-tag

Tag 对象与XML或HTML原生文档中的tag相同。

name
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
tag.name
# u'b'  tag自己的名字
tag.name = "blockquote" #改变html文档
Attributes

一个tag可能有很多个属性. tag <b class="boldest"> 有一个 “class” 的属性,值为 “boldest” 。 tag的属性的操作方法与字典相同:

tag['class']
# u'boldest'

#直接”点”取属性, 比如: .attrs :
tag.attrs
# {u'class': u'boldest'}   #获得所有的属性
多值属性

在Beautiful Soup中多值属性的返回类型是list:

css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.p['class']
# ["body", "strikeout"]

css_soup = BeautifulSoup('<p class="body"></p>')
css_soup.p['class']
# ["body"]

如果转换的文档是XML格式,那么tag中不包含多值属性

xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
xml_soup.p['class']
# u'body strikeout'

2 - NavigableString

Beautiful Soup用 NavigableString 类来包装tag中的字符串:

tag.string
# u'Extremely bold'
type(tag.string)
# <class 'bs4.element.NavigableString'>
```py
通过 unicode() 方法可以直接将 NavigableString 对象转换成Unicode字符串。  
tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用 replace_with() 方法:
```py
tag.string.replace_with("No longer bold")
tag
# <blockquote>No longer bold</blockquote>

3-Comment

markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(markup)
comment = soup.b.string

#Comment 对象是一个特殊类型的 NavigableString 对象:

comment
# u'Hey, buddy. Want to buy a used parser'

遍历文档树

tag

.name

通过点取属性的方式只能获得当前名字的第一个tag:

#获取<body>标签中的第一个<b>标签:
soup.body.b
# <b>The Dormouse's story</b>

.contents 和 .children

.contents 属性可以将tag的子节点以列表的方式输出

 head_tag
# <head><title>The Dormouse's story</title></head>
head_tag.contents
[<title>The Dormouse's story</title>]

通过tag的 .children 生成器,可以对tag的子节点进行循环:

for child in title_tag.children:
    print(child)

.descendants

.contents 和 .children 属性仅包含tag的直接子节点.例如,<head>标签只有一个直接子节点<title>

head_tag.contents
# [<title>The Dormouse's story</title>]

但是<title>标签也包含一个子节点:字符串 “The Dormouse’s story”,这种情况下字符串 “The Dormouse’s story”也属于标签的子孙节点. .descendants 属性可以对所有tag的子孙节点进行递归循环

for child in head_tag.descendants:
    print(child)
    # <title>The Dormouse's story</title>
    # The Dormouse's story

.strings 和 stripped_strings

输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容

.parent 和 .parents

获取某个元素的父节点,层节点比如<html>的父节点是 BeautifulSoup 对象
通过元素的 .parents 属性可以递归得到元素的所有父辈节

link = soup.a
link
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
for parent in link.parents:
    if parent is None:
        print(parent)
    else:
        print(parent.name)
# p
# body
# html
# [document]
# None

.next_sibling 和 .previous_sibling

使用 .next_sibling 和 .previous_sibling 属性来查询兄弟节点

.next_element 和 .previous_element

.next_element 属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与 .next_sibling 相同,但通常是不一样的.

last_a_tag = soup.find("a", id="link3")
last_a_tag
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>

last_a_tag.next_sibling
# '; and they lived at the bottom of a well.'
last_a_tag.next_element
# u'Tillie'

搜索方法

其它方法的参数和用法类似

过滤器

  • 字符串 soup.find_all('b')
  • 正则表达式 soup.find_all(re.compile("^b"))
  • 列表(或条件) soup.find_all(["a", "b"])
  • True(可以匹配任何值) soup.find_all(True)
  • 方法
    如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False
def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')

find_all()

find_all( name , attrs , recursive , text , **kwargs )
  • name 参数
    name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉。
  • keyword 参数
    如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索。
soup.find_all(href=re.compile("elsie"), id='link1')

有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:

data_soup = BeautifulSoup('<div data-foo="value">foo!</div>')
data_soup.find_all(data-foo="value")
# SyntaxError: keyword can't be an expression

但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:

data_soup.find_all(attrs={"data-foo": "v
  • 按照css搜索
    通过 class_ 参数搜索有指定CSS类名的tag。
soup.find_all(class_=re.compile("itl"))
  • text 参数
    通过 text 参数可以搜搜文档中的字符串内容。
soup.find_all(text=re.compile("Dormouse"))

除了搜索字符串,还可以与其它参数混合使用来过滤tag

soup.find_all("a", text="Elsie")
  • limit 参数
    限制返回结果的数量
  • recursive 参数
    调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False


BeautifulSoup 对象和 tag 对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 find_all() 方法相同

soup.find_all("a")
soup("a")

find()

find_parents() 和 find_parent()

find_next_siblings() 和 find_next_sibling()

find_previous_siblings() 和 find_previous_sibling()

css选择器

在 Tag 或 BeautifulSoup 对象的 .select() 方法中传入字符串参数,即可使用CSS选择器的语法找到tag。
通过tag标签逐层查找:

soup.select("body a")

找到某个tag标签下的直接子标签 :

soup.select("head > title")

通过CSS的类名查找:

soup.select(".sister")

通过tag的id查找:

soup.select("#link1")
soup.select("a#link2")

是否存在某个属性来查找:

soup.select('a[href]')

通过属性的值来查找:

soup.select('a[href="http://example.com/elsie"]')

找到兄弟节点标签:

soup.select("#link1 ~ .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie"  id="link3">Tillie</a>]

soup.select("#link1 + .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

soup.select("#link1 + .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
posted @ 2016-11-30 16:02  jcuan  阅读(299)  评论(0)    收藏  举报