爬蟲:python之BeautifulSoup(lxml)
阿新 • • 發佈:2019-02-13
一、簡介
一個靈活又方便的HTML解析庫,處理高效,支援多種解析器,利用它不使用正則表示式也能抓取網頁內容。
解析器 | 使用方法 | 優勢 | 劣勢 |
python標準庫 | BeautifulSoup(markup,"html.parser") | python內建標準庫 執行速度適中 文件糾錯能力強 | python2.7.3以前的版本容錯能力差 |
lxml HTML解析器 | BeautifulSoup(markup,"lxml") | 速度快 文件糾錯能力強 | 需要安裝C語言庫 |
lxml xml解析器 | BeautifulSoup(markup,["lxml","xml"]) | 速度快 唯一的支援解析的xml的解析器 | 需要安裝C語言庫 |
html5lib | BeautifulSoup(markup,"html5lib") | 最好的容錯性 以瀏覽器的方式解析文件 生成html5格式的文件 | 速度慢 不宜懶外部庫 |
二、lxml解析器的基本使用
#獲取直接子節點:contents、children #獲取父節點:parent #獲取兄弟節點:next_siblings、next_sibling、previous_siblings、previous_sibling html = ''' <html> <head> <title>The Dormouse's story</title> </head> <body> <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"> <span>Elsie</span> </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> ''' from bs4 import BeautifulSoup soup=BeautifulSoup(html,'html.parser') # contents:獲取直接子節點,返回list型別 print(soup.p.contents) # children,返回的是可以迭代的,直接列印輸出None for i in soup.p.children: print(i) print(soup.p.childrensoup) #獲取 父節點 print(soup.a.parent) # 獲取兄弟節點 for i in soup.a.next_siblings:#獲取a標籤後面的所有兄弟節點 print(i)
html = ''' <html><head><title>The Dormouse's story</title></head> <body> <p class="title"><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> ''' import lxml from bs4 import BeautifulSoup #建立bs物件 bs是使用的python預設的解析器,lxml也是解析器 soup = BeautifulSoup(html,'lxml') #prettify實現格式化的輸出 print(soup.prettify()) #通過soup標籤名,獲取這個標籤的內容。注意:通過這種方式獲取標籤,如果文件中有多個這樣的標籤,返回的結果是第一個標籤內容 print(soup.a) print(soup.p) #獲取名稱name print(soup.title.name) print(soup.p.name) #獲取屬性 print(soup.a['href']) #獲取文字內容-string、text print(soup.a.string) print(soup.a.text) print(soup.title.string) print(soup.title.text) #巢狀選擇,直接通過巢狀的方式獲取 print(soup.p.b.string) print(soup.head.title.text)
三、lxml解析器標準選擇器、find_all的使用
搜尋文件樹:
(1)find_all():可以根據標籤名、屬性、內容查詢文件
(2)find():返回匹配結果的第一個元素
(3)find_parents() find_parent()
(4)find_next_siblings() find_next_sibling()
(5)find_previous_siblings() find_previous_sibling()
(6)find_all_next() find_next()
(7)find_all_previous() 和 find_previous()
html='''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all('ul'))
print(type(soup.find_all('ul')[0]))
html='''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="panel-body" id="list-2">
<li class="element">年後中好說歹說開發,什麼才能傷風膠囊</li>
<li class="element">Bar</li>
</ul>
<a href="link1.html">first item</a>
<a href="link2.html">second item</a>
<li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup=BeautifulSoup(html,"lxml")
import re
# 1、name引數
# 查詢所有名字為name的tag,搜尋 name 引數的值可以使任一型別的 過濾器 ,字元竄,正則表示式,列表,方法或是 True
print(soup.find_all('li'))
# 使用列表
print(soup.find_all(['li','a']))
print(soup.find_all(True))
print(soup.find_all(re.compile('h4')))
# 2、keyword關鍵字引數
# 關鍵字是指tag的屬性:id、title、href等,注意:使用class時要加上'_'
print(soup.find_all('a',href="link1.html"))
print(soup.find_all(id="list-1"))
print(soup.find_all('ul',class_="list"))
# 使用正則
print(soup.find_all(href=re.compile('3.html')))
# 3、text
# 一般與name一起使用,通過 text 引數可以搜搜文件中的字串內容.與 name 引數的可選值一樣, text 引數接受 字串 , 正則表示式 , 列表, True
print(soup.find_all(text=re.compile('好')))
print(soup.find_all('li',text=re.compile('好')))
# 使用多個屬性
print(soup.find_all(class_="panel-body",id="list-2"))
# 3、string
# 一般與name一起使用,通過 string 引數可以搜搜文件中的字串內容.與 name 引數的可選值一樣, string 引數接受 字串 , 正則表示式 , 列表, True;
print(soup.find_all("a", string="first item"))
print(soup.find_all(string="first item"))
# 4、limit引數
# 這個引數其實就是控制我們獲取資料的數量,效果和SQL語句中的limit一樣;
print(soup.find_all("a",limit=2))
# 5、recursive引數
# 呼叫tag的 find_all() 方法時,Beautiful Soup會檢索當前tag的所有子孫節點,如果只想搜尋tag的直接子節點,可以使用引數 recursive=False;
四、CSS選擇器
# select()直接傳入CSS選擇器完成選擇
# .表示class ,#表示id
# 標籤1,標籤2
# 標籤1 標籤2
# [attr]可以通過這種方式找到具有某個屬性值的所有標籤
# [attr=value]例子:[target=blank]
html='''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup=BeautifulSoup(html,"lxml")
# 找到class屬性是panel的標籤內的class屬性是panel-heading的標籤內容
print(soup.select(".panel .panel-heading"))
# 找id屬性為list-1和id屬性為list-2的所有標籤
print(soup.select('#list-1,#list-2'))
# 找到ul標籤下的li標籤
print(soup.select('ul li'))
# 找到id屬性值為list-2內部class屬性是element的所有標籤
print(soup.select('#list-2 .element'))
# get_text():拿到標籤文字值
# 所有li標籤下的文字值
for i in soup.select('li'):
print(i.get_text())
# 獲取屬性值
for i in soup.select('ul'):
print(i["id"])
總結:推薦使用lxml解析庫,必要時使用html.parser,標籤選擇篩選功能弱但是速度快,
建議使用find()、find_all() 查詢匹配單個結果或者多個結果
如果對CSS選擇器熟悉建議使用select()
記住常用的獲取屬性和文字值的方法