Python爬蟲包 BeautifulSoup 學習(四) bs基本物件與函式
四大物件種類
BeautifulSoup將複雜HTML文件轉換成一個複雜的樹形結構。如圖所示
每個節點都是Python物件,我們只用根據節點進行查詢就可以了,因為解析工作交給了框架本身。所有物件可以歸納為4種:
- Tag
- NavigableString
- BeautifulSoup
- Comment
Tag
什麼是Tag,舉幾個例子
<title>The Dormouse's story</title>
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a >
上面的title a 等等 HTML 標籤加上裡面包括的內容就是 Tag。
在前幾次的文章中,我們就是通過Tag來獲取資訊的。
如獲得標籤<title>
print soup.title
#<title>The Dormouse's story</title>
我們可以利用 bs4加標籤名輕鬆地獲取這些標籤的內容,比用正則表示式求方便很多。
不過有一點是,它查詢的是在所有內容中的第一個符合要求的標籤,如果要查詢所有的標籤,則需要使用find()
和find_all()
(findAll()
)這兩個函式,後面兩個函式在目前的程式碼中來看功能和語法是一樣的,如果後期有什麼區別,我會再返回來講的。
for item in soup.findAll('a'):
print item,'\n'
print soup.find('a')
print soup.find_all('a', limit = 1)[0]
# limit 是取前x項的意思,find()實際等於limit=1的情況,只是find_all()返回的是列表
print soup.find_all(lambda tag: len(tag.attrs) == 2)
# BS4允許我們把特定函式型別當做findAll函式的引數,唯一的限制是這些函式必須把一個標籤當做引數且返回結果為bool型別
我們可以驗證一下這些物件的型別
print type(soup.a)
# <class 'bs4.element.Tag'>
對於Tag而言,有兩個很重要的屬性,一個是name,一個是attrs。
name
print soup.name
print soup.head.name.
# [document]
# head
soup 物件本身比較特殊,它的 name 即為 [document],對於其他內部標籤,輸出的值便為標籤本身的名稱。
attrs
print soup.p.attrs
# {'class': ['title'], 'name': 'dromouse'}
在這裡,我們把 p 標籤的所有屬性列印輸出了出來,得到的型別是一個字典。
如果我們想要單獨獲取某個屬性,可以這樣,例如我們獲取它的 class 叫什麼
print soup.p.attrs
# {'class': ['title'], 'name': 'dromouse'}
還可以這樣,利用get方法,傳入屬性的名稱,二者是等價的
print soup.p.get('class')
# ['title']
我們可以對這些屬性和內容等等進行修改,例如
soup.p['class']="newClass"
print soup.p
# <p class="newClass" name="dromouse"><b>The Dormouse's story</b></p>
還可以對這個屬性進行刪除,例如
del soup.p['class']
print soup.p
#<p name="dromouse"><b>The Dormouse's story</b></p>
不過,對於修改刪除的操作,不是我們的主要用途,在此不做詳細介紹了,如果有需要,請檢視前面提供的官方文件。
同時我們也可以通過這個attrs去更加詳細地過濾標籤
print soup.find_all('a', {"class" : "sister"})
# 限制了標籤為a,且屬性中的class = sister
# "sister的位置也可以是一個re.compile("")的物件,
NavigableString
我們已經得到了標籤,用 .string 即可獲得標籤內部的文字。
如獲得標籤<p>
中的內容
print soup.p.string
#The Dormouse's story
這樣我們就輕鬆獲取到了標籤裡面的內容,想想如果用正則表示式要多麻煩。它的型別是一個 NavigableString,翻譯過來叫 可以遍歷的字串。
來檢查一下它的型別
print type(soup.p.string)
# <class 'bs4.element.NavigableString'>
BeautifulSoup
BeautifulSoup 物件表示的是一個文件的全部內容。大部分時候,可以把它當作 Tag 物件,是一個特殊的 Tag,我們可以分別獲取它的型別,名稱,以及屬性來感受一下。
print type(soup.name)
# <type 'unicode'>
print soup.name
# [document]
print soup.attrs
# {}
Comment
Comment 物件是一個特殊型別的 NavigableString 物件,其實輸出的內容仍然不包括註釋符號,但是如果不好好處理它,可能會對我們的文字處理造成意想不到的麻煩。
我們找一個帶註釋的標籤
print soup.a
print soup.a.string
print type(soup.a.string)
執行結果如下
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
Elsie
<class 'bs4.element.Comment'>
a 標籤裡的內容實際上是註釋,但是如果我們利用 .string 來輸出它的內容,我們發現它已經把註釋符號去掉了,所以這可能會給我們帶來不必要的麻煩。
另外我們列印輸出下它的型別,發現它是一個 Comment 型別,所以,我們在使用前最好做一下判斷,判斷程式碼如下
if type(soup.a.string)==bs4.element.Comment:
print soup.a.string
上面的程式碼中,我們首先判斷了它的型別,是否為 Comment 型別,然後再進行其他操作,如列印輸出。
# -*- coding: utf-8 -*-
# @Author: HaonanWu
# @Date: 2016-12-24 17:27:43
# @Last Modified by: HaonanWu
# @Last Modified time: 2016-12-24 19:53:47
from bs4 import BeautifulSoup
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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>
"""
def Tree_test(soup):
print soup.prettify()
def Tag_test(soup):
print soup.title
print type(soup.a)
for item in soup.findAll('a'):
print item,'\n'
print soup.find('a')
print soup.find_all('a', limit = 1)
print soup.name
print soup.head.name
print soup.p.attrs
print soup.p.get('class')
def string_test(soup):
print soup.p.string
print type(soup.p.string)
def bs_test(soup):
print soup.name
print soup.attrs
print type(soup.name)
def comment_test(soup):
print soup.a
print soup.a.string
print type(soup.a.string)
if __name__ == '__main__':
soup = BeautifulSoup(html, 'lxml')