Xpath解析
定义:
Xpath是XML路径语言,它可以用来确定xml文档中的元素位置,通过元素路径来完成对元素的查找。xpath是一种非常强大的定位方式。Path通常与lxml库一起使用,用于解析XML或HTML文档。
概念:
XPath 是一种用于在 XML 文档中导航和选择节点的查询语言,它基于一些核心概念:
- 节点(Nodes): 在XML文档中,所有的内容都被视为节点,包括元素、属性、文本、注释等。XPath 中的节点分为元素节点、属性节点、文本节点等。。
- 节点路径(Node Path): 节点路径是XPath中用于定位节点的一种表达方式。它描述了从文档根节点到目标节点的路径,以斜杠
/分隔各级节点。 - 谓词(Predicate): 谓词是XPath中用于筛选节点的表达式,可以附加在节点路径的末尾,帮助进一步限定所选节点的条件。
- 表达式(Expression): XPath 表达式是一组语法规则,用于描述如何在XML文档中选择节点。这包括节点路径、运算符、函数等。
- 运算符(Operators): XPath 提供了一些运算符,用于在表达式中执行比较和计算操作,例如关系运算符(=、!=、<、>等)和逻辑运算符(and、or、not等)。
- 函数(Functions): XPath 支持一些内置函数,用于执行各种操作,例如字符串处理、数学运算等。函数通过名称和参数来调用。
节点之间的关系:
- 父节点(Parent) : HTML 是 body 和 head 节点的父节点;
- 子节点(Child) :head 和 body 是 HTML 的子节点;
- 兄弟节点(Sibling) :拥有相同的父节点,head 和 body 就是兄弟节点。title 和 div 不是兄弟,因为他们不是同一个父节点。
- 祖先节点(Ancestor) :body 是 form 的祖先节点,爷爷辈及以上👴;
- 后代节点(Descendant) :form 是 HTML 的后代节点,孙子辈及以下👶。
html文档树
代码演示:
import requests
from lxml import etree
url='example.com'
headers='User-Agent':'example
response=requests.get(url=url,headers=headers)
# 创建etree对象
html=etree.HTML(response.text)
...
Xpath的定位语法
例:
绝对路径与相对路径
绝对路径定位语法:
Xpath 中的绝对路径从 HTML 根节点开始算,相对路径从任意节点开始。通过开发者工具,我们可以拷贝到 Xpath 的绝对路径和相对路径代码:
同时绝对路径也是最直观的路径:
/html/body/div[2]/div[1]/div[5]/div/div/form/span[1]/input
相对路径定位语法:
| 表达式 | 说明 | 举例 |
|---|---|---|
| / | 从根节点开始选取 | /html/div/span |
| // | 从任意节点开始选取 | //input |
| . | 选取当前节点 | |
| .. | 选取当前节点的父节点 | //input/.. 会选取 input 的父节点 |
| @ | 选取属性或者根据属性选取 | //input[@data] 选取具备 data 属性的 input 元素 //@data 选取所有 data 属性 |
| * | 通配符,表示任意节点或任意属性 |
相对路径:
以//开头,可以从任意节点开始,一般我们会取一个唯一定位到的元素开始写,可以增加查找的准确性。
//*[@id="kw"]
# 从根节点开始定位
/html/body/div/form/div
# 从任意节点开始选取
//form/div
# 属性定位是通过 @ 符号指定需要使用的属性。
# class属性定位
//form/span[@class="soutu"]
# ID属性定位
//input[@id="su"]
# 使用谓语定位
# 元素下标定位
//form[@id="form"]/span[2]
#定位到form标签下的第二个span标签
//form[@id="form"]/span[last()]
#定位到form标签下的最后一个span标签
//form[@id="form"]/span[last()-1]
#定位到form下的倒数第二个span标签
//form[@id="form"]/span[position()=2]
#定位到from 下第二个span标签
//form[@id="form"]/span[position()>2]
#定位到form下的 下标大于 2 的span标签
使用部分匹配函数定位
| 函数 | 说明 | 举例 |
|---|---|---|
| contains | 选取属性或者文本包含某些字符 | //div[contains(@id, 'data')] 选取 id 属性包含 data 的 div 元素 |
| starts-with | 选取属性或者文本以某些字符开头 | //div[starts-with(@id, 'data')] 选取 id 属性以 data 开头的 div 元素 |
bs4解析
BeautifulSoup的基础应用
Beautiful Soup 是一个 Python 库,用于从 HTML 和 XML 文件中提取数据。它提供了一种方式来快速浏览文件的结构,找到我们需要的数据,并提供解析、遍历和修改文档树的方法。通常在网络爬虫、数据挖掘和数据分析等领域中使用。Beautiful Soup 支持多种解析器,包括 Python 的内置解析器和第三方库。它能够将复杂的 HTML 和 XML 文档转换为一个复杂的树形结构,每个节点都是一个 Python 对象,可以通过不同的方式进行遍历、搜索和修改。
一些文档解析器:
一些常见对象的种类:
- tag : html中的标签。可以通过BeautifulSoup分析Tag的具体内容,具体格式为soup.name,其中name是html下的标签。
- NavigableString : 标签中的文本对象。
- BeautifulSoup : 整个html文本对象。可以作为Tag对象。
- Comment : 特殊的NavigableString对象,如果html标签中有注释,则可过滤注释符号并保留注释文本。
代码演示
from bs4 import BeautifulSoup
html_doc = """
<html>
<head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">
Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>
</html>
"""
#创建BeautifulSoup对象
soup=BeautifulSoup(httml_doc,'lxml')
print(type(soup)) # 输出<class 'bs4.BeautifulSoup'>
print(type(soup.body)) # 输出 <class 'bs4.element.Tag'>
print(type(soup.title.string)) # 输出<class 'bs4.element.NavigableString'>
遍历文档树
- contents 返回的是一个所有子节点的列表(了解)
- children 返回的是一个子节点的迭代器(了解)
- descendants 返回的是一个生成器遍历子子孙孙(了解)
- string 获取标签里面的内容 .string 属性获取元素的文本。如果元素不存在文本,则返回 None 需要注意的是,
如果元素包含了多个子元素,则该属性返回 None。(掌握) - strings 返回是一个生成器对象用过来获取多个标签内容(掌握)
- stripped_strings 和strings 基本一致 但是它可以把多余的空格去掉(掌握)
搜索文档树
- find():返回搜索到的第一条数据
- find_all():以列表形式返回所有的搜索到的标签数据
- select(): 搜索方法 根据css定位器去定位
div=soup.find('div',attrs={'class':"resblock-desc-wrapper"}) # 找标签的第一种写法
div1=soup.find('div',class_="resblock-desc-wrapper") # 找标签的第二种写法
print(div.div.a.string) # 输出第一个a标签的文本内容
div_box1=soup.find_all('div',attrs={'class':'resblock-desc-wrapper'})
print(div_box1) # 输出的是一个生成器需要加for循环遍历
for i in div_box1:
title=i.find('div','resblock-name').a.string # 输出第一个a标签的文本内容
address=''.join(i.find('div','resblock-location').stripped_strings) # 输出的内容是去掉空格符和换行符的内容
div_box2=soup.select('div.resblock-desc-wrapper') # 找的是div标签且属性为class 返回的是一个可迭代对象
print(len(div_box2))
for i in div_box2:
title=i.div.a.string
mianji=i.select('div.resblock-area > span')[0].string # 因为.select()返回的是一个列表,而列表不能直接取到文本
address=''.join(i.select('div.resblock-location')[0].stripped_strings)
price=''.join(i.select('div.main-price')[0].stripped_strings)
print(title,mianji,address,price)
最后:创作不易麻烦小哥哥小姐姐高抬贵手点赞收藏加关注,感谢!