【Python】 html解析BeautifulSoup


BeautifulSoup

  bs是個html解析模塊,常用來做爬蟲?

  ■  安裝

  BeautifulSoup可以通過pip來安裝,用pip install beautifulsoup4 即可。但是僅僅這樣安裝的bs,其默認的html解析器是python自帶的HTMLParser模塊,性能不是很好。可以考慮安裝性能更加好的lxml和html5lib模塊:pip install html5lib

  

  ■  基本用法

   BeautifulSoup有官方文檔,可以查閱

  ① 建立BeautifulSoup對象,它是基於一個html字符串或者一個文件

from bs4 import BeautifulSoup
soup = BeautifulSoup("...一串html")
#或者
soup = BeautifulSoup(open("文件路徑","r"))

print soup.prettify()    #可以美化這段html並打印出來

   ②  四類對象

   bs將一個html抽象成一個樹形結構,每個節點都是一個python里的對象。共分成了四種對象。

   ●  Tag類對象

    即html中的標簽,BeautifulSoup對象(以上面代碼中的soup為例)可以直接在后面接上某種標簽的名稱,得到的對象是該種標簽在這段html中的第一個實例。

    比如對於print soup.h1 >>> <h1 class="...">...</h1>  (bs里的html對象是可打印的,打印出來就是html原文)

    每個Tag類對象都有兩個屬性,name和attrs。

    name就是標簽的名字,而attrs是個字典,里面記錄了所有這個tag的屬性值。比如有tag是<h1 class="space-seo space-meta" name="testname">HELLO</h1>

    其name就是u'h1',而attrs是{u'class':[u'space-seo',u'space-meta'],u'name':u'testname'}  //注意區別tag對象的name屬性和寫在attrs里面的name屬性的區別,另外所有被存到變量里的html內容全部都變成了unicode對象。在print的時候可以指定encode,默認encode是utf-8。還有,所有class屬性都默認都被解析成一個列表,即便只有一個class值,也會成為[u'class_value']

    當然,在定位到Tag對象之后可以獲取查看其屬性值,另一方面,也可以對其屬性值等進行修改,修改完了之后就是存在內存中的這個變量里面的,最終可以輸出成文件的形式。

   ●  String對象  //selenium用的是text來指代標簽內部的文本內容,而bs用的是string。而且對於<div>這種本身不帶文本帶后輩節點可能帶文本的標簽兩者意義不同。selenium中的.text會帶出來所有后輩節點中的文本,而bs中的這個.string返回的是None

    String對象用於代表每個元素所含的文字部分,在標簽后面加上.string即可調用

    print soup.h1.string >>> HELLO

    注意,某個Tag對象的子節點以及子節點里面的內容都不算進string,當一個元素(比如<div>這種)里面只有子節點,本身沒有文字的話,得到的就是None。

    ●  BeautifulSoup對象

    指代整個文檔的對象。可以視為是<html>的對象。其實之前創建的BeautifulSoup對象soup,就是指代整個html文檔

    ●  comment對象

    用於代表某個元素內的注釋

■  遍歷文件樹

    除了上面提到的一些基本屬性,Tag對象(包括BeautifulSoup對象)都含有以下屬性:

    Tag.contents  將某個Tag的各個子節點(不包括孫和孫以下節點)按照列表的方式輸出

    Tag.children  返回一個上述列表的迭代器,也只有子節點(沒有孫和孫以下節點)

    Tag.descendants  返回一個迭代器,內容是所有后輩節點

    Tag.strings  返回Tag中所有的文字部分的生成器,保留換行,制表符等空格。相當於是prettify之后去掉所有html標簽的文本狀態。

    Tag.stripped_strings  和上一項相比,再去掉所有空白字符,只保留有實際字符的文本部分。這兩個方法常用於對被分析網頁文本的搜索和處理。

 

    Tag.parent  父節點

    Tag.parents  長輩節點的迭代器

 

    Tag.next_sibling  下一個同輩節點(如果沒有同輩就返回None,下同)

    Tag.previous_sibling  上一個同輩節點

    Tag.next_sibilings  之后所有同輩節點的迭代器

    Tag.previous_sibilings  之前所有同輩節點的迭代器

    //關於同輩節點有一個坑。。在看起來比較美觀的HTML文檔中,總是有很多換行符合制表符的。而在BS中如果要調用一個同輩節點,那么這些空白的文本節點也都會被算進去。比如:

 

#<p><span>one</span><span id="main">two</span></p>
print soup.find(name="span",attrs={"id":"main"}).previous_sibling
#得到的是<span>one</span>

#如果處理的是這樣一段HTML:
#<p>
#    <span>one</span>
#    <span id="main">two</span>
#</p>
print repr(soup.find(name="span",attrs={"id":"main"}).previous_sibling)
#得到的是"\n\t"因為在第一個span之前有一段空白文本被當做一個節點了。

 

 

 

    然而在通過這個span.parent尋找p或者是通過p.children尋找span的時候,這些空白文本節點都不會被算進去。所以只有在引用同輩節點的時候要注意。

    

    Tag.next_element  下一個元素,包括string對象,子節點,同輩分節點在內,無視輩分的下一個

    Tag.previous_element  上一個元素,說明同上

    Tag.next_elements  next_element的迭代器

    Tag.previous_elements  previous_element的迭代器

    

  ■  檢索文件樹方法

    ●  Tag.find_all(name,attr,recursive,text,**kwargs) 方法。功能是檢索Tag內所有后輩節點,並判斷是否符合某種條件,最后返回一個列表

      1.  name參數

      name參數可以直接寫Tag.name。比如find_all("p"),find_all("div")等

      也可以寫正則表達式(re.compile之后的對象)。比如find_all(re.compile("^b"))

      也可以寫列表,比如find_all(['a','p'])

      甚至可以寫一個函數對象,這時就要自己定義這個函數了。這個函數要接收一個Tag對象來作為參數,並最終返回True或者False來告訴find_all這個對象該不該被find進去

      2.  attr參數

      attr參數可以指定一個字典的形式來過濾,比如find_all(attrs={'id':'testid'})就是找到所有id是testid的元素

      3.  text參數

      用於搜索字串內容。也可以支持name參數中那幾種寫的形式。注意,返回的不是對象的列表,而是文本的列表。當name和text的參數同時出現的話,text會作為name的一個附加條件,返回的還是帶標簽的列表。

      4.  recursive參數

      默認是True,可改成False放棄遞歸進子輩以下子節點。只檢索第一級的子節點。

      5.  limit參數

      有時候文檔太大了,檢索所有元素很費時間,limit可以指定一個數值,當檢索找到了這個數量的目標之后就停止檢索

    

     ●  Tag.find方法:參數和find_all一致,只不過其返回的不是一個列表,而是找到第一個就返回了。

 

     ●  Tag.find_parents    Tag.find_parent

      Tag.find_next_sibilings    Tag.find_next_sibiling

      Tag.find_previous_sibilings    Tag.find_previous_sibiling

      Tag.find_all_next    Tag.find_next

      Tag.find_all_previous  Tag.find_previous

      以上所有方法,每行前一個和后一個的關系就是find_all和find的關系。而每一行相當於是為檢索指定了一個大致的范圍。比如說find_all和find是在所有后輩節點中檢索的話,那么find_parents和find_parent就是在所有長輩節點中尋找,find_next_sibilings和find_next_sibiling就是在所有后面的同輩節點中尋找等等

    

     ●  Tag.select("selector")  可以借助select方法來確定一個或多個特定的元素,默認查找全部符合的元素並返回一個列表。selector的語法就是jQuery里面selector的語法。這個方法還是比較實用的。與之相對的有select_one方法,只返回第一個查找到的元素。

 

總的來說,不管是通過一個節點,遍歷文件樹的方法來找到想要獲得的節點對象,還是通過檢索方法來定位一個節點對象,都是尋找對象的一種方法。很難說哪種最好哪種不好,應該要靈活運用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM