多表格合并一起
1024
2022-05-30
lxml庫
lxml是Python的一個解析庫,專門用于解析XML與HTML,支持XPath解析方式。由于lxml庫的底層是使用C語言編寫的,所以其解析效率非常的高。
在我們后面講解使用該庫之前,我們需要安裝該庫。一般通過如下命令進行安裝即可,代碼如下:
pip install lxml
lxml基本用法
既然,lxml庫支持解析XML以及HTML,那么肯定就需要學會這2種文檔的解析方式。下面,我們來分別講解。
解析XML文件
首先,我們需要使用lxml庫解析XML文件,這里XML文件其實有很多種類,這里博主隨便定義一個XML進行解析。
XML代碼如下:
解析示例代碼如下所示:
from lxml import etree tree = etree.parse("lxml_xml.xml") print(str(etree.tostring(tree, encoding='utf-8'), 'utf-8')) root = tree.getroot() print("根節點", root.tag) children = root.getchildren() for child in children: print("sex:", child[0].text) print("class :", child.get('class'))
運行之后,效果如下所示:
解析HTML文件
解析HTML比XML稍微復雜一點,它需要創建一個HTMLParser()對象傳入到parser()方法中,因為其默認是解析XML的。
HTML代碼如下:
解析代碼如下所示:
from lxml import etree parser = etree.HTMLParser() tree = etree.parse('demo.html', parser) root = tree.getroot() result = etree.tostring(root, encoding='UTF-8', pretty_print=True, method='html') print(root.tag) children = root.getchildren() print("語言:", children[0].get('lang')) print(root[0][1].text)
運行之后,效果如下所示:
XPath
估計細心的小伙伴,已經看出lxml庫直接使用的弊端了。因為這是小編寫的一個簡單的HTML與XML,所以它的層級很低。
如果是真實的網頁,那么可能層級會很多,如果還按數組這樣一層一層往下查找,估計能搞出個十幾維的數組。這樣太復雜了。
所以,這里我們需要引入XPath進行輔助解析。
什么是XPath
XPath于1991年11月6日稱為W3C標準,它被設計為可以在XSLT、XPointer以及其他XML解析軟件中使用,其中文文檔為:
https://www.w3school.com.cn/xpath/index.asp
XPath全稱XML Path Language,中文叫XML路徑語言,它是一種在XML文檔中查詢信息的語言。
最初雖然只支持XML文件,但是后來隨著版本的迭代,已經可以支持HTML文件的解析與搜索,因為HTML與XML同源。
XPath語法
XPath語言的基本語法就是多級目錄的層級結構,但比數組那種容易理解的多。下表是博主歸納總結的XPath語法規則:
XPath實戰
既然,我們已經了解XPath具體的語法結構,那么我們將一一實戰這些語法,讓讀者更清晰,更快捷的掌握。
測試HTML文件如下所示:
選取某節點的所有子孫節點
假設我們需要獲取上面HTML文件中
from lxml import etree parser = etree.HTMLParser() html = etree.parse('demo.html', parser) nodes = html.xpath("http://ul//a") for index in range(0, len(nodes)): print("網址:", nodes[index].get('href'), " 文本:", nodes[index].text)
運行之后,效果如下:
雙斜杠“//”代表獲取當前節點下的子孫節點,也就是說,直接在根節點操作,就是獲取根節點下面的所有該標簽。
選取某節點的所有子節點
還是上面這個例子,我們如果使用單斜杠“/”獲取所有的標簽呢?
因為標簽是
from lxml import etree parser = etree.HTMLParser() html = etree.parse('demo.html', parser) nodes = html.xpath("http://li/a") for index in range(0, len(nodes)): print("網址:", nodes[index].get('href'), " 文本:", nodes[index].text)
如上面代碼所示,我們把xpath語法改成“//li/a”即可。運行之后,效果與上面一模一樣。
通過屬性選取某節點的父節點
對于當前節點來說,我們只需要通過其標簽與屬性確認,自然就可以獲取當前節點。所以.這里就不贅述了。
我們直接介紹后兩種語法,通過"@“查找屬性,然后通過”.."查找其父節點。
實戰,通過class等于aaa的節點獲取父親節點,然后獲取其屬性class的值。示例代碼如下所示:
from lxml import etree parser = etree.HTMLParser() html = etree.parse('demo.html', parser) nodes = html.xpath("http://a[@class='aaa']/../@class") print(nodes)
運行之后,效果如下:
除了通過/…獲取父節點之外,我們還可以通過parent::*獲取父節點。那么同樣的轉換語法也可以得到如上圖所示的結果。(把…替換成即可)
多屬性匹配
我們還是來獲取那個有class的標簽,這里使用多屬性匹配原則。
也就是,我們匹配其父節點class等于li以及class等于aaa的標簽。那么如何首先呢?示例如下:
from lxml import etree parser = etree.HTMLParser() html = etree.parse('demo.html', parser) nodes = html.xpath("http://a[contains(@class,'aaa') and ../@class='li']") print(nodes[0].text)
運行之后,效果如下:
看看上面的輸出圖,是不是最后一個標簽的文本內容?這里通過and進行多屬性條件判斷。
XPath運算符規則
不過,這里就涉及XPath運算符規則了。博主這里,也列出了一個專門的運算符規則的表格,方便讀者查閱參考。
實戰:爬取CSDN個人博文
我們先通過chrome,或者任意瀏覽器按F12打開查看CSDN個人主頁的元素,可以看到,這里的div是整個主頁內容的div。
然后,在一條一條的遍歷子div獲取里面的每篇博文信息即可。不過,我們首先需要獲取網頁的HTML文本,通過requests進行獲取。
然后,我們再來看看其標題與鏈接到底在哪里?如下圖所示:
可以看到,標題與鏈接都在每個div的
標簽中,知道了這些,我們來獲取主頁的所有博文。
示例代碼如下:
from lxml import etree import requests url = "https://blog.csdn.net/liyuanjinglyj" session = requests.session() headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9', 'cache-control': 'max-age=0', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' } result = requests.get(url, headers=headers) result.encoding = result.apparent_encoding html = etree.HTML(result.text) urlStr = html.xpath("http://div[@class='article-list']//div/h4/a/@href") titleStr = html.xpath("http://div[@class='article-list']//div/h4/a/text()") titleStr = [i for i in titleStr if i.strip() != ''] contentStr = html.xpath("http://div[@class='article-list']//div/p[@class='content']/text()") for url, title, content in zip(urlStr, titleStr, contentStr): print("博文鏈接:", url) print("博文標題:", title.strip()) print("博文描述:", content.strip())
運行之后,效果如下:
這里有一個很奇怪的問題,相信大家也發現了,我們titleStr遍歷了2遍,其他的只遍歷的一遍這是為什么呢?我們先來看一張圖:
這里獲取標簽文本的時候,默認是獲取了2個,一個是空,一個才是下面的標題。所以,這里每次獲取標簽文本標題時,都是一個空白,一個標題。
所以,我們在后續遍歷的時候,應該去除掉空白字符串。只要標題。
XPath最簡單的玩法
如果你是安裝的Chrome,那么XPath語法,你可以不必學。因為這個瀏覽器可以直接生成XPath。
比如,我們獲取上面的標簽,那么如何獲取呢?只要選中標簽,然后按住右鍵選擇Copy-Copy XPath即可。如下圖所示:
不過,博主不建議這么做。因為這里Copy的XPath僅僅只是針對當前的標簽,而我們上面獲取的標簽是一個有規則的標簽列表。而你不學習的XPath語法的話,這要是有100個列表標簽,你難道還復制XPath語法100次不成?而學習過XPath只需要一行代碼,然后遍歷即可。
HTML HTTP Python XML 爬蟲
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。