Python - 爬蟲之數據提取

歡迎關注微信公衆號:FSA全棧行動 👋html

1、概述

一、響應內容的分類

  • 結構化的響應內容
    • json 字符串:可使用 re、json、jsonpath 等模塊來提取特定數據
    • xml 字符串:可使用 re、lxml 等模塊來提取特定數據
  • 非結構化的響應內容
    • html 字符串:可使用 re、lxml、Beautiful Soup、pyquery 等模塊來提取特定數據

注意:re 模塊須要掌握正則語法,lxml 模塊須要掌握 xpath 語法。node

二、xml 與 html 的區別

數據格式 描述 設計目標
XML EXtensible Markup Language(可擴展標記語言) 被設計爲傳輸和存儲數據,其焦點是數據的結構
HTML HyperText Markup Language(超文本標記語言) 顯示數據以及如何更好顯示數據

2、jsonpath 模塊【瞭解】

一、介紹

  • 場景:多層嵌套的複雜字典直接提取數據
  • 安裝:pip install jsonpath
  • 使用:
from jsonpath import jsonpath
ret = jsonpath(data, 'jsonpath語法規則字符串')
複製代碼

注意:data 類型是字典,ret 類型是列表python

二、jsonpath 語法規則

經常使用核心語法web

JSONPath 描述
$ 根節點
. or [] 取子節點
.. 內部任意位置,取子孫節點

完整語法說明:kubernetes.io/zh/docs/ref…chrome

from jsonpath import jsonpath

data = {'key1': {'key2': {'key3': {'key4': {'key5': {'key6': 'lqr'}}}}}}

# print(data['key1']['key2']['key3']['key4']['key5']['key6'])

# jsonpath的結果爲列表,獲取數據須要索引
print(jsonpath(data, '$.key1.key2.key3.key4.key5.key6')[0])
print(jsonpath(data, '$..key6')[0])
複製代碼

3、lxml 模塊【重點】

一、介紹

  • lxml 模塊:能夠利用 XPath 規則語法,快速定位 HTML/XML 文檔中的元素以及獲取節點信息(文本內容、屬性值)
  • XPath:是一門對 HTML/XML 文檔中查找信息的語言,可用來在 HTML/XML 文檔中對元素和屬性進行遍歷
  • 關係:提取 xml、html 中的數據須要 lxml 模塊和 xpath 語法配合使用

二、xpath 語法

完整語法說明:www.w3school.com.cn/xpath/index…json

1)xpath 定位節點以及提取屬性或文本內容語法

nodename 選取此節點的全部子節點。
/ 從根節點選取。
// 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。
. 選取當前節點。
.. 選取當前節點的父節點。
@ 選取屬性。
text() 選取文本。

舉例:微信

<!-------選取title標籤-------->
html/head/title	絕對路徑
html//title		相對路徑
//title			相對於整個html文檔
//title/.		當前節點
//title/./../..	父節點

<!-------從開閉標籤之間取文本內容-------->
//title/text()

<!-------從選中的節點標籤中獲取指定屬性的值-------->
//link/@href
複製代碼

安利:Chrome 插件【xmlpath-helper】:chrome.google.com/webstore/de…markdown

2)xpath 選取特定節點語法

路徑表達式 結果
//title[@lang="eng"] 選擇 lang 屬性值爲 eng 的全部 title 元素
/bookstore/book[1] 選取屬於 bookstore 子元素的第一個 book 元素
/bookstore/book[last] 選取屬於 bookstore 子元素的最後一個 book 元素
/bookstore/book[last()-1] 選取屬於 bookstore 子元素的倒數第二個 book 元素
/bookstore/book[position()>1] 選擇 bookstore 下面的 book 元素,從第二個開始選擇
//book/title[text()='Harry Potter'] 選擇全部 book 下的 title 元素,僅僅選擇文本爲 Harry Potter 的 title 元素
/bookstore/book[price>35.00]/title 選取 bookstore 元素中的 book 元素的全部 title 元素,且其中的 price 子元素的值須大於 35.00

注意:在 xpath 中,第一個元素的位置是 1;最後一個元素的位置是 last();倒數第二個是 last()-1。函數

舉例:oop

<!-------經過索引修飾節點-------->
/html/body/div[3]/div/div[1]/div
/html/body/div[3]/div/div[1]/div[3]
/html/body/div[3]/div/div[1]/div[last()]		選中最後一個
/html/body/div[3]/div/div[1]/div[last()-1]		選中倒數第二個
/html/body/div[3]/div/div[1]/div[position()>=10] 範圍選擇

<!-------經過屬性修飾節點-------->
//div[@id="content-left"]/div/@id	出如今[]中的@是使用標籤屬性名和屬性值修飾節點,出如今結尾的/@是取屬性值

<!-------經過子節點修飾節點-------->
//span[i>2000]
//div[span[2]>=9.4]

<!-------經過包含修飾節點-------->
//div[contains(@id, "qiushi_tag_")]
複製代碼

3)xpath 選取未知節點語法

能夠經過通配符來選取未知的 html、xml 的元素

通配符 描述
* 匹配任何元素節點。
@* 匹配任何屬性節點。
node() 匹配任何類型的節點。

補充:經過在路徑表達式中使用"|"運算符,能夠選取若干個路徑。

舉例:

/bookstore/*	選取 bookstore 元素的全部子元素。
//*				選取文檔中的全部元素。
//title[@*]		選取全部帶有屬性的 title 元素

//h2/a|//td/a	xpath複合使用語法
複製代碼

三、lxml 模塊的使用

1)導入 lxml 的 etree 庫

from lxml import etree

# 若是上面導入代碼報錯,能夠改用下面的導入代碼
from lxml import html
etree = html.etree
複製代碼

注意:from lxml import etree 提示報錯的話,其實不會影響代碼的運行,只是看着有點彆扭。

2)使用 etree.HTML 轉化 Element 對象

利用 etree.HTML 將 html 字符串(bytes 類型或 str 類型)轉化爲 Element 對象,Element 對象具備 xpath 方法,返回結果的列表:

html = etree.HTML(text)
ret_list = html.xpath('xpath語法規則字符串')
複製代碼

3)xpath 方法返回列表的三種狀況

  • 空列表:沒有定位到任何元素
  • 字符串列表:匹配到了文本內容或某屬性的值
  • Element 列表:匹配到符合條件的標籤,列表中的 Element 對象能夠繼續進行 xpath

舉例:

from lxml import etree

text = """ <div> <ul> <li class="item-1"><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> """

html = etree.HTML(text)
#print(html)

print(html.xpath('//a[@href="link1.html"]/text()'))
print(html.xpath('//a[@href="link1.html"]/text()')[0])

# 字符串列表
text_list = html.xpath('//a/text()')
link_list = html.xpath('//a/@href')
# for text in text_list:
# myindex = text_list.index(text)
# link = link_list[myindex]
# print(text, link)
for text, link in zip(text_list, link_list):
    print(text, link)

# Element列表
el_list = html.xpath('//a')
for el in el_list:
    print(el.xpath('//text()'))  # ×://開頭是相對整個文檔的
    print(el.xpath('./text()'))  # √
    print(el.xpath('.//text()'))  # √
    print(el.xpath('text()'))  # √
複製代碼

4)etree.tostring 函數的使用

etree.tostring 函數能夠將 Element 對象轉化回 html 字符串:

from lxml import etree

text = """ <div> <ul> <li class="item-1"><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> """

html = etree.HTML(text)

html_str = etree.tostring(html).decode()
print(html_str)
複製代碼

注意:轉化後,可能會多出來一些標籤,好比本來沒有的<body><html>,這是由於 etree.HTML(text) 會自動補全原 html 中的語法錯誤。

若是文章對您有所幫助, 請不吝點擊關注一下個人微信公衆號:FSA全棧行動, 這將是對我最大的激勵. 公衆號不只有Android技術, 還有iOS, Python等文章, 可能有你想要了解的技能知識點哦~

相關文章
相關標籤/搜索