1. 程式人生 > >爬蟲網頁分析——XPath與lxml的使用

爬蟲網頁分析——XPath與lxml的使用

爬蟲網頁分析——XPath與lxml的使用

簡介:

xpath :

是一種結構化網頁元素選擇器,支援列表和單節點資料獲取,他的好處可以支援規整網頁資料抓取。

xPath helper:

是一款Chrome瀏覽器的開發者外掛,讓開發者能輕鬆獲取HTML元素的。整個抓取使用了xpath、正則表示式、訊息中介軟體、多執行緒排程框架)。我們可以用它進行xpath的實踐使用。

lxml:

lxml 是提供了一個 Pythonic API,主要的功能是如何解析和提取 HTML/XML 資料。,lxml 下面還有很多的模組,有 etree 、html 、cssselect 等眾多模組,它和BeautifulSoup之間可以相互呼叫。

我們搜尋xpath或者lxml,他們兩個總是成對出現,原因是很多時候,我們都是通過lxml將string轉為標準的html標籤格式,然後再去給xpath進行解析,所以經常一起使用

使用

XPath使用

XPath 使用路徑表示式來選取 XML 文件中的節點或者節點集。這些路徑表示式和我們在常規的電腦檔案系統中看到的表示式非常相似。

路勁查詢

路徑表示式:

表示式 描述
nodename 選取此節點的所有子節點。
/ 從根節點選取。
// 從匹配選擇的當前節點選擇文件中的節點,而不考慮它們的位置。
. 選取當前節點。
.. 選取當前節點的父節點。
@ 選取屬性。

例子:

  路徑表示式 結果
bookstore 選取 bookstore 元素的所有子節點。  
/bookstore 選取根元素 bookstore。註釋:假如路徑起始於正斜槓( / ),則此路徑始終代表到某元素的絕對路徑!  
bookstore/book 選取屬於 bookstore 的子元素的所有 book 元素。  
//book 選取所有 book 子元素,而不管它們在文件中的位置。  
bookstore//book 選擇屬於 bookstore 元素的後代的所有 book 元素,而不管它們位於 bookstore 之下的什麼位置。  
//@lang 選取名為 lang 的所有屬性。  

謂語(Predicates)

謂語用來查詢某個特定的節點或者包含某個指定的值的節點,被嵌在方括號中。

路徑表示式 結果
/bookstore/book[1] 選取屬於 bookstore 子元素的第一個 book 元素。
/bookstore/book[last()] 選取屬於 bookstore 子元素的最後一個 book 元素。
/bookstore/book[last()-1] 選取屬於 bookstore 子元素的倒數第二個 book 元素。
/bookstore/book[position()<3] 選取最前面的兩個屬於 bookstore 元素的子元素的 book 元素。
//title[@lang] 選取所有擁有名為 lang 的屬性的 title 元素。
//title[@lang=’eng’] 選取所有 title 元素,且這些元素擁有值為 eng 的 lang 屬性。
/bookstore/book[price>35.00] 選取 bookstore 元素的所有 book 元素,且其中的 price 元素的值須大於 35.00。
/bookstore/book[price>35.00]/title 選取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值須大於 35.00。

選取節點

萬用字元 描述
* 匹配任何元素節點。
@* 匹配任何屬性節點。
node() 匹配任何型別的節點。

例子:

路徑表示式 結果
/bookstore/* 選取 bookstore 元素的所有子元素。
//* 選取文件中的所有元素。
//title[@*] 選取所有帶有屬性的 title 元素。

選取若干路徑

使用“|”運算子,可以選取若干個路徑。

路徑表示式 結果
//book/title | //book/price 選取 book 元素的所有 title 和 price 元素。
//title | //price 選取文件中的所有 title 和 price 元素。
/bookstore/book/title | //price 選取屬於 bookstore 元素的 book 元素的所有 title 元素,以及文件中所有的 price 元素。

XPath的運算子

 

實戰示例


簡單使用

from lxml import etree
​
text = '''<html>
​
    <div class="large" id="content">
​
        <span>A line of text</span><br/>
​
        <span><a href="http://google.com">A link</a></span>
​
    </div>
​
    <div class="short" id="footer">
​
    </div>
</html>
'''
​
html = etree.HTML(text)
#result1 = etree.tostring(html)
#print(result1)
​
#(1)提取class屬性值為large的div標籤中的id屬性值
print("id屬性值:",html.xpath('//div[@class="large"]/@id')[0])
​
#(2)提取第一個span標籤中的文字資訊
print("第一個span標籤中的文字資訊:",html.xpath('//span/text()')[0])
​
#(3)提取第二個span標籤中的連結
print("第二個span標籤中的連結:",html.xpath('//span/a/@href')[0])
​

常用操作

1、text()中包含某個欄位

//a[contains(text(),"聯絡")]

2、多條件的篩選

選取a標籤下text包含“聯絡”和“昆明”欄位的a標籤

//a [contains(text(),"聯絡") and contains(text(),"昆明")]

找去a標籤下text包含“聯絡”和“昆明”欄位並且title屬性中包含化妝的a標籤

//a[contains(text(),"聯絡") and contains(text(),"昆明") and contains(@title,"化妝")]

注意:

xpath = response.xpath('//span[@class="total"]/text()').extract()

通過xpath得到的資料是一個selector的陣列:

<Selector xpath='//span[@class="total"]/text()' data='共50頁'>]

通過.extract之後才能拿到比較正式的資料

['共50頁']

 

 

 

 

lxml使用

lxml匯入html文件內容

能將字串或流讀進來解析成 ElementTree ,又能將 ElementTree 轉換為字串或流。

  • etree.fromstring( string )

    將 string 解析為 Element 或者 ElementTree 。

  • etree.parse( file )

    將檔案或者是 file_like 物件解析為 ElementTree (not an Element object)

  • etree.tostring(text)

    按字串序列化HTML文件

Element屬性操作

屬性簡介:

ag:元素的名稱

.attrib:一個包含元素屬性的字典,key 是屬性名,value 是對應的值。

.text:Element 的文字均為直接子文字,不包含子元素中的文字,這其中又包含兩部分 .text 和 .tail 。.text 是第一個子元素標籤之前的,如果沒有則為 None 。

.tail:.tail 為 Element 的關閉標籤之後的文字,並且是在下一個兄弟子標籤之前的部分。沒有則為 None 。

屬性操作方法:

append( child )

新增一個新的子節點(可以是 Element 、Comment)到當前 Element 中。

insert( index, elt)

將子元素 elt 插入到指定位置,這個 index 的隨意性比較大,如果是正數但是超過了最大值,那麼 lxml 會直接將這個元素插到末尾,如果是負數,但是這個負數所指位置不存在,那麼就插到末尾,這個負數的位置計算規則和列表的那個不太一樣,不知道正確的規律是什麼,但是經過測試,-n所插的位置,後面有 n (以變化前計算)個元素。如果對 Element 中的子元素執行 insert() 操作,那麼子元素位置會按 index 指定的變換。

clear()

呼叫該函式,將移除所有內容 .attrib 將被移除 .text 和 .tail 將被設定為 None 所有的子節點將被刪除。

remove( child )

將子節點 child 從Element 中移除 ,如果child 不是 Element 的子節點,將會引發 ValueError 異常。

find( path )

從 Element 的子元素及後代元素中查詢第一個符合 path 的 subelement 。如果沒有返回 None 。

ElementPath 是 ElementTree 自帶的一個 XPath-like 的路徑語言,和 XPath 差不太多,主要區別是 ElementPath 能用 {namespace}tag,但是 ElementPath 不能使用值比較和函式。

findall( path )

返回一個匹配的 Element 的列表。

findtext( path, default=None )

返回第一個匹配元素的 .text 內容,如果存在匹配,但是沒有 .text 內容,那麼將返回一個空字串,如果沒有一個匹配的元素,那麼將會返回一個 None ,但是有 default 引數,返回 default 所指定的。

get( key, default=None )

返回字串形式的 屬性 key 的值,沒有返回 None 或者 default 指定的。

getchildren()

返回一個包含 Element 子元素的列表。

getiterator( tag=None, *tags )

返回元素的一個生成器,返回元素類別取決於引數 tag ,生成順序是in document order (depth first pre-order) 深度優先的先根遍歷。如果沒有引數的話,則第一個就是元素本身。如果想使用一個高效的生成器,可以使用 .iter() 。

getroottree()

返回該元素的 ElementTree 。

iter( tag=None, *tags )

過濾特定標籤,生成迭代器。預設情況下,iter() 迭代所有的節點,包括PI(處理指令) 、Comment(註釋) 等,如果只想迭代標籤元素,可以使用 Element factory 做引數e.iter(tag = etree.Element)

iterfind( path )

迭代所有匹配 ElementPath 的 Element 。

itertext( tag=None, *tags, with_tail=True )

迭代 Element 元素的文字內容,with_tail 引數決定是否迭代子元素的 tail 。Element 的tail 不會進行迭代。

iterancestors( tag=None )

如果忽略引數,那麼將會迭代所有先輩,加標籤名可以只迭代該標籤先輩。

iterchildren( reversed=False, tag=None )

通過設定 reversed=True 可以以反向的順序迭代子元素。

itersiblings( preceding=False )

迭代 Element 之後的兄弟元素,可以通過設定 preceding=True 僅迭代 Element 之前的兄弟元素。

iterdescendants( tag=None )

同 iterancestors()

items()

返回由元素屬性的鍵值所構成的( name, value)元組的列表。

keys()

返回一個沒有特定順序的元素屬性名的列表。

set(A, V)

建立或者改變屬性 A 的值為 V。

xpath()

實戰:

將string轉為html

# 使用 lxml 的 etree 庫
from lxml import etree 
​
text = '''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a> # 注意,此處缺少一個 </li> 閉合標籤
     </ul>
 </div>
'''
​
#利用etree.HTML,將字串解析為HTML文件
html = etree.HTML(text) 
​
# 按字串序列化HTML文件
result = etree.tostring(html) 
​
print(result)