1. Beautiful Soup (bs4 )
Beautiful Soup 是一個可以從HTML或XML文件中提取數據的Python庫.它能夠通過你喜歡的轉換器實現(xiàn)慣用的文檔導航,查找,修改文檔的方式.Beautiful Soup會幫你節(jié)省數小時甚至數天的工作時間.
在測試學習使用bs4的過程中,需要反復用到xml文檔。這里就采用bs4官方文檔中提供的一個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 class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a> and
<a class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
包含一個簡單的頁面呛每。
下面使用python做簡單測試酪我。首先是格式化輸出:
# 構造BeautifulSoup 對象异赫,其中html_doc為前文的愛麗絲夢游仙境頁面
page = BeautifulSoup(html_doc, 'html.parser')
# 格式化輸出
print(page.prettify())
控制臺的輸出結果為:
<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 class="sister" id="link1">
Elsie
</a>
,
<a class="sister" id="link2">
Lacie
</a>
and
<a class="sister" id="link3">
Tillie
</a>
;
and they lived at the bottom of a well.
</p>
<p class="story">
...
</p>
</body>
</html>
顯然這是一個規(guī)范的html文件。使用起來實在是太方便了~再探索一下其他的功能吧逗扒。
bs4能夠很輕松地獲取到文檔信息,瀏覽結構化信息欠橘。例如矩肩,獲取頁面的title,只需要
page.title.name
需要注意的是肃续,如果使用CSS選擇器蛮拔,應該使用select方法述暂,如:
#查找class為sister的
print('class為sister的(CSS方式查找的):', page.select('.sister'))
#查找id為link2的
print('id為link2的(CSS方式查找的:)', page.select('#link2'))
完整的測試代碼:
# 構造BeautifulSoup 對象,其中html_doc為前文的愛麗絲夢游仙境頁面
page = BeautifulSoup(html_doc, 'html.parser')
# 格式化輸出
# print(page.prettify())
# 獲取title相關信息
print('page.title : ', page.title)
print('page.title.name : ', page.title.name)
print('page.title.text : ', page.title.text)
print('page.title.parent.name : ', page.title.parent.name)
# 獲取a標簽
print('單個a標簽:', page.a)
print('所有a標簽: ', page.find_all('a'))
# 以css的方式查找 使用select
print('class為sister的(CSS方式查找的):', page.select('.sister'))
print('id為link2的(CSS方式查找的:)', page.select('#link2'))
輸出結果為:
page.title : <title>The Dormouse's story</title>
page.title.name : title
page.title.text : The Dormouse's story
page.title.parent.name : head
單個a標簽: <a class="sister" id="link1">Elsie</a>
所有a標簽: [<a class="sister" id="link1">Elsie</a>, <a class="sister" id="link2">Lacie</a>, <a class="sister" id="link3">Tillie</a>]
class為sister的(CSS方式查找的): [<a class="sister" id="link1">Elsie</a>, <a class="sister" id="link2">Lacie</a>, <a class="sister" id="link3">Tillie</a>]
id為link2的(CSS方式查找的:) [<a class="sister" id="link2">Lacie</a>]
如果要獲取標簽中的某一部分建炫,可以使用get方法畦韭。例如:獲取頁面中所有a標簽的鏈接內容。
for line in page.find_all('a'):
print(line.get('href'))
輸出為:
http://example.com/elsie
http://example.com/lacie
http://example.com/tillie
如果要獲取頁面中所有的文字信息肛跌,只需要一行代碼:
text = page.get_text()
這是bs4一些最基礎的用法艺配。遇到問題就查一下官方文檔:bs4.4.0官方文檔
2. lxml
lxml是一個Python庫,使用它可以輕松處理XML和HTML文件衍慎,還可以用于web爬取转唉。市面上有很多現(xiàn)成的XML解析器,但是為了獲得更好的結果稳捆,開發(fā)人員有時更愿意編寫自己的XML和HTML解析器赠法。這時lxml庫就派上用場了。這個庫的主要優(yōu)點是易于使用乔夯,在解析大型文檔時速度非匙┲快,歸檔的也非常好末荐,并且提供了簡單的轉換方法來將數據轉換為Python數據類型侧纯,從而使文件操作更容易。
2.1 Xpath語言
節(jié)點:元素甲脏、屬性眶熬、文本、命名空間块请、文檔節(jié)點等娜氏。
節(jié)點關系:父、字墩新、同胞牍白、先輩、后代等抖棘。
表達式 | 描述 |
---|---|
nodename | 選此節(jié)點的所有子節(jié)點 |
// | 從任意子節(jié)點選擇 |
/ | 從根節(jié)點選擇(這里是相對的) |
. | 從當前節(jié)點選擇 |
.. | 從上一級節(jié)點選擇 |
@ | 取屬性 |
2.2 lxml的使用
首先需要導入lxml庫
from lxml import etree
from bs4_sample import html_doc
構造etree
et = etree.HTML(html_doc)
需要使用單個屬性獲取所需內容
- 變量.tag——標簽名——字符串
- 變量.attrib——節(jié)點標簽a的屬性——字典
- 變量.text——標簽文本——字符串
通過例子體會:
et = etree.HTML(html_doc)
print(et)
for tag in et:
print("TAG : ", et.tag)
for attrib in et:
print("ATTRIB : ", et.attrib)
for text in et:
print("TEXT : ", et.text)
輸出結果為:
TAG : html
TAG : html
ATTRIB : {}
ATTRIB : {}
TEXT : None
TEXT : None
也就是說茂腥,et變量實際上是這個html頁面的根節(jié)點。若執(zhí)行
print(et)
輸出的是
<Element html at 0x1a5b5135b40>
也就是html切省,也即該頁面的最外層:
測試代碼:
for i in range(len(et)):
print(et[i].tag)
輸出結果為:
head
body
觀察頁面的結構最岗,發(fā)現(xiàn)html下兩個同胞節(jié)點為head 和body。如圖:
獲取各個子節(jié)點的信息朝捆,以類似于多維數組的方式般渡,通過代碼實現(xiàn)遍歷:
for i in range(len(et)):
print(et[i].tag)
for j in range(len(et[i])):
print(" "+et[i][j].tag)
輸出結果為:
head
title
body
p
p
p
與頁面標簽結構相符。這樣就基本理解了etree.HTML(html_doc)語句所生成對象的結構。
下面來做幾件爬蟲可能需要的工作驯用。
- 檢查元素是都有子元素
- 檢查節(jié)點是都為一個elements
- 檢查一個元素是否有父元素
- 檢查同胞元素
- 尋找元素
在python代碼中依次做這些測試脸秽。比較簡單,基本方法總結見表:
功能 | 方法 |
---|---|
檢查是否存在子元素 | len(et)>0 |
檢查是否為element | etree.iselement(et[i])) |
檢查是否存在父元素 | getparent() 注意:是方法 不是getparent屬性蝴乔! |
檢查同胞元素 | getprevious()和getnext()方法 |
尋找元素 | find()方法 |
代碼比較簡單记餐,測試結果寫在注釋中:
# 1.檢查元素是都有子元素 ——檢查長度
# 1.1 檢查根節(jié)點是否有子元素
if len(et) > 0:
print("根節(jié)點有%s個子元素" % len(et))
else:
print("根節(jié)點沒有子元素!")
# 1.2檢查根節(jié)點的子節(jié)點是否有子元素
for i in range(len(et)):
if len(et[i]) > 0:
print("%s標簽有子節(jié)點薇正,第一個子節(jié)點為:%s" % (et[i].tag, et[i][0].tag))
else:
print("%s標簽沒有子節(jié)點片酝!" % et[i].tag)
# 此部分的輸出結果為:
# 根節(jié)點有2個子元素
# head標簽有子節(jié)點,第一個子節(jié)點為:title
# body標簽有子節(jié)點挖腰,第一個子節(jié)點為:p
# 2.檢查是否為elements etree.iselement(et[i]))
for i in range(len(et)):
print("%s是否為element : %s" % (et[i].tag, etree.iselement(et[i])))
# 此部分輸出結果為:
# head是否為element : True
# body是否為element : True
# 3.檢查是否存在父元素——getparent() 注意:是方法 不是getparent屬性雕沿!
print(et.getparent())
for i in range(len(et)):
if et[i].getparent():
print("%s存在父元素!" % et[i].tag)
else:
print("%s不存在父元素猴仑!" % et[i].tag)
# 此部分輸出結果:
# None
# head存在父元素审轮!
# body存在父元素!
# 4.檢查同胞——getprevious()和getnext()方法
# 代碼略
# 5.尋找元素
print(et[1].find('p'))
print(et[1].find('p').tag)
# 此部分輸出結果:
# <Element p at 0x1b688db5c40>
# p
2.3 lxml的xpath方法
取出所有的a標簽中的href鏈接:et.xpath('//a/@href')
x = et.xpath('//a/@href')
for i in range(len(x)):
print(x[i])
輸出結果為:
http://example.com/elsie
http://example.com/lacie
http://example.com/tillie