【Python】爬蟲-Xpath

Xpath

文章參考:https://www.cnblogs.com/mxjhaima/p/13775844.html#%E6%A1%88%E4%BE%8B

安裝

pip install lxml

引用

from lxml import etree

獲取文檔樹對象

通過Xpath 獲取文檔的對象,獲取到對象后,可以通過文檔的對象去去獲取到樹中的元素。

文本轉(zhuǎn)化文檔樹對象

def strToEleObj():
    doc = '''
          <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> 閉合標(biāo)簽
               </ul>
           </div>
          '''
    # 把文本轉(zhuǎn)換成一個文檔樹對象
    html = etree.HTML(doc)
    result = etree.tostring(html)
    print(str(result, 'utf-8'))

文件轉(zhuǎn)化文檔樹對象

def fileToEleObj():
    # 讀取外部文件 index.html
    html = etree.parse('./index.html')
    # pretty_print=True 會格式化輸出
    result = etree.tostring(html, pretty_print=True)  # pretty_print=True 會格式化輸出
    print(result)

節(jié)點(diǎn)、元素、屬性、內(nèi)容

xpath 的思想是通過 路徑表達(dá) 去尋找節(jié)點(diǎn)。節(jié)點(diǎn)包括元素,屬性,和內(nèi)容

路徑表達(dá)式

/   根節(jié)點(diǎn),節(jié)點(diǎn)分隔符,
//  任意位置
.   當(dāng)前節(jié)點(diǎn)
..  父級節(jié)點(diǎn)
@   屬性

示例

from lxml import etree
'''
    路徑表達(dá)式
'''
def get_el_list():
    doc = '''
              <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> 閉合標(biāo)簽
                   </ul>
               </div>
              '''
    # 把文本轉(zhuǎn)換成一個文檔樹對象
    html = etree.HTML(doc)
    # 獲取當(dāng)前節(jié)點(diǎn)
    print('獲取當(dāng)前節(jié)點(diǎn)---> ', html.xpath('.'))
    # 獲取 根節(jié)點(diǎn) 標(biāo)簽 ,當(dāng)前元素?zé)o根節(jié)點(diǎn) 通過 打印 etree.tostring(html) ,會發(fā)現(xiàn)根節(jié)點(diǎn)為 <html> </html> 包裹的內(nèi)容 ,上一行獲取的當(dāng)前節(jié)點(diǎn)為 html
    print('獲取 根節(jié)點(diǎn) 標(biāo)簽---> ', html.xpath('/'))
    # 獲取 li 標(biāo)簽
    print('獲取 li 標(biāo)簽---> ', html.xpath('//li'))
    # 獲取 li 下的 a 標(biāo)簽屬性
    print('獲取li下的 a 標(biāo)簽屬性----> ', html.xpath('//li/a/@href'))
    # 獲取 p 標(biāo)簽 ,此標(biāo)簽不存在 返回結(jié)果為空數(shù)組
    print('獲取 p 標(biāo)簽----> ', html.xpath('//p '))

輸出結(jié)果

獲取當(dāng)前節(jié)點(diǎn)--->  [<Element html at 0x2a989854200>]
獲取 根節(jié)點(diǎn) 標(biāo)簽--->  []
獲取 li 標(biāo)簽--->  [<Element li at 0x2a9898ece40>, <Element li at 0x2a9899240c0>, <Element li at 0x2a989924180>, <Element li at 0x2a9899241c0>, <Element li at 0x2a989924200>]
獲取li下的 a 標(biāo)簽屬性---->  ['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']
獲取 p 標(biāo)簽---->  []

說明

  1. 將doc 轉(zhuǎn)換成 文檔對象后,為 <html> </html> 包裹的內(nèi)容;故獲取到的當(dāng)前的節(jié)點(diǎn)對象為HTML;
  2. 當(dāng)前節(jié)點(diǎn)為HTML,無根節(jié)點(diǎn)故返回為空數(shù)組即:[];
  3. 查詢不存在的節(jié)點(diǎn)時,返回空數(shù)組即:[]

通配符

*   任意元素
@*  任意屬性
node()  任意子節(jié)點(diǎn)(元素,屬性,內(nèi)容)

示例


'''
    通配符
'''
from lxml import etree
def get_el_by_anyChar():
    doc = '''
              <div>
                  <ul class="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> 閉合標(biāo)簽
                   </ul>
               </div>
              '''
    # 把文本轉(zhuǎn)換成一個文檔樹對象
    html = etree.HTML(doc)
    # 獲取 ul 下的所有子節(jié)點(diǎn)
    print('獲取 ul 下的所有子節(jié)點(diǎn)---> ', html.xpath('//ul/node()'))
    # 獲取 任意元素[所有的]
    print('獲取 ul 下 任意元素[所有的]---> ', html.xpath('//ul/*'))
    # 獲取 任意屬性 [所有的]
    print('獲取 ul 下 任意屬性[所有的]---> ', html.xpath('//ul/@*'))

輸出結(jié)果

獲取 ul 下的所有子節(jié)點(diǎn)--->  ['\n                       ', <Element li at 0x1d4792b5e80>, '\n                       ', <Element li at 0x1d4792b5e00>, '\n                       ', <Element li at 0x1d4792b5f00>, '\n                       ', <Element li at 0x1d4792b5f40>, '\n                       ', <Element li at 0x1d4792b5ec0>, ' 閉合標(biāo)簽\n                   ']
獲取 任意元素--->  [<Element li at 0x1d47928dd80>, <Element li at 0x1d4792b5e80>, <Element li at 0x1d4792b5fc0>, <Element li at 0x1d4792b5e00>, <Element li at 0x1d4792b5f00>]
獲取 任意屬性--->  ['ul']

謂語

//a[n] n為大于零的整數(shù),代表子元素排在第n個位置的<a>元素
//a[last()]   last()  代表子元素排在最后個位置的<a>元素
//a[last()-]  和上面同理,代表倒數(shù)第二個
//a[position()<3] 位置序號小于3,也就是前兩個,這里我們可以看出xpath中的序列是從1開始
//a[@href]    擁有href的<a>元素
//a[@href='www.baidu.com']    href屬性值為'www.baidu.com'的<a>元素
//book[@price>2]   price值大于2的<book>元素

示例

from lxml import etree
def get_el_by_wei():
    doc = '''
                  <div>
                      <ul class="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> 閉合標(biāo)簽
                       </ul>
                   </div>
                  '''
    # 把文本轉(zhuǎn)換成一個文檔樹對象
    html = etree.HTML(doc)
    # 獲取第一個 li / a 元素 里面的文本
    print('獲取第一個 ---> ', html.xpath('//li[1]/a/text()'))
    # 獲取最后一個 li / a 元素 里面的文本
    print('獲取最后一個 ---> ', html.xpath('//li[last()]/a/text()'))
    # 獲取倒數(shù)第二個 li / a元素 里面的文本
    print('獲取 倒數(shù)第二個---> ', html.xpath('//li[last()-1]/a/text()'))
    # 獲取位置序號小于3,也就是前兩個 li / a元素 里面的文本
    print('獲取位置序號小于3 ---> ', html.xpath('//li[position()<3]/a/text()'))
    # 獲取擁有href的<a>元素下的文本
    print('獲取第一個 ---> ', html.xpath('//a[@href]/text()'))
    # 獲取 a 標(biāo)簽下 href = link3.html的a元素下的文本 注意 不是 == 而是 =
    print('獲取 a 標(biāo)簽下 href = link3.html的<a>元素---> ', html.xpath('//a[@href="link3.html"]/text()'))
    # 獲取 ul class == ul 的
    print('獲取 ul class == ul  ---> ', html.xpath('//ul[@class="ul"]'))

多個路徑

用| 連接兩個表達(dá)式,可以進(jìn)行 或匹配

//book/title | //book/price  

示例

from lxml import etree
def get_el_mutil_path():
    doc = '''
                  <div>
                      <ul class="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> 閉合標(biāo)簽
                       </ul>
                   </div>
                  '''
    # 把文本轉(zhuǎn)換成一個文檔樹對象
    html = etree.HTML(doc)
    # 獲取li 下 class = item-inactive 或者 item-1
    print('獲取li 下 class = item-inactive 或者 item-1 ---> ', html.xpath('//li[@class="item-inactive"] | //li[@class="item-1"] '))

輸出結(jié)果

獲取li 下 class = item-inactive 或者 item-1 --->  [<Element li at 0x1b490955f40>, <Element li at 0x1b490966200>, <Element li at 0x1b490966180>]

函數(shù)

更多函數(shù)查看https://www.w3school.com.cn/xpath/xpath_functions.asp

contains(string1,string2)
starts-with(string1,string2)
# 文本
text()
# 最后一個
last()
# 位置
position()
# 回去所有節(jié)點(diǎn)
node()
'''
    函數(shù)
'''
from lxml import etree
def get_el_func():
    doc = '''
                     <div>
                         <ul class="ul" >
                              <li class="item-0 active"><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> 閉合標(biāo)簽
                          </ul>
                      </div>
                     '''
    # 把文本轉(zhuǎn)換成一個文檔樹對象
    html = etree.HTML(doc)
    # 匹配 class 包含 active 的 元素
    print(html.xpath("http://*[contains(@class,'active')]"))
    # 獲取所有 li / a 文本
    print(html.xpath("http://li/a/text()"))
    # 獲取最后一個 li / a 文本
    print(html.xpath("http://li[last()]/text()"))
    # 獲取位置為1的li /a 文本 ,節(jié)點(diǎn)時從1開始 而不是0
    print(html.xpath("http://li[position()=1]/a/text()"))

輸出結(jié)果

[<Element li at 0x23ea36d0400>, <Element li at 0x23ea36d0180>]
['first item', 'second item', 'third item', 'fourth item', 'fifth item']
[' # 注意,此處缺少一個 ']
['first item']

實(shí)戰(zhàn)信息

獲取某電影網(wǎng)站電影名稱、簡單描述、圖片

import requests
from lxml import etree

'''
     獲取電影信息列表
'''
def get_moive_info_list(url):
        # 定義頭部信息
        headers = {
                'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
        }
        res = requests.get(url, headers=headers)
        # res.text 返回的是 文本
        html = res.text
        print('輸出響應(yīng)信息->',html)
        # 將文本轉(zhuǎn)換成文檔對象
        selector = etree.HTML(html)
        # 返回是電影名列表
        title_list = selector.xpath('//a[@class="pic-pack-outer"]/h3/text()')
        print('電影名稱列表:',title_list)
        # 獲取簡單描述
        desc_list = selector.xpath('//a[@class="pic-pack-outer"]/p/text()')
        print('電影名稱簡單描述:', desc_list)
        # 圖片
        img_list = selector.xpath('//a[@class="pic-pack-outer"]/img/@src')
        print('圖片列表:', img_list)

if __name__ == '__main__':
        url = 'https://xxxxxxx/vod/list/n_1_t_25/o1p1.html'
        get_moive_info_list(url)

輸出結(jié)果

輸出響應(yīng)信息-> <!DOCTYPE html>
·······
</body>
</html>
電影名稱列表: ['辣媽犟爸', '五月梨花香', '歲歲平安',.....]
電影名稱簡單描述: ['年輕村官奮斗歷程', '脫貧致富振興家鄉(xiāng)', .....]
圖片列表: ['https://image11.m1905.cn/uploadfile/2022/0804/thumb_1_150_203_20220804094442559303.jpg',  .... 'https://image11.m1905.cn/uploadfile/2016/0926/thumb_1_150_85_20160926105222739343.jpg']

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

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

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