BeautifulSouphtml
bs是個html解析模塊,經常使用來作爬蟲?html5
■ 安裝python
BeautifulSoup能夠經過pip來安裝,用pip install beautifulsoup4 便可。可是僅僅這樣安裝的bs,其默認的html解析器是python自帶的HTMLParser模塊,性能不是很好。能夠考慮安裝性能更加好的lxml和html5lib模塊:pip install html5lib正則表達式
■ 基本用法函數
BeautifulSoup有官方文檔,能夠查閱性能
① 創建BeautifulSoup對象,它是基於一個html字符串或者一個文件spa
from bs4 import BeautifulSoup soup = BeautifulSoup("...一串html") #或者 soup = BeautifulSoup(open("文件路徑","r")) print soup.prettify() #能夠美化這段html並打印出來
② 四類對象code
bs將一個html抽象成一個樹形結構,每一個節點都是一個python裏的對象。共分紅了四種對象。xml
● Tag類對象htm
即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方法,只返回第一個查找到的元素。
總的來講,不論是經過一個節點,遍歷文件樹的方法來找到想要得到的節點對象,仍是經過檢索方法來定位一個節點對象,都是尋找對象的一種方法。很難說哪一種最好哪一種很差,應該要靈活運用。