python3實現網絡爬蟲(4)--BeautifulSoup使用(3)

這一次我們繼續來講一下BeautifulSoup的相關知識,說一下BeautifulSoup導航樹的相關內容。

     在上一次的博客中我們瞭解到findAll函數通過標籤的名稱和屬性來查找標籤,但有的時候在進網頁中的內容爬取時,我們會發現有些我們想要獲取的元素並不是都可以通過名稱來獲得的,因爲我們要考慮到有些網站在編寫的時候,只有一些需要特殊效果的標籤會進行屬性值的設置,而有些普通的標籤是不會進行屬性值的設置的,所以我們會遇到這種情況:當我們想要抓取一些標籤中的內容時,我們在對源碼進行分析時發現它的標籤並沒有設置class、type這些容易我們使用findAll函數的值,那我們這個時候如果強行使用findAll,很可能會抓取到很多無用的標籤,這會增大我們後期的分析難度,是不可取的,這個時候我們便需要通過其它特性進行標籤 的抓取了。我們其實可以通過抓取其它帶有特定屬性的標籤,然後通過這個標籤和我們目標標籤之間的關係進行轉化,然後得到我們想要的標籤。這個可以理解爲兩種解決問題的方法啊,在我們解答數學題的時候經常會用到的,這就是有的問題我們可以通過直接求解進行解答,但有的問題需要通過間接求解然後進行相應的轉化才能得到最終的結果,下面我們就來看看導航樹給我們帶來的一些功能。

     顧名思義啊,導航樹是一棵樹。從我們現實世界中出發,樹就是樹幹和樹枝組成,當然作爲一個抽象化成一種方法的樹,導航樹比現實世界中的樹的枝和幹要多很多,是一棵非常豐滿的樹,有很多的枝幹。導航樹就是將HTML頁面映射成一棵樹,這棵樹分別在橫向和縱向進行延伸,橫向延伸的都是同級的標籤,比如說一個ul標籤中包含很多的li標籤,這些li標籤就是同級的;縱向延伸的是不同級的標籤,其關係就是父與子的關係,包含與被包含的關係。

下面是豆瓣首頁中源碼的一個簡潔的截圖:


     在上圖中我們可以看到,body下有子節點div,div下還有div標籤組,div下還包含div標籤組,之後div包含li標籤組。

下面我們就以這個HTML標籤結構爲例進行解說:

1、處理子標籤和其它後代標籤 

       在BeautifulSoup中,孩子標籤和後代標籤與我們現實社會的人類的家譜是一樣的,子標籤是一個父標籤的下一級,而後代標籤是指一個父標籤下面所有級別的標籤。例如,在我們剛剛選擇的源碼中,ul是div的子標籤,而ul、li和a則都是div標籤的後代標籤。所有的子標籤都是後代標籤,但不是所有的後代標籤都是子標籤。

       在BeautifulSoup中,它的函數總是處理當前標籤的後代標籤,並不會處理其它的標籤,正如我們前面的博客中說過的,bsObj.body.div這段代碼是會選擇body部分的div進行查找,並不會跑到body外面(如head)的區域進行查找的,就像你在學校選定了計科院進行查找一個人的時候,是絕對不會查找別的院的。

       比如說我們只想拿到豆瓣中每部電影的那個源碼(可以用來後期解析使用),如下圖所示,我們想要得到奇異博士這部影片在網頁中這個框的區域所有的源碼,在右邊的源碼彙總我們可以看出,這是存放在一個ul中的,可是我們會發現這個ul沒有帶什麼屬性,那麼我們嘗試使用以前的代碼試一試。


程序如下:

#coding:utf - 8
from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("https://movie.douban.com/")
bsObj=BeautifulSoup(html,"lxml")    #將html對象轉化爲BeautifulSoup對象
ulList=bsObj.findAll("ul")    #找到所有ul
for ul in ulList:
    print(ul)
程序運行結果如下:

<ul>
<li class="">
<a data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com/" target="_blank">
              豆瓣
            </a>
</li>
<li class="">
<a data-moreurl-dict='{"from":"top-nav-click-book","uid":"0"}' href="https://book.douban.com/" target="_blank">
              讀書
            </a>
</li>
<li class="on">
<a data-moreurl-dict='{"from":"top-nav-click-movie","uid":"0"}' href="https://movie.douban.com/">
              電影
            </a>
</li>
<li class="">
<a data-moreurl-dict='{"from":"top-nav-click-music","uid":"0"}' href="https://music.douban.com/" target="_blank">
              音樂
            </a>
</li>
<li class="">
<a data-moreurl-dict='{"from":"top-nav-click-location","uid":"0"}' href="https://www.douban.com/location/" target="_blank">
              同城
            </a>
</li>
<li class="">
<a data-moreurl-dict='{"from":"top-nav-click-group","uid":"0"}' href="https://www.douban.com/group/" target="_blank">
              小組
            </a>
</li>
<li class="">
<a data-moreurl-dict='{"from":"top-nav-click-read","uid":"0"}' href="https://read.douban.com/?dcs=top-nav&amp;dcm=douban" target="_blank">
              閱讀
            </a>
</li>
<li class="">
<a data-moreurl-dict='{"from":"top-nav-click-fm","uid":"0"}' href="https://douban.fm/?from_=shire_top_nav" target="_blank">
              FM
            </a>
</li>
<li class="">
<a data-moreurl-dict='{"from":"top-nav-click-commodity","uid":"0"}' href="https://dongxi.douban.com/?dcs=top-nav&amp;dcm=douban" target="_blank">
              東西
            </a>
</li>
<li class="">
<a data-moreurl-dict='{"from":"top-nav-click-market","uid":"0"}' href="https://market.douban.com/?utm_campaign=douban_top_nav&amp;utm_source=douban&amp;utm_medium=pc_web" target="_blank">
              市集
            </a>
</li>
<li>
<a class="bn-more" href="#more"><span>更多</span></a>
<div class="more-items">
<table cellpadding="0" cellspacing="0">
<tr><td><a data-moreurl-dict='{"from":"top-nav-click-moment","uid":"0"}' href="https://moment.douban.com" target="_blank">一刻</a></td></tr>
<tr><td><a data-moreurl-dict='{"from":"top-nav-click-ypy","uid":"0"}' href="https://ypy.douban.com" target="_blank">豆瓣攝影</a></td></tr>
</table>
</div>
</li>
</ul>
。。。。。。

        從上面的結果我們可以發現,不對啊,怎麼會有一個ul顯示的內容不是我們想要的關於電影的一些信息,這時候我們回到網頁的源碼中進行查看,會看到如下的ul,是不符合我們的需求的,如下圖所示:

        這時我們會發現,有個多餘的ul是我們不想要的,其實這種情況在我們以後的爬取過程中會經常發生的,這就需要我們解決了,最好的方法就是在爬取的時候就把這些無用的信息扔掉,而不是在拿到手後進行處理,要做到防範於未然嘛,預防總比治療來得輕鬆嘛。

那我們到網頁中去看看,有什麼可以解決的方法呢,然後我們可以看到ul的父親節點是有屬性的,這就是我們的突破點了,如下圖:


修改後的程序如下

#coding:utf - 8
from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("https://movie.douban.com/")
bsObj=BeautifulSoup(html,"lxml")    #將html對象轉化爲BeautifulSoup對象
liList=bsObj.findAll("li",{"class":"ui-slide-item"})    #找到所有li
for li in liList:
    ul=li.children     #由於children是個孩子集合,所以下面要迭代進行查看
    for child in ul:
        print(child)
程序運行如下:

<ul class="">
<li class="poster">
<a href="https://movie.douban.com/subject/26630781/?from=showing" οnclick="moreurl(this, {from:'mv_a_pst'})">
<img alt="我不是潘金蓮" class="" rel="nofollow" src="https://img3.doubanio.com/view/movie_poster_cover/lpst/public/p2378133884.jpg"/>
</a>
</li>
<li class="title">
<a class="" href="https://movie.douban.com/subject/26630781/?from=showing" οnclick="moreurl(this, {from:'mv_a_tl'})">我不是潘金蓮</a>
</li>
<li class="rating">
<span class="rating-star allstar35"></span><span class="subject-rate">7.1</span>
</li>
<li class="ticket_btn"><span><a href="https://movie.douban.com/subject/26630781/cinema/" οnclick="moreurl(this, {from:'mv_b_tc'})">選座購票</a></span></li>
</ul>

。。。。。。。

      這次是不是就不會有多餘的了,比較細心的同學有可能會發現在這個網頁中這些ul的class並不都是ui-slide-item,有的是"ui-slide-item s",這個問題可能是網站的顯示問題啊,因爲在我們抓取到 的網頁源碼上就不是這樣了,當然有興趣的可以去研究下爲什麼。

     這樣我們就拿到了這些電影的整體信息了,那我們要想對它們做分析是不是就很簡單了

2、處理兄弟標籤

      BeautifulSoup可以使用next_siblings()函數處理一些處理相同等級的相同標籤,就像我們剛剛拿到的ul中的li標籤,滿足這一個性質,我們可以通過next_siblings()函數進行處理。

這次我們就處理奪路而逃這個電影中的li,以便於理解:

#coding:utf - 8
from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("https://movie.douban.com/")
bsObj=BeautifulSoup(html,"lxml")    #將html對象轉化爲BeautifulSoup對象
li=bsObj.find("li",{"data-title":"奪路而逃"})    #找到符合條件的li
for li1 in li.li.next_siblings:
    print(li1)
程序運行如下:

<li class="title">
<a class="" href="https://movie.douban.com/subject/26125842/?from=showing" οnclick="moreurl(this, {from:'mv_a_tl'})">奪路而逃</a>
</li>

<li class="rating">
<span class="text-tip">暫無評分</span>
</li>

<li class="ticket_btn"><span><a href="https://movie.douban.com/subject/26125842/cinema/" οnclick="moreurl(this, {from:'mv_b_tc'})">選座購票</a></span></li>


      這裏我們會發現,咦,一共有四個li標籤,爲什麼少了一個,那是因爲一個li標籤 不能將自己作爲自己的兄弟標籤,所以第一條li被跳過了,這裏我們只是爲了 演示這個next_siblings的用法,當然這個方法對於表格處理是很有效果的,因爲 表格的第一行是提示的文字信息,我們在處理 表格數據時是不需要的,那麼這個next_siblings就起到作用了。

      和next_siblings一樣,如果你很容易找到一組兄弟標籤的最後一個標籤,那麼previous_siblings函數也會很有用。與此對應的還有next_sibling和previous_sibling,它們與next_siblings和previous_siblings作用類似,只是它們返回的是單個標籤,而不是一組標籤。

3、父標籤處理

      在抓取網頁的時候,我們一般想要得到的都是一些子標籤,因爲父標籤一般是爲了模塊更好的展示進行合併的一種表示方法,只是一個框架,對於我們的用處是不大的,但是有些 時候我們也是可能會用到的,比如說上面在找ul時,我們可以通過帶class屬性的子標籤來得到這個父標籤ul,父標籤可以爲parent和parents。

程序如下圖:

#coding:utf - 8
from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("https://movie.douban.com/")
bsObj=BeautifulSoup(html,"lxml")    #將html對象轉化爲BeautifulSoup對象
liList=bsObj.findAll("li",{"class":"poster"})    #找到所有li
for li in liList:
    ul=li.parent
    print(ul)
運行結果就不貼了 ,還是一樣的。


      這樣我們就講完了導航樹了,這些方法如何適當使用在我們的爬蟲中,還是可以起到很好的效果的。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章