python爬虫从入门到放弃(六)之 BeautifulSoup库的使用

上一篇文章的正则,其实对不少人来讲用起来是不方便的,加上须要记不少规则,因此用起来不是特别熟练,而这节咱们提到的beautifulsoup就是一个很是强大的工具,爬虫利器。html

beautifulSoup “美味的汤,绿色的浓汤”前端

一个灵活又方便的网页解析库,处理高效,支持多种解析器。
利用它就不用编写正则表达式也能方便的实现网页信息的抓取html5

快速使用

经过下面的一个例子,对bs4有个简单的了解,以及看一下它的强大之处:python

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,'lxml')
print(soup.prettify())
print(soup.title)
print(soup.title.name)
print(soup.title.string)
print(soup.title.parent.name)
print(soup.p)
print(soup.p["class"])
print(soup.a)
print(soup.find_all('a'))
print(soup.find(id='link3'))

结果以下:正则表达式

使用BeautifulSoup解析这段代码,可以获得一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出。工具

同时咱们经过下面代码能够分别获取全部的连接,以及文字内容:spa

for link in soup.find_all('a'):
    print(link.get('href'))

print(soup.get_text())

解析器

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,若是咱们不安装它,则 Python 会使用 Python默认的解析器,lxml 解析器更增强大,速度更快,推荐安装。code

下面是常看法析器:orm

推荐使用lxml做为解析器,由于效率更高. 在Python2.7.3以前的版本和Python3中3.2.2以前的版本,必须安装lxml或html5lib, 由于那些Python版本的标准库中内置的HTML解析方法不够稳定.xml

基本使用

标签选择器

在快速使用中咱们添加以下代码:
print(soup.title)
print(type(soup.title))
print(soup.head)
print(soup.p)

经过这种soup.标签名 咱们就能够得到这个标签的内容
这里有个问题须要注意,经过这种方式获取标签,若是文档中有多个这样的标签,返回的结果是第一个标签的内容,如上面咱们经过soup.p获取p标签,而文档中有多个p标签,可是只返回了第一个p标签内容

获取名称

当咱们经过soup.title.name的时候就能够得到该title标签的名称,即title

获取属性

print(soup.p.attrs['name'])
print(soup.p['name'])
上面两种方式均可以获取p标签的name属性值

获取内容

print(soup.p.string)
结果就能够获取第一个p标签的内容:
The Dormouse's story

嵌套选择

咱们直接能够经过下面嵌套的方式获取

print(soup.head.title.string)

子节点和子孙节点

contents的使用
经过下面例子演示:

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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,'lxml')
print(soup.p.contents)

结果是将p标签下的全部子标签存入到了一个列表中

列表中会存入以下元素

children的使用

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

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

经过contents以及children都是获取子节点,若是想要获取子孙节点能够经过descendants
print(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

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

name的用法

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>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all('ul'))
print(type(soup.find_all('ul')[0]))

结果返回的是一个列表的方式

同时咱们是能够针对结果再次find_all,从而获取全部的li标签信息

for ul in soup.find_all('ul'):
    print(ul.find_all('li'))

attrs

例子以下:

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1" name="elements">
            <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>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(attrs={'id': 'list-1'}))
print(soup.find_all(attrs={'name': 'elements'}))

attrs能够传入字典的方式来查找标签,可是这里有个特殊的就是class,由于class在python中是特殊的字段,因此若是想要查找class相关的能够更改attrs={'class_':'element'}或者soup.find_all('',{"class":"element}),特殊的标签属性能够不写attrs,例如id

text

例子以下:

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>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(text='Foo'))

结果返回的是查到的全部的text='Foo'的文本

find

find(name,attrs,recursive,text,**kwargs)
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()返回第一个符合条件的节点

CSS选择器

经过select()直接传入CSS选择器就能够完成选择
熟悉前端的人对CSS可能更加了解,其实用法也是同样的
.表示class #表示id
标签1,标签2 找到全部的标签1和标签2
标签1 标签2 找到标签1内部的全部的标签2
[attr] 能够经过这种方法找到具备某个属性的全部标签
[atrr=value] 例子[target=_blank]表示查找全部target=_blank的标签

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>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))
print(type(soup.select('ul')[0]))

获取内容

经过get_text()就能够获取文本内容

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>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for li in soup.select('li'):
    print(li.get_text())

获取属性
或者属性的时候能够经过[属性名]或者attrs[属性名]

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>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for ul in soup.select('ul'):
    print(ul['id'])
    print(ul.attrs['id'])

总结

推荐使用lxml解析库,必要时使用html.parser标签选择筛选功能弱可是速度快建议使用find()、find_all() 查询匹配单个结果或者多个结果若是对CSS选择器熟悉建议使用select()记住经常使用的获取属性和文本值的方法

相关文章
相关标签/搜索