beautifulSoup模块

  这个库用来对网页进行解析功能,十分强大,有了它我们可以减少对正则的使用,也能顺利的从网页源码中拿到我们要的值。他是一个灵活,方便的网页解析库,处理高效,支持多种解析器。

  这个库把HTML源码解析成对象与对象的关系,这样就不需要操作字符串这样简单的繁琐的操作了。

  BeautifulSoup是将HTML转化为一个复杂的树形结构,每个节点都是python对象,有前端基础的同学会知道,类似DOM对象。BeautifulSoup中的对象大致有四种,Tag、NavigableString、BeautifulSoup、Comment。

bs4初相见

  BeautifulSoup解析一个HTML源码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出。在实际操作中,我们会将所需要的标签通过选择器查找出来,然后通过操作Tag对象来获取所需信息。

from bs4 import BeautifulSoup

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>
'''
soup = BeautifulSoup(html,'html.parser')
print(soup.prettify())
##############################
输出的结果:
'''
<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 class="sister" href="http://example.com/elsie" id="link1">
    Elsie
   </a>
   ,
   <a class="sister" href="http://example.com/lacie" id="link2">
    Lacie
   </a>
   and
   <a class="sister" href="http://example.com/tillie" id="link3">
    Tillie
   </a>
   ;
and they lived at the bottom of a well.
  </p>
  <p class="story">
   ...
  </p>
 </body>
</html>
'''
BeautifulSoup解析格式化输出

  这样我们就可以轻松的找到复杂的网页结构中我们需要的信息了。

print(soup.find_all('a'))#包含所有a标签的列表[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,...]
for link in soup.find_all('a'):
    print(link.get('href'))#取出所有链接
print(soup.get_text())#取出标签里的文本信息
找到所有a标签下的链接

  可以看出bs4的功能是十分的强大,用起来也非常的简单,较之正则表达式操作起来也是非常的简单。

解析器

  Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,推荐我们安装lxml解析器,这个解析器更加强大,速度更快。

  几种常见的解析器:

基本操作

  标签选择器:通过这种soup.标签名 我们就可以获得这个标签的内容。通过这种方式获取标签,如果文档中有多个这样的标签,返回的结果是第一个标签的内容,如上面我们通过soup.p获取p标签,而文档中有多个p标签,但是只返回了第一个p标签内容。

print(soup.title)#<title>The Dormouse's story</title>
print(type(soup.title))#<class 'bs4.element.Tag'>是一个bs4的对象
print(soup.p)#取到的第一个标签<p class="title"><b>The Dormouse's story</b></p>
print(soup.a)#<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

  获取名称:当我们通过soup.title.name的时候就可以获得该title标签的名称,即title。

print(soup.title.name)#title
print(type(soup.title.name))#<class 'str'>
print(soup.title.parent.name)#head(取到了父标签名字)

  获取属性:

print(soup.p.attrs['name'])
print(soup.p['name'])
print(soup.p["class"])#['title']把所有的class名存放到一个列表中返回,也有可能属性不是class是其他
print(soup.p.attrs["class"])#['title']

  获取内容:

print(soup.标签.string)
结果就可以获取第一个标签的内容。
print(soup.title.string)#The Dormouse's story
print(soup.p.string)#The Dormouse's story

  嵌套选择:

print(soup.head.title.string)#The Dormouse's story

  子节点和子孙节点:

print(soup.p.contents)#结果是将一个p标签下的所有子标签存入到了一个列表中
for link in soup.find_all('p'):#soup.p与link都是bs4的p标签的对象
    print(link.contents)
#[<b>The Dormouse's story</b>]
#['Once upon a time there were three little sisters; and their names were\n', <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, ',\n', <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, ' and\n', <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>, ';\nand they lived at the bottom of a well.']
#['...']

  children获取p标签下的所有子节点内容和通过contents获取的结果是一样的,但是不同的地方是soup.p.children是一个迭代对象,而不是列表,只能通过循环的方式获取素有的信息。

for link in soup.find_all('p'):
    print(link.children.__next__())#说明它是一个可迭代对象

  通过contents以及children都是获取子节点,如果想要获取子孙节点可以通过soup.descendants,这种获取的结果也是一个迭代器。

  父节点和祖先节点

  通过soup.a.parent就可以获取父节点的信息;

  通过list(enumerate(soup.a.parents))可以获取祖先节点,这个方法返回的结果是一个列表,会分别将a标签的父节点的信息存放到列表中,以及父节点的父节点也放到列表中,并且最后还会讲整个文档放到列表中,所有列表的最后一个元素以及倒数第二个元素都是存的整个文档的信息。

  兄弟节点:

soup.a.next_siblings 获取后面的兄弟节点
soup.a.previous_siblings 获取前面的兄弟节点
soup.a.next_sibling 获取下一个兄弟标签
souo.a.previous_sinbling 获取上一个兄弟标签

 find_all用法

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
假设现在爬取了这样的网页

  find_all(name,attrs,recursive,text,**kwargs)可以根据标签名,属性,内容查找文档。

  参数详解:

  name参数:

  取出标签为name的所有标签,存放到列表中,索引取出来都是bs4对象。

soup = BeautifulSoup(html, 'lxml')
print(soup.find_all('ul'))#取出所有ul放入一个列表中,每一个ul单独取都是一个bs4对象
'''
[<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>, <ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>]
'''
print(type(soup.find_all('ul')[0]))#<class 'bs4.element.Tag'>

  要获得里面的li标签则需要对每个bs4对象再次使用find_all()方法。

for ul in soup.find_all('ul'):
    print(ul.find_all('li'))
'''
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
[<li class="element">Foo</li>, <li class="element">Bar</li>]
'''

  name除了可以传字符串以外还可以传正则表达式或者列表。

#name传这三种方式都可以
print(soup.find_all('p'))
print(soup.find_all(re.compile('^b')))
print(soup.find_all(['p','title']))

  attr参数:

print(soup.find_all(attrs={'id': 'list-1'}))
print(soup.find_all('',{"class":"element"}))#class需要使用这种方式取

  attrs可以传入字典的方式来查找标签,但是这里有个特殊的就是class,因为class在python中是特殊的字段,所以如果想要查找class相关的可以更改为soup.find_all('',{"class":"element})或者soup.findAll(class_='class')

  text参数:

print(soup.find_all(text='Foo'))#['Foo', 'Foo']
print(soup.find_all(text='Fo'))#[]

  结果返回的是查到的所有的text='Foo'的文本,必须精确匹配。

  recursive参数:

  recursive的默认参数为True,BeautifulSoup会查找所有后代节点,而只想搜索子节点时,可设置参数为False。

  find的用法:

  find(name,attrs,recursive,text,**kwargs),与find_all()的区别就是find返回的匹配结果的第一个元素。

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()返回第一个符合条件的节点
find的用法

css选择器

  bs4提供select()直接传入CSS选择器就可以完成选择,与前端匹配css的方式基本一致。

print(soup.select('.panel .panel-heading'))#[<div class="panel-heading"><h4>Hello</h4></div>]
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))#[<li class="element">Foo</li>, <li class="element">Bar</li>]
print(type(soup.select('ul')[0]))#<class 'bs4.element.Tag'>

  get_text()获取内容:

for li in soup.select('li'):
    print(li.get_text())

  通过[属性名]或者attrs[属性名]获得属性:

for ul in soup.select('ul'):
    print(ul['id'])#两种方法的效果一致
    print(ul.attrs['id'])

  可以说这个库是非常的实用的,这里只是一部分常用的操作,还有更多的操作,在使用bs4的时候可以进一步查找官方文档:Beautiful Soup 4.4.0 文档

posted @ 2017-12-22 15:18  JeffD  阅读(579)  评论(0编辑  收藏  举报