1. 程式人生 > >Python爬蟲包 BeautifulSoup 學習(四) bs基本物件與函式

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("")的物件,

我們已經得到了標籤,用 .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')