【Python3 爬蟲學習筆記】解析庫的使用 5 —— Beautiful Soup 3
提取資訊
要獲取關聯元素節點的資訊,比如文字、屬性等,如下:
html = """
<html>
<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">Bob</a><a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>
</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print('Next Sibling:')
print(type(soup.a.next_sibling))
print(soup.a.next_sibling)
print(soup.a.next_sibling.string)
print('Parent:')
print(type(soup.a.parents))
print(list(soup.a.parents)[0])
print(list(soup.a.parents)[0].attrs['class' ])
執行結果如下:
Next Sibling:
<class 'bs4.element.Tag'>
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
Lacie
Parent:
<class 'generator'>
<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">Bob</a><a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
</p>
['story']
如果返回結果是單個節點,那麼可以直接呼叫string、attrs等屬性獲得其文字和屬性;如果返回結果是多個節點的生成器,則可以轉為列表後取出某個元素,然後再呼叫string、attrs等屬性獲取其對應節點的文字和屬性。
方法選擇器
find_all()
find_all,顧名思義,就是查詢所有符合條件的元素。給它傳入一些屬性或文字,就可以得到符合條件的元素,它的功能十分強大。
它的API如下:
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(name='ul'))
print(type(soup.find_all(name='ul')[0]))
執行結果如下:
[<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>]
<class 'bs4.element.Tag'>
這裡我們呼叫了find_all()方法,傳入name引數,其引數值為ul。也就是說,我們想要查詢所有ul節點,返回結果是列表型別,長度是2,每個元素依然都是bs4.element.Tag型別。
因為都是Tag型別,所以依然可以進行巢狀查詢。還是同樣的文字,這裡查詢出所有ul節點後,在繼續查詢其內部的li節點:
for ul in soup.find_all(name='ul'):
print(ul.find_all(name='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>]
返回結果是列表型別,列表中的每個元素依然還是Tag型別。
接下來,就可以裡邊每一個li,獲取它的文字了:
for ul in soup.find_all(name='ul'):
print(ul.find_all(name='li'))
for li in ul.find_all(name='li'):
print(li.string)
執行結果如下:
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
Foo
Bar
Jay
[<li class="element">Foo</li>, <li class="element">Bar</li>]
Foo
Bar
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>
</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'}))
執行結果如下:
[<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" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
這裡查詢的時候傳入的是attrs引數,引數的型別是字典型別。比如,要查詢id為list-1的節點,可以傳入attrs={‘id’:‘list-1’}的查詢條件,得到的結果是列表形式,包含的內容就是符合id為list-1的所有節點。在上面的例子中,符合條件的元素個數是1,所以結果是長度為1的列表。
對於一些常用的屬性,比如id和class等,我們可以不用attrs來傳遞。比如,要查詢id為list-1的節點,可以直接傳入id這個引數。還是上面的文字,我們換一種方式來查詢:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(id='list-1'))
print(soup.find_all(class_='element'))
執行結果如下:
[<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
這裡直接傳入id=‘list-1’,就可以查詢id為list-1的節點元素了。而對於class來說,由於class在Python裡是一個關鍵字,所以後面需要加一個下劃線,即class_=‘element’,返回的結果依然還是Tag組成的列表。