XPath,全称 XML Path Language,即 XML 路径语言。它使用路径表达式来选取 XML 文档中的节点或节点集。
Python 使用 XPath 要先安装 lxml 库
XPath的简单调用方法:
from lxml import etree
html = etree.HTML(源码) # 将源码转化为能被 XPath 匹配的格式
result = html.xpath(表达式) # 返回列表
节点、元素、标签的关系
将 HTML 文档视作树结构,每个 HTML 元素都是元素节点。节点还包括文本节点、属性节点等。
HTML 源码中被尖括号(<
和>
)包起来的是标签,比如<head>、<body>
。大多数标签都成对使用 <p></p>
,成对标签和它们之间的一切形成一个元素,标签名就是元素名。
节点关系
a 节点包括 b 节点,则 a 就是 b 的父节点,b 就是 a 的子节点。
拥有相同父节点的是同胞节点
某节点的父,父的父,等等,是其先辈节点
某节点的子,子的子,等等,是其后代节点
示例:
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
<bookstore>
是<book>
的父节点
<title>、<author>、<year>、<price>
都是<book>
的子节点
<title>、<author>、<year>、<price>
互相之间是同胞节点
<bookstore> 、<book>
是<title>
的先辈节点
<book> 、 <title>
是<bookstore>
的后代节点
语法
常用路径表达式
/
从当前节点选取直接子节点,或对当前节点进行操作
//
从当前节点选取后代节点
..
选取当前节点的父节点
@
选取属性
示例:
/bookstore
选取根元素 bookstore
bookstore/book
选取 bookstore 元素的直接子元素中的 book 元素
//book
选取文档中的所有 book 元素
bookstore//book
选取 bookstore 元素的所有后代 book 元素
//@lang
选取文档中包含 lang 属性的所有元素
谓语
示例:
/bookstore/book[1]
选取 bookstore 子元素中的第一个 book 元素
/bookstore/book[last()]
选取 bookstore 子元素中的最后一个 book 元素
/bookstore/book[last()-1]
选取 bookstore 子元素中的倒数第二个 book 元素
//title[@lang]
选取所有拥有 lang 的属性的 title 元素
//title[@lang='eng']
选取所有拥有 lang 属性且值为 eng 的 title 元素
通配符
示例:
/bookstore/*
选取 bookstore 元素的所有子元素
//*
选取文档中的所有元素
//title[@*]
选取所有带有属性的 title 元素
运算符
|
选取若干路径
示例:
//title | //price
选取文档中的所有 title 和 price 元素
属性
attribute::lang
获取当前节点的属性 lang 的值
@lang
获取当前节点的属性 lang 的值
不含某属性
//p[not(@class)]
选取不含 class 属性的所有 p 节点
//p[not(@class or @id)]
选取不含 class 属性和 id 属性的所有 p 节点
文本
/text()
获取节点中的文本
示例
# python3
# -*- coding: utf-8 -*-
# Filename: xpath_demo.py
"""
练习使用 XPath 提取网页内容
@author: v1coder
"""
from lxml import etree
import requests
headers = {'User-Agent': ''}
def get_content(url):
data = requests.get(url, headers=headers).content
return data
# 简书
def jianshu():
url = '//www.greatytc.com/p/713415f82576'
data = get_content(url)
html = etree.HTML(data)
# p[not(@class)] 为不含 class 属性的 p 节点
texts = html.xpath('//p[not(@class)]/text()')
for text in texts[:-1]:
print(text)
#jianshu()
# 代码解释:
# //p 为所有 p 元素
# //p[not(@class)] 为所有不含 class 属性的 p 元素
# /text() 为获取当前元素的文本
# 盗版小说网站
def biqukan_com():
url = 'https://www.biqukan.com/1_1094/5403177.html'
data = get_content(url)
html = etree.HTML(data)
texts = html.xpath('//div[@id="content"]//text()')
for text in texts:
print(text)
#biqukan_com()
# 代码解释:
# //div[@id="content"] 为获取包含 id 属性且属性值为 content 的所有 div 元素
# //text() 为获取当前节点及所有后代节点的文本
# 豆瓣电影 TOP250
def top_250():
url = 'https://movie.douban.com/top250'
data = get_content(url)
html = etree.HTML(data)
# 第一个 span 节点用 span[1]
texts = html.xpath('//div[@class="hd"]/a/span[1]/text()')
for text in texts:
print(text)
#top_250()
# 代码解释:
# /a 为当前节点的直接子节点中的 a 节点
# /span[1] 为直接子节点中的第一个 span 节点
# 妹子图1
def mmjpg_com():
url = 'http://www.mmjpg.com/'
data = get_content(url)
html = etree.HTML(data)
# 获取属性 src 的值,用 attribute::src
urls = html.xpath('//img[@width="220"]/attribute::src')
for url in urls:
print(url)
#mmjpg_com()
# 代码解释:
# /attribute::src' 为获取当前元素的属性 src 的值
# 妹子图2
def haopic():
url = 'http://www.haopic.me/tag/meizitu'
data = get_content(url)
html = etree.HTML(data)
urls = html.xpath('//div[@class="post"]/a/img/@src')
for url in urls:
print(url)
#haopic()
# 代码解释:
# //div 获取所有 div 元素
# '//div[@class="post"] 获取包含属性 class 且属性值为 post 的 div 元素
# /a 获取前面节点的直接子节点中的 a 节点
# /img 获取前面节点的直接子节点中的 img 节点
# /attribute::src 获取前面节点的属性 src 的值
# 妹子图3
def mzitu():
url = 'https://www.mzitu.com/'
data = get_content(url)
html = etree.HTML(data)
urls = html.xpath('//img[@width="236"]/attribute::data-original')
for url in urls:
print(url)
#mzitu()
获取网页某节点 xpath 的方法:
Chrome浏览器,打开开发者工具(Windows 快捷键 F12,Mac 快捷键 command+option+I)
在 elements 中找到想要获取 XPath 的标签,
单击右键,选择 Copy 》 Copy XPath,XPath路径就复制到剪切板了
或者:
把鼠标放在目标数据上,点击右键,点击"检查"
在弹出的 Elements 窗口,就已经定位到了该元素的位置
然后右键,选择 Copy 》 Copy XPath,XPath路径就复制到剪切板了
报错:
lxml.etree.XPathEvalError: Invalid predicate
通常是使用 xpath 的语法里方括号没写全,例如:
[@width="220"
解决方法:补全符号
[@width="220"]
鸣谢:
XPath 语法 - w3school
使用XPath - 静觅
2018-12-29