BeautifulSoup庫介紹

一個靈活又方便的網頁解析庫,處理高效,支持多種解析器。
利用它就不用編寫正則表達式也能方便的實現網頁信息的抓取html

BS快速使用

經過下面的一個例子,對bs4有個簡單的瞭解,以及看一下它的強大之處:前端

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

結果以下:html5

使用BeautifulSoup解析這段代碼,可以獲得一個 BeautifulSoup 的對象,並能按照標準的縮進格式的結構輸出。python

同時咱們經過下面代碼能夠分別獲取全部的連接,以及文字內容:正則表達式

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

print(soup.get_text())

解析器

Beautiful Soup支持Python標準庫中的HTML解析器,還支持一些第三方的解析器,若是咱們不安裝它,則 Python 會使用 Python默認的解析器,lxml 解析器更增強大,速度更快,推薦安裝。spa

下面是常看法析器:code

推薦使用lxml做爲解析器,由於效率更高. 在Python2.7.3以前的版本和Python3中3.2.2以前的版本,必須安裝lxml或html5lib, 由於那些Python版本的標準庫中內置的HTML解析方法不夠穩定.orm

基本使用

標籤選擇器xml

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

經過這種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()
記住經常使用的獲取屬性和文本值的方法

BS功能強大,操做方便,功能靈活,是解析網頁的利器,建議複雜網頁使用bs,簡單的網頁能夠用xpath等庫實現。

相關文章
相關標籤/搜索