本篇內(nèi)容主要講解“l(fā)xml與pyquery解析html的方法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“l(fā)xml與pyquery解析html的方法”吧!
創(chuàng)新互聯(lián)制作網(wǎng)站網(wǎng)頁找三站合一網(wǎng)站制作公司,專注于網(wǎng)頁設(shè)計,做網(wǎng)站、成都做網(wǎng)站,網(wǎng)站設(shè)計,企業(yè)網(wǎng)站搭建,網(wǎng)站開發(fā),建網(wǎng)站業(yè)務,680元做網(wǎng)站,已為上1000+服務,創(chuàng)新互聯(lián)網(wǎng)站建設(shè)將一如既往的為我們的客戶提供最優(yōu)質(zhì)的網(wǎng)站建設(shè)、網(wǎng)絡營銷推廣服務!
首先來了解一下lxml,很多常用的解析html的庫都用到了lxml這個庫,例如BeautifulSoup、pyquery。
下面我們介紹一下lxml關(guān)于html解析的3個Element。
from lxml import etree text = ''' <div> <ul> <li class="item-0"><a href="link1.html">first</a></li> <li class="item-1"><a href="link2.html">second</a></li> <li class="item-0"><a href="link3.html">third</a></li> </ul> </div> ''' # lxml.etree._Element element = etree.HTML(text)
# 通過css選擇器獲取節(jié)點 cssselect(expr) # 通過標簽或者xpath語法獲取第一個匹配 find(path) # 通過標簽或者xpath語法獲取所有匹配 findall(path) # 獲取屬性值 get(key) # 獲取所有屬性 items() # 獲取所有屬性名稱 keys() # 獲取所有屬性值 values() # 獲取子節(jié)點 getchildren() # 獲取父節(jié)點 getparent() # 獲取相鄰的下一個節(jié)點 getnext() # 獲取相鄰的上一個節(jié)點 getprevious() # 迭代節(jié)點 iter(tag) # 通過xpath表達式獲取節(jié)點 xpath(path)
from lxml import etree text = ''' <div> <ul> <li class="item-0"><a href="link1.html">first</a></li> <li class="item-1"><a href="link2.html">second</a></li> <li class="item-0" rel="third"><a href="link3.html">third</a></li> </ul> </div> ''' element = etree.HTML(text) # css選擇器,獲取class為item-0的li節(jié)點 lis = element.cssselect("li.item-0") for li in lis: # 獲取class屬性 print(li.get("class")) # 獲取屬性名稱和值,元組列表 print(li.items()) # 獲取節(jié)點所有的屬性名稱 print(li.keys()) # 獲取所有屬性值 print(li.values()) print("--------------") ass = element.cssselect("li a") for a in ass: # 獲取文本節(jié)點 print(a.text) print("--------------") # 獲取第一個li節(jié)點 li = element.find("li") # 獲取所有l(wèi)i節(jié)點 lis = element.find("li") # 獲取所有的a節(jié)點 lias = element.iter("a") for lia in lias: print(lia.get("href")) textStr = element.itertext("a") for ts in textStr: print(ts)
xpath我們后面單獨介紹。
from io import StringIO from lxml import etree text = ''' <div> <ul> <li class="item-0"><a href="link1.html">first</a></li> <li class="item-1"><a href="link2.html">second</a></li> <li class="item-0"><a href="link3.html">third</a></li> </ul> </div> ''' parser = etree.HTMLParser() # lxml.etree._ElementTree elementTree = etree.parse(StringIO(text), parser) # 可以直接從文件讀取 # elementTree = etree.parse(r'F:\tmp\etree.html',parser)
find(path) findall(path) iter(tag) xpath(path)
_ElementTree方法和 _Element的同名方法使用基本一樣。
有很多不同的是_ElementTree的find和findall方法只接受xpath表達式。
from io import StringIO from lxml import etree text = ''' <div> <ul> <li class="item-0"><a href="link1.html">first</a></li> <li class="item-1"><a href="link2.html">second</a></li> <li class="item-0"><a href="link3.html">third</a></li> </ul> </div> ''' parser = etree.HTMLParser() elementTree = etree.parse(StringIO(text), parser) lis = elementTree.iter("li") for li in lis: print(type(li)) print("---------") firstLi = elementTree.find("//li") print(type(firstLi)) print(firstLi.get("class")) print("---------") ass = elementTree.findall("//li/a") for a in ass: print(a.text)
import lxml.html text = ''' <div> <ul> <li class="item-0"><a href="link1.html">first</a></li> <li class="item-1"><a href="link2.html">second</a></li> <li class="item-0"><a href="link3.html">third</a> </ul> </div> ''' # lxml.html.HtmlElement htmlElement = lxml.html.fromstring(text)
HtmlElement繼承了etree.ElementBase和HtmlMixin,etree.ElementBase繼承了_Element。
因為HtmlElement繼承了_Element,所以_Element中介紹的方法,HtmlElement都可以使用。 HtmlElement還可以使用HtmlMixin中的方法。
# 通過類名獲取節(jié)點 find_class(class_name) # 通過id獲取節(jié)點 get_element_by_id(id) # 獲取文本節(jié)點 text_content() # 通過css選擇器獲取節(jié)點 cssselect(expr)
xpath功能非常強大,并且_Element、_ElementTree、HtmlElement都可以使用xpath表達式,所以最后介紹一下xpath。
表達式 | 描述 |
---|---|
/ | 從根節(jié)點開始,絕對路徑 |
// | 從當前節(jié)點選取子孫節(jié)點,相對路徑,不關(guān)心位置 |
. | 選取當前節(jié)點 |
.. | 選取當前節(jié)點的父節(jié)點 |
@ | 選取屬性 |
* | 通配符,選擇所有元素節(jié)點與元素名 |
@* | 選取所有屬性 |
[@attrib] | 選取具有給定屬性的所有元素 |
[@attrib='value'] | 選取給定屬性具有給定值的所有元素 |
[tag] | 選取所有具有指定元素的直接子節(jié)點 |
[tag='text'] | 選取所有具有指定元素并且文本內(nèi)容是text節(jié)點 |
expression | 表達式 | 描述 |
---|---|---|
ancestor | xpath('./ancestor:: *') | 選取當前節(jié)點的所有先輩節(jié)點 |
ancestor-or-self | ('./ancestor-or-self:: *') | 選取當前節(jié)點的所有先輩以及節(jié)點本身 |
attribute | xpath('./attribute:: *') | 選取當前節(jié)點的所有屬性 |
child | xpath('./child:: *') | 返回當前節(jié)點的所有子節(jié)點 |
descendant | xpath('./descendant:: *') | 返回當前節(jié)點的所有后代節(jié)點(子節(jié)點、孫節(jié)點) |
following | xpath('./following:: *') | 選取文檔中當前節(jié)點結(jié)束標簽后的所有節(jié)點 |
following-sibing | xpath('./following-sibing:: *') | 選取當前節(jié)點之后的兄弟節(jié)點 |
parent | xpath('./parent:: *') | 選取當前節(jié)點的父節(jié)點 |
preceding | xpath('./preceding:: *') | 選取文檔中當前節(jié)點開始標簽前的所有節(jié)點 |
preceding-sibling | xpath('./preceding-sibling:: *') | 選取當前節(jié)點之前的兄弟節(jié)點 |
self | xpath('./self:: *') | 選取當前節(jié)點 |
很多時候我們可以通過瀏覽器獲取xpath表達式:
from lxml.html.clean import Cleaner from lxml import etree text = ''' <div> <ul> <li class="item-0" rel="li1"><a href="link1.html">first</a></li> <li class="item-1" rel="li2"><a href="link2.html" rel="attrRel">second</a></li> <li class="item-0" rel="li3"><a href="link3.html" id="thirda">third</a> </ul> </div> ''' # 去除css、script cleaner = Cleaner(style=True, scripts=True, page_structure=False, safe_attrs_only=False) print(cleaner.clean_html(text)) # _Element element = etree.HTML(text) # 文本節(jié)點,特殊字符轉(zhuǎn)義 print(element.xpath('//text()')) # 文本節(jié)點,不轉(zhuǎn)義 print(element.xpath('string()')) # find、findall只能使用相對路徑,以.//開頭 print(element.findall('.//a[@rel]')) print(element.find('.//a[@rel]')) # 獲取包含rel屬性的a節(jié)點 print(element.xpath('//a[@rel]')) # 獲取ul元素下的第一個li節(jié)點,注意是列表,因為ul可能有多個 print(element.xpath("//ul/li[1]")) # 獲取ul元素下rel屬性為li2的li節(jié)點 print(element.xpath("//ul/li[@rel='li2']")) # 獲取ul元素下的倒數(shù)第2個節(jié)點 print(element.xpath("//ul/li[last()-1]")) # 獲取ul元素下的前2個li節(jié)點 print(element.xpath("//ul/li[position()<3]")) # 獲取li元素下的所有a節(jié)點 for a in element.xpath("//li/a"): print(a.text) print(a.get("href")) # 獲取父節(jié)點,列表,因為可能匹配多個a print(element.xpath('//a[@href="link2.html"]/parent::*')) # 獲取的是文本節(jié)點對象列表 print(element.xpath('//li[@class="item-1"]/a/text()')) print("---------------") # 獲取a的href屬性 print(element.xpath('//li/a/@href')) # 獲取所有l(wèi)i子孫節(jié)點的href屬性 print(element.xpath('//li//@href'))
from lxml import etree text = ''' <li class="subject-item"> <div class="pic"> <a class="nbg" href="https://book.douban.com/subject/25862578/"> <img class="" src="https://img3.doubanio.com/view/subject/m/public/s27264181.jpg" width="90"> </a> </div> <div class="info"> <h3 class=""><a href="https://book.douban.com/subject/25862578/" title="解憂雜貨店">解憂雜貨店</a></h3> <div class="pub">[日] 東野圭吾 / 李盈春 / 南海出版公司 / 2014-5 / 39.50元</div> <div class="star clearfix"> <span class="allstar45"></span> <span class="rating_nums">8.5</span> <span class="pl"> (537322人評價) </span> </div> <p>現(xiàn)代人內(nèi)心流失的東西,這家雜貨店能幫你找回——僻靜的街道旁有一家雜貨店,只要寫下煩惱投進卷簾門的投信口,第二天就會在店后的牛奶箱里得到回答。因男友身患絕... </p> </div> </li> ''' element = etree.HTML(text) # 查找符合xpath(//li/div/a)的節(jié)點 aeles = element.xpath("//li/div/a") for aele in aeles: # 獲取href屬性 print(aele.get("href")) # 查找img標簽,并且獲取src屬性 print(aele.find("img").get("src")) # 返回列表的原因是:雖然我們只取了第一個a節(jié)點,但是上級xpath(//li/div[@class='info']/h3)可能匹配多個 for a in element.xpath("//li/div[@class='info']/h3/a[1]"): print(a.get("href")) print(a.text) # print(a.get("title")) # 指定div的class屬性 for pu in element.xpath("//li/div[@class='info']/div[@class='pub']"): print(pu.text) # 使用到contains函數(shù)和or運算符 spans = element.xpath("//li/div[@class='info']/div[@class='star clearfix']/span[contains(@class,'rating_nums') or " "contains(@class,'pl')]") for span in spans: print(span.text.strip()) for content in element.xpath("//li/div[@class='info']/p"): print(content.text) # 如果確定只有一個或者只需要第一個可以使用find,注意find使用xpath為參數(shù)的時候使用相對路徑(.//開頭) print(element.find(".//li/div[@class='info']/p").text)
從字符串:
from pyquery import PyQuery as pq html = '' with open(r"F:\tmp\db.html", "r", encoding='utf-8') as f: html = f.read() doc = pq(html)
從URL:
from pyquery import PyQuery as pq headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0' } doc = pq('https://book.douban.com/tag/小說', headers=headers)
從文件:
from pyquery import PyQuery as pq doc = pq(filename=r"F:\tmp\db.html")
從文件有一個問題就是不能指定文件編碼,所以一般都是自己讀取文件,然后從字符串構(gòu)造。
pyquery最強大的地方就在于,它可以像jQuery使用css選擇器一樣獲取節(jié)點。
常用的一些選擇器:
id選擇器(#id) 類選擇器(.class) 屬性選擇器(a[href="xxx"]) 偽類選擇器(:first :last :even :odd :eq :lt :gt :checked :selected)
前面我們已經(jīng)知道怎樣構(gòu)造一個PyQuery,上面我們有知道了怎么通過選擇器獲取節(jié)點,下面我們通過一個小示例來具體了解一下。
from pyquery import PyQuery as pq html = ''' <!DOCTYPE html> <html> <head> <title>pyquery</title> </head> <body> <ul id="container"> <li class="li1">li1</li> <li class="li2">li2</li> <li class="li3" data-type='3'>li3</li> </ul> </body> </html> ''' doc = pq(html) # id選擇器,outerHtml輸出整體的html print(doc("#container").outerHtml()) print("----------") # 類選擇器 print(doc(".li1").outerHtml()) print("----------") # 偽類選擇器 # 選擇第2個li節(jié)點,并通過text獲取該li節(jié)點的值 print(doc('li:nth-child(2)').text()) # 獲取第1個li節(jié)點 print(doc('li:first-child').text()) # 獲取最后一個li節(jié)點,并通過attr獲取該節(jié)點的data-type屬性值 print(doc('li:last-child').attr("data-type")) print(doc("li:contains('li3')").attr("data-type")) print("----------") # 屬性選擇器 # 選擇li的data-type的屬性值為3的節(jié)點 print(doc("li[data-type='3']").outerHtml())
首先我們通過html字符串構(gòu)造了一個PyQuery對象,然后就可以通過選擇器愉快的獲取我們想要的節(jié)點了。
注意:上面的text方法是獲取節(jié)點的文本,attr是獲取節(jié)點的屬性,非常常用
這里就補貼輸出代碼了,如果感興趣可以自己動手嘗試一下,看一下輸出。
很多時候,我們并不能直接通過選擇器一步到位的獲取到我們需要的節(jié)點,所以我們需要另外一些查找、過濾、遍歷節(jié)點的方法,例如:find、filter、eq、not_、items、each等,下面我們還是通過一個小例子來介紹一下這些方法。
from pyquery import PyQuery as pq html = ''' <!DOCTYPE html> <html> <head> <title>pyquery</title> </head> <body> <ul id="container"> <li class="li1">li1</li> <li class="li2">li2</li> <li class="li3" data-type='3'>li3</li> </ul> </body> </html> ''' doc = pq(html) # find的語法和直接使用選擇器一樣 print("---find:") print(doc.find("li").show()) # 輸出li的個數(shù) print(doc.find("li").size()) # filter過濾得到滿足條件的 print("---filter:") print(doc.find("li").filter(".li3").show()) # eq選擇第n個,下標從0開始 print("---eq:") print(doc.find("li").eq(1).show()) # not_排除滿足條件的節(jié)點 print("---not_:") print(doc.find("li").not_("li[data-type='3']").show()) lis = doc.find("li") # 輸出PyQuery print(type(lis)) # each輸出的類型是lxml.etree._Element print("---each:") lis.each(lambda i, e: print(type(e))) print("---for:") for li in lis: print(type(li)) # items獲取到的類型才是PyQuery print("---items:") for li in lis.items(): print(type(li))
這些方法還是比較基礎(chǔ)的,看代碼中的注釋就能知道是什么意思了,如果有疑問,可以自己動手調(diào)試一下。
注意lis是PyQuery類型,PyQuery的each是lxml.etree._Element類型,items才是PyQuery
這意味著使用for\each循環(huán)不能使用PyQuery的find、filter、text、attr這些方法。
需要使用lxml.etree._Element的方法。
到此,相信大家對“l(fā)xml與pyquery解析html的方法”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!
本文名稱:lxml與pyquery解析html的方法
本文來源:http://www.rwnh.cn/article24/jgjgje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護、做網(wǎng)站、云服務器、虛擬主機、域名注冊、動態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)