XPath

Date: 2019-07-03

Author: Sun

XPath简介

XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。

1、辅助工具

  1. Chrome插件 XPath Helper
  2. Firefox插件 XPath Checker

附加:XPath Helper安装过程

(1)找到chrome_xpath_tools目录

(2)方式一:先导入crx文件,看是否可行

​ 安装方式一:直接拖拽chrome.crx插件到谷歌浏览器的扩展程序里。使用快捷钱ctrl+shift+x调出插件,如果没有成功,安装方式二进行安装

(3)方式二:把你的插件扩展名改成rar,然后解压到chrome目录。再重新添加chrome目录到你的谷歌浏览的扩展程序里面。使用快捷键查看是否安装成功

2、lxml

  • lxml 是一个支持XPATH语法的HTML/XML的解析库,主要的功能是解析和提取 HTML/XML 数据,我们可以利用XPath语法,来快速的定位特定元素以及节点信息。
  • lxml和正则一样,也是用 C 实现的,是一款高性能的 Python HTML/XML 解析器。
  • 兼容python2.7和python3.x的所有版本
  • lxml 官方文档

3. 语法基础

3.1、语法格式

  1. 路径 = 相对路径 | 绝对路径

"/"处在XPath表达式开头则表示文档根元素,(表达式中间作为分隔符用以分割每一个步进表达式)如:/html/body/div是一种绝对路径表示法,它表明是从文档根开始查找节点。

如果路径前没有"/"这种表示法称为相对路径,表明从当前节点开始查找。

如:body/div

  1. 路径表达式 = 步进表达式 或者 相对路径 "/"步进表达式。
  2. 步进表达式 = 轴 节点测试 谓词等组成
    • 其中轴表示步进表达式选择的节点和当前上下文节点间的树状关系(层次关系),节点测试指定步进表达式选择的节点名称扩展名,谓词即相当于过滤表达式以进一步过滤细化节点集。
    • 谓词可以是0个或多个。多个谓词用逻辑操作符and, or连接。取逻辑非用not()函数。

3.2、选取节点

  1. 说明

    XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取的

    所谓节点(node),就是XML文件的最小构成单位,一共分成7种

    • element(元素节点)常用
    • attribute(属性节点)常用
    • text (文本节点)常用
    • root (根节点)
    • comment (注释节点)
    • namespace (名称空间节点xml)
    • processing-instruction (处理命令节点(xml))
  2. 语法

    表达式 描述 实例
    nodename 选取nodename节点的所有子节点 xpath(‘//div’) 选取了div节点的所有子节点
    / 从根节点选取 xpath(‘/div’) 从根节点上选取div节点
    // 选取所有的当前节点,不考虑他们的位置 xpath(‘//div’) 选取所有的div节点
    . 选取当前节点 xpath(‘./div’) 选取当前节点下的div节点
    .. 选取当前节点的父节点 xpath(‘..’) 回到上一个节点
    @ 选取属性 xpath(’//@calss’) 选取所有的class属性

3.3、谓语

  1. 说明

    谓语被嵌在方括号内,用来查找某个特定的节点或包含某个制定的值的节点

  2. 语法

    表达式 结果
    xpath(‘/body/div[1]’) 选取body下的第一个div节点
    xpath(‘/body/div[last()]’) 选取body下最后一个div节点
    xpath(‘/body/div[last()-1]’) 选取body下倒数第二个div节点
    xpath(‘/body/div[positon()❤️]’) 选取body下前两个div节点
    xpath(‘/body/div[@class]’) 选取body下带有class属性的div节点
    xpath(‘/body/div[@class=”main”]’) 选取body下class属性为main的div节点
    xpath(‘/body/div[price>35.00]’) 选取body下price元素值大于35的div节点

3.4、通配符

  1. 说明

    Xpath通过通配符来选取未知的XML元素

  2. 语法

    表达式 结果
    xpath(’/div/*’) 选取div下的所有子节点
    xpath(‘/div[@*]’) 选取所有带属性的div节点

3.5、Xpath轴

  1. 说明

    轴可以定义相对于当前节点的节点集

  2. 语法

    轴名称 表达式 描述
    ancestor xpath(‘./ancestor:’) 选取当前节点的所有先辈节点(父、祖父)
    ancestor-or-self xpath(‘./ancestor-or-self:’) 选取当前节点的所有先辈节点以及节点本身
    attribute xpath(‘./attribute:’) 选取当前节点的所有属性
    child xpath(‘./child:’) 返回当前节点的所有子节点
    descendant xpath(‘./descendant:’) 返回当前节点的所有后代节点(子节点、孙节点)
    following xpath(‘./following:’) 选取文档中当前节点结束标签后的所有节点
    following-sibing xpath(‘./following-sibing:’) 选取当前节点之后的兄弟节点
    parent xpath(‘./parent:’) 选取当前节点的父节点
    preceding xpath(‘./preceding:’) 选取文档中当前节点开始标签前的所有节点
    preceding-sibling xpath(‘./preceding-sibling:’) 选取当前节点之前的兄弟节点
    self xpath(‘./self:’) 选取当前节点

3.6、功能函数

  1. 说明

    使用功能函数能够更好的进行模糊搜索

  2. 语法

    函数 用法 解释
    starts-with xpath(‘//div[starts-with(@id,”test”)]‘) 选取id值以test开头的div节点
    contains xpath(‘//div[contains(@id,”test”)]‘) 选取id值包含test的div节点
    and xpath(‘//div[contains(@id,”test”) and contains(@id,”in”)]‘) 选取id值包含ma和in的div节点
    text() xpath(‘//div[contains(text(),”test”)]‘) 选取节点文本包含test的div节点

4. xpath应用

4.1、准备工作

  1. 安装lxml

    pip install lxml==4.3.0
    
    pip install lxml-4.3.0-cp36-cp36m-win_amd64.whl
    

    备注: 下载对应系统版本的wheel文件地址

4.2、基本使用

  1. 导入lxml

    from lxml import etree 
    
  2. 实例化ElementTree

    用来解析字符串格式的HTML文档对象

    root = etree.HTML(html)
    

    从本地读取HTML文件

    root = etree.parse('test.html',etree.HTMLParser())
    result = etree.tostring(html, pretty_print=True)
    
  3. 利用xpath语法解析

    result = root.xpath('//li')
    
  4. 注意事项

先确保html经过了utf-8解码,即code = html.decode('utf-8', 'ignore'),否则会出现解析出错情况。因为中文被编码成utf-8之后变成 '/u2541' 之类的形式,lxml一遇到 “/”就会认为其标签结束

4.3 案例分析

案例1:

爬取百度贴吧楼主页面中图片

#coding=utf-8
from lxml import etree

import requests

num = 0

header = {'User-Agent':'Mozilla/5.0(Macintosh;IntelMacOSX10_7_0)AppleWebKit/535.11(KHTML,likeGecko)Chrome/17.0.963.56Safari/535.11'}

def load_data(key, page_start, page_end):
    url = 'https://tieba.baidu.com/f?ie=utf-8&kw=%s&pn=%d'
    for page in range(page_start,page_end+1):
        full_url = url%(key,(page-1)*50)
        headers = {'User_Agent':'User-Agent:Mozilla/5.0(Macintosh;IntelMacOSX10_7_0)AppleWebKit/535.11(KHTML,likeGecko)Chrome/17.0.963.56Safari/535.11'}
        response = requests.get(full_url,headers = headers,verify = False)
        data = response.text
        xml = etree.HTML(data)
        lzs = xml.xpath('//div[@class="threadlist_lz clearfix"]/div/a/@href')
        #进入楼主的帖子
        for lz in lzs:
            load_lz_detail(lz)

def load_lz_detail(lz_url):
    url = 'https://tieba.baidu.com'+lz_url
    header = {'User-Agent':'Mozilla/5.0(Macintosh;IntelMacOSX10_7_0)AppleWebKit/535.11(KHTML,likeGecko)Chrome/17.0.963.56Safari/535.11'}
    #使用requests进行数据加载
    response = requests.request('GET',url,headers = header,verify = False)
    html = response.text
    xml = etree.HTML(html)
    image_url = xml.xpath('//img[@class="BDE_Image"]/@src')
    #获取了楼主详情页面的图片
    for url in image_url:
        load_lz_detail_image(url)

def load_lz_detail_image(url):
    global  num
    response = requests.get(url,headers =header,verify = False)
    num+=1
    with open('./images/'+str(num)+'.jpg','wb') as file:
        file.write(response.content)

if __name__ == '__main__':
    key = input('请输入贴吧名称:')
    page_start = int(input("请输入起始页"))
    page_end = int(input('请输入末尾页'))
    load_data(key, page_start, page_end)

案例2:

采用xpath爬取格言网数据

练习:

58同城租房信息

原文地址:https://www.cnblogs.com/sunBinary/p/11129800.html