XPath語法和lxml模塊

XPath語法和lxml模塊

什么是XPath?

xpath(XML Path Language)是一門在XML和HTML文檔中查找信息的語言,可用來在XML和HTML文檔中對(duì)元素和屬性進(jìn)行遍歷。

XPath開發(fā)工具

  1. Chrome插件XPath Helper。
  2. Firefox插件Try XPath。

XPath語法

選取節(jié)點(diǎn):

XPath 使用路徑表達(dá)式來選取 XML 文檔中的節(jié)點(diǎn)或者節(jié)點(diǎn)集。這些路徑表達(dá)式和我們?cè)诔R?guī)的電腦文件系統(tǒng)中看到的表達(dá)式非常相似。

表達(dá)式 描述 示例 結(jié)果
nodename 選取此節(jié)點(diǎn)的所有子節(jié)點(diǎn) bookstore 選取bookstore下所有的子節(jié)點(diǎn)
/ 如果是在最前面,代表從根節(jié)點(diǎn)選取。否則選擇某節(jié)點(diǎn)下的某個(gè)節(jié)點(diǎn) /bookstore 選取根元素下所有的bookstore節(jié)點(diǎn)
// 從全局節(jié)點(diǎn)中選擇節(jié)點(diǎn),隨便在哪個(gè)位置 //book 從全局節(jié)點(diǎn)中找到所有的book節(jié)點(diǎn)
@ 選取某個(gè)節(jié)點(diǎn)的屬性 //book[@price] 選擇所有擁有price屬性的book節(jié)點(diǎn)
. 當(dāng)前節(jié)點(diǎn) ./a 選取當(dāng)前節(jié)點(diǎn)下的a標(biāo)簽

謂語:

謂語用來查找某個(gè)特定的節(jié)點(diǎn)或者包含某個(gè)指定的值的節(jié)點(diǎn),被嵌在方括號(hào)中。
在下面的表格中,我們列出了帶有謂語的一些路徑表達(dá)式,以及表達(dá)式的結(jié)果:

路徑表達(dá)式 描述
/bookstore/book[1] 選取bookstore下的第一個(gè)子元素
/bookstore/book[last()] 選取bookstore下的倒數(shù)第二個(gè)book元素。
bookstore/book[position()<3] 選取bookstore下前面兩個(gè)子元素。
//book[@price] 選取擁有price屬性的book元素
//book[@price=10] 選取所有屬性price等于10的book元素

通配符

*表示通配符。

通配符 描述 示例 結(jié)果
* 匹配任意節(jié)點(diǎn) /bookstore/* 選取bookstore下的所有子元素。
@* 匹配節(jié)點(diǎn)中的任何屬性 //book[@*] 選取所有帶有屬性的book元素。

選取多個(gè)路徑:

通過在路徑表達(dá)式中使用“|”運(yùn)算符,可以選取若干個(gè)路徑。
示例如下:

//bookstore/book | //book/title
# 選取所有book元素以及book元素下所有的title元素

lxml庫

lxml 是 一個(gè)HTML/XML的解析器,主要的功能是如何解析和提取 HTML/XML 數(shù)據(jù)。

lxml和正則一樣,也是用 C 實(shí)現(xiàn)的,是一款高性能的 Python HTML/XML 解析器,我們可以利用之前學(xué)習(xí)的XPath語法,來快速的定位特定元素以及節(jié)點(diǎn)信息。

lxml python 官方文檔:http://lxml.de/index.html

需要安裝C語言庫,可使用 pip 安裝:pip install lxml

基本使用:

我們可以利用他來解析HTML代碼,并且在解析HTML代碼的時(shí)候,如果HTML代碼不規(guī)范,他會(huì)自動(dòng)的進(jìn)行補(bǔ)全。示例代碼如下:

# 使用 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> # 注意,此處缺少一個(gè) </li> 閉合標(biāo)簽
     </ul>
 </div>
'''

#利用etree.HTML,將字符串解析為HTML文檔
html = etree.HTML(text) 

# 按字符串序列化HTML文檔
result = etree.tostring(html) 

print(result)

輸入結(jié)果如下:

<html><body>
<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>
</body></html>

可以看到。lxml會(huì)自動(dòng)修改HTML代碼。例子中不僅補(bǔ)全了li標(biāo)簽,還添加了body,html標(biāo)簽。

從文件中讀取html代碼:

除了直接使用字符串進(jìn)行解析,lxml還支持從文件中讀取內(nèi)容。我們新建一個(gè)hello.html文件:

<!-- hello.html -->
<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"><span class="bold">third item</span></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.parse()方法來讀取文件。示例代碼如下:

from lxml import etree

# 讀取外部文件 hello.html
html = etree.parse('hello.html')
result = etree.tostring(html, pretty_print=True)

print(result)

輸入結(jié)果和之前是相同的。

在lxml中使用XPath語法:

  1. 獲取所有l(wèi)i標(biāo)簽:

     from lxml import etree
    
     html = etree.parse('hello.html')
     print type(html)  # 顯示etree.parse() 返回類型
    
     result = html.xpath('//li')
    
     print(result)  # 打印<li>標(biāo)簽的元素集合
    
    
  2. 獲取所有l(wèi)i元素下的所有class屬性的值:

     from lxml import etree
    
     html = etree.parse('hello.html')
     result = html.xpath('//li/@class')
    
     print(result)
    
    
  3. 獲取li標(biāo)簽下href為www.baidu.com的a標(biāo)簽:

     from lxml import etree
    
     html = etree.parse('hello.html')
     result = html.xpath('//li/a[@href="www.baidu.com"]')
    
     print(result)
    
    
  4. 獲取li標(biāo)簽下所有span標(biāo)簽:

     from lxml import etree
    
     html = etree.parse('hello.html')
    
     #result = html.xpath('//li/span')
     #注意這么寫是不對(duì)的:
     #因?yàn)?/ 是用來獲取子元素的,而 <span> 并不是 <li> 的子元素,所以,要用雙斜杠
    
     result = html.xpath('//li//span')
    
     print(result)
    
    
  5. 獲取li標(biāo)簽下的a標(biāo)簽里的所有class:

     from lxml import etree
    
     html = etree.parse('hello.html')
     result = html.xpath('//li/a//@class')
    
     print(result)
    
    
  6. 獲取最后一個(gè)li的a的href屬性對(duì)應(yīng)的值:

     from lxml import etree
    
     html = etree.parse('hello.html')
    
     result = html.xpath('//li[last()]/a/@href')
     # 謂語 [last()] 可以找到最后一個(gè)元素
    
     print(result)
    
    
  7. 獲取倒數(shù)第二個(gè)li元素的內(nèi)容:

     from lxml import etree
    
     html = etree.parse('hello.html')
     result = html.xpath('//li[last()-1]/a')
    
     # text 方法可以獲取元素內(nèi)容
     print(result[0].text)
    
    
  8. 獲取倒數(shù)第二個(gè)li元素的內(nèi)容的第二種方式:

     from lxml import etree
    
     html = etree.parse('hello.html')
     result = html.xpath('//li[last()-1]/a/text()')
    
     print(result)
    
    

使用requests和xpath爬取電影天堂

示例代碼如下:

import requests
from lxml import etree

BASE_DOMAIN = 'http://www.dytt8.net'
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',
    'Referer': 'http://www.dytt8.net/html/gndy/dyzz/list_23_2.html'
}

def spider():
    url = 'http://www.dytt8.net/html/gndy/dyzz/list_23_1.html'
    resp = requests.get(url,headers=HEADERS)
    # resp.content:經(jīng)過編碼后的字符串
    # resp.text:沒有經(jīng)過編碼,也就是unicode字符串
    # text:相當(dāng)于是網(wǎng)頁中的源代碼了
    text = resp.content.decode('gbk')
    # tree:經(jīng)過lxml解析后的一個(gè)對(duì)象,以后使用這個(gè)對(duì)象的xpath方法,就可以
    # 提取一些想要的數(shù)據(jù)了
    tree = etree.HTML(text)
    # xpath/beautifulsou4
    all_a = tree.xpath("http://div[@class='co_content8']//a")
    for a in all_a:
        title = a.xpath("text()")[0]
        href = a.xpath("@href")[0]
        if href.startswith('/'):
            detail_url = BASE_DOMAIN + href
            crawl_detail(detail_url)
            break

def crawl_detail(url):
    resp = requests.get(url,headers=HEADERS)
    text = resp.content.decode('gbk')
    tree = etree.HTML(text)
    create_time = tree.xpath("http://div[@class='co_content8']/ul/text()")[0].strip()
    imgs = tree.xpath("http://div[@id='Zoom']//img/@src")
    # 電影海報(bào)
    cover = imgs[0]
    # 電影截圖
    screenshoot = imgs[1]
    # 獲取span標(biāo)簽下所有的文本
    infos = tree.xpath("http://div[@id='Zoom']//text()")
    for index,info in enumerate(infos):
        if info.startswith("◎年  代"):
            year = info.replace("◎年  代","").strip()

        if info.startswith("◎豆瓣評(píng)分"):
            douban_rating = info.replace("◎豆瓣評(píng)分",'').strip()
            print(douban_rating)

        if info.startswith("◎主  演"):
            # 從當(dāng)前位置,一直往下面遍歷
            actors = [info]
            for x in range(index+1,len(infos)):
                actor = infos[x]
                if actor.startswith("◎"):
                    break
                actors.append(actor.strip())
            print(",".join(actors))


if __name__ == '__main__':
    spider()
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ···lxml用法源自 lxml python 官方文檔,更多內(nèi)容請(qǐng)直接參閱官方文檔,本文對(duì)其進(jìn)行翻譯與整理。lx...
    小豐豐_72a2閱讀 1,101評(píng)論 0 1
  • 一、簡(jiǎn)介 XPath 是一門在 XML 文檔中查找信息的語言。XPath 可用來在 XML 文檔中對(duì)元素和屬性進(jìn)行...
    朝畫夕拾閱讀 615評(píng)論 0 1
  • 生活中總面臨著無數(shù)的選擇,我經(jīng)常問自己:我喜歡我現(xiàn)在的狀態(tài)嗎?但總有兩種回答:喜歡;因?yàn)檫@里讓我永遠(yuǎn)緊張,讓我不能...
    巫娜萌主閱讀 169評(píng)論 0 0
  • 大家好,我是雨落偏安。新的一年,祝大家步步高升,愿想事成。 已經(jīng)有好長(zhǎng)一段時(shí)間沒有在簡(jiǎn)書上發(fā)文章了。前段時(shí)間一直都...
    雨落偏安閱讀 316評(píng)論 1 0
  • 一口茶,微呷入口,細(xì)細(xì)品味,苦中一縷清香,苦中一絲甘甜,輕輕地滑落喉間,苦盡甘來,細(xì)細(xì)品味。 品茶,像...
    雪戀寒冰閱讀 260評(píng)論 0 4

友情鏈接更多精彩內(nèi)容