语法规则

XPath使用路径表达式来选取文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。

表达式

描述

nodename

选中该元素

/

从根节点选取、或者是元素和元素间的过渡

//

从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置

.

选取当前节点

..

选取当前节点的父节点

@

选取属性

text()

选取文本

路径表达式

路径表达式

结果

bookstore

选择bookstore元素

/bookstore

选取根元素 bookstore。注释:假如路径起始于正斜杠(/),则此路径始终代表到某元素的绝对路径!

bookstore/book

选取属于 bookstore 的子元素的所有 book 元素

//book

选取所有 book 子元素,而不管它们在文档中的位置

bookstore//book

选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置

//book/title/@lang

选择所有的book下面的title中的lang属性的值

//book/title/text()

选择所有的book下面的title的文本

查询特定节点

路径表达式

结果

//title[@lang="eng"]

选择lang属性值为eng的所有title元素

/bookstore/book[1]

选取属于 bookstore 子元素的第1个 book 元素

/bookstore/book[last()]

选取属于 bookstore 子元素的最后1个 book 元素

/bookstore/book[last()-1]

选取属于 bookstore 子元素的倒数第2个 book 元素

/bookstore/book[position()>1]

选择bookstore下面的book元素,从第2个开始选择

/bookstore/book[position()>1][postion()<5]

选择bookstore下面的book元素,从第2个开始取到第4个元素

//book/title[text()='Harry Potter']

选择所有book下的title元素,仅仅选择文本为Harry Potter的title元素

注意点: 在XPath中,第一个元素的位置是1,最后一个元素的位置是last(),倒数第二个是last()-1

语法练习

接下来对豆瓣电影top250的页面来练习上述语法:豆瓣电影 Top 250

  • 选择所有的h1下的文本
//h1/text()
  • 获取电影信息的href属性
//div[@class='item']//div[@class='hd']/a/@href
  • 获取电影的评价人数
//div[@class='star']/span[last()]/text()

总结

  1. XPath的概述:XPath (XML Path Language),解析查找提取信息的语言
  2. xml是和服务器交互的数据格式和json的作用一致
  3. html是浏览器解析标签数据显示给用户
  4. XPath的重点语法获取任意节点://
  5. XPath的重点语法根据属性获取节点:标签[@属性 = '值']
  6. XPath的获取节点属性值:@属性值
  7. XPath的获取节点文本值:text()

案例-抓取豆瓣电影信息

import requests
# import lxml.html as lh
from lxml import etree
import chardet
from multiprocessing.dummy import Pool

times=input('输入抓取页面数:')
startUrl='https://movie.douban.com/top250?start='

urls=[]
for page in range(int(times)):
    urls.append(startUrl+str(25*page))

#获取网页源代码
def getHtml(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.622"
    }
    # requests.get(url)获取响应,.content获取网页二进制编码内容
    html_b = requests.get(url,headers=headers).content
    # chardet.detect(html_b)#检测二进制代码的编码方式
    # print(chardet.detect(html_b))
    html = html_b.decode()
    return html

html=getHtml(startUrl)
# print(html)

# 多线程访问多个页面
pool=Pool(5)
htmls=pool.map(getHtml,urls)
pool.close()
pool.join()

# 抓取页面信息
def XpathGetInfo(html):
    html_xpath=etree.HTML(html)#将html页面转换为xpath结构
    data=html_xpath.xpath('//ol[@class="grid_view"]/li')
    results=[]
    # 获取一页的电影信息
    for i in range(len(data)):
        res = {}
        info=data[i].xpath('.//div[@class="hd"]')
        # print(blockInfo)
        # 获取电影链接
        href=info[0].xpath('.//a/@href')[0]
        # 获取电影名称
        name=info[0].xpath('.//a/span[@class="title"]/text()')[0]

        starInfo=data[i].xpath('.//div[@class="bd"]')
        star=starInfo[0].xpath('.//span[@class="rating_num" and @property="v:average"]/text()')[0]
        res['name']=name
        res['href']=href
        res['star']=star
        results.append(res)
    return results

pool=Pool(5)
res=pool.map(XpathGetInfo,htmls)
#抓取times页电影信息
for i in range(int(times)):
    print(res[i])