爬蟲(四):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()
  • 記住經常使用的獲取屬性和文本值的方法
相關文章
相關標籤/搜索