爬虫(四):BeautifulSoup库的使用

一:beautifulsoup简介html

beautifulsoup是一个很是强大的工具,爬虫利器。前端

beautifulSoup “美味的汤,绿色的浓汤”html5

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

二:经常使用解析库正则表达式

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

下面是常看法析器:工具

解析器 使用方法 优点 劣势
Python标准库 BeautifulSoup(markup, "html.parser") Python的内置标准库、执行速度适中 、文档容错能力强 Python 2.7.3 or 3.2.2)前的版本中文容错能力差
lxml HTML 解析器 BeautifulSoup(markup, "lxml") 速度快、文档容错能力强 须要安装C语言库
lxml XML 解析器 BeautifulSoup(markup, "xml") 速度快、惟一支持XML的解析器 须要安装C语言库
html5lib BeautifulSoup(markup, "html5lib") 最好的容错性、以浏览器的方式解析文档、生成HTML5格式的文档 速度慢、不依赖外部扩展

 

 

 

 

 

 三:基本使用spa

# BeautifulSoup入门
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') # 建立BeautifulSoup对象
print(soup.prettify()) # 格式化输出
print(soup.title) # 打印标签中的全部内容
print(soup.title.name) # 获取标签对象的名字
print(soup.title.string) # 获取标签中的文本内容  == soup.title.text
print(soup.title.parent.name)  # 获取父级标签的名字
print(soup.p)  # 获取第一个p标签的内容
print(soup.p["class"])  # 获取第一个p标签的class属性
print(soup.a) # 获取第一个a标签
print(soup.find_all('a'))  # 获取全部的a标签
print(soup.find(id='link3')) # 获取id为link3的标签
print(soup.p.attrs) # 获取第一个p标签的全部属性
print(soup.p.attrs['class']) # 获取第一个p标签的class属性
print(soup.find_all('p',class_='title')) # 查找属性为title的p


# 经过下面代码能够分别获取全部的连接以及文字内容

for link in soup.find_all('a'):
    print(link.get('href')) # 获取连接

print(soup.get_text())获取文本

(1):标签选择器code

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

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

(2):获取名称

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

(3):获取属性

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

(4):获取内容

    print(soup.p.string)
    结果就能够获取第一个p标签的内容。

(5):嵌套选择   

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

    print(soup.head.title.string)

(6):子节点和子孙节点

a、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标签中的全部内容,各部分存入一个列表


################################ 运行结果
['\n            Once upon a time there were three little sisters; and their names were\n            ', <a class="sister" href="http://example.com/elsie" id="link1">
<span>Elsie</span>
</a>, '\n', <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, '\n            and\n            ', <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>, '\n            and they lived at the bottom of a well.\n        ']
#################################

b、children的使用

print(soup.p.children)
for i,child in enumerate(soup.p.children):
    print(i,child)
# 经过children也能够获取内容,和contents获取的结果是同样的,可是children是一个迭代对象,而不是列表,只能经过循环的方式获取信息

print(soup.descendants)# 获取子孙节点

(7):父节点和祖父节点

经过soup.a.parent就能够获取父节点的信息

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

(8):兄弟节点

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

 

四:标准选择器

(1):find_all

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

a、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'))  # 找到全部ul标签
print(type(soup.find_all('ul')[0])) # 拿到第一个ul标签

# find_all能够屡次嵌套,如拿到ul中的全部li标签
for ul in soup.find_all('ul'):
    print(ul.find_all('li'))

b、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'}))  # 找到id为ilist-1的标签
print(soup.find_all(attrs={'name': 'elements'})) # 找到name属性为elements的标签

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

c、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"的文本

(2)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]))

a、获取内容

经过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())

b、获取属性

获取属性的时候能够经过[属性名]或者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()
  • 记住经常使用的获取属性和文本值的方法
相关文章
相关标签/搜索