Python爬虫——4-2.数据筛选之XPath

本文介绍XPath在爬虫中的应用,包括环境搭建、基本概念、语法及实战案例。通过XPath可高效筛选结构化数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

爬虫数据筛选——XPath

        在使用爬虫爬取的数据可以分为两种,非结构化数据:数据的内容没有固定的格式和规范,如用户名、邮箱、账号、电话号码、地址、电影名称、评分、评论、商品名称等等,对此类数据的筛选我们一般使用正则表达式,效率较高且非常精准,而对于一些有特定规范的数据如HTML网页文档、XML网页文档、JSON等等,由于数据本身存在一定的规律性,可以通过针对这些规律的分析工具进行数据的提取:**正则表达式、Xpath、BeautifulSoup4、select、css等等,本篇我们主要学习XPath,做个笔记,方便以后学习吧~

Xpath原本是在可扩展标记语言XML中进行数据查询的一种描述语言,可以很方便的在XML文档中查询到具体的数据;后续再发展过程中,对于标记语言都有非常友好的支持,如超文本标记语言HTML。

一、认识Xpath

1.Xpath应用环境的搭建——lxml的安装

      正如在python中有一个内置的re模块用来支持正则表达式语法一样,python中有一个第三方的lxml模块,可以方便的支持Xpath的各种操作,可以友好的解析Xpath语法,使其用于在程序中进行结构化数据筛选。

安装命令如下:

pip install lxml

python2 -m pip install lxml

pip2 install lxml

2.在操作Xpath之前,首先需要了解一些基础的技术术语

* 根标签:在标记语言中,处在最外层的一个标签就是根标签,根标签有且仅有一个,在上述代码中\<html\>就是跟标签
* 父标签:和子标签对应,内部包含了其他元素数据,该标签就是内部标签的父标签,如\<html\>是\<head\>的父标签,\<head\>又是\<title\>的父标签,某些说法中,父标签的父标签..被称为上级标签或则先代标签或者先辈标签
* 子标签:和父标签对应,被包含的元素,就是外部元素的子标签,如\<head\>是\<html\>的子标签,\<title\>标签是\<head\>的子标签,\<tr\>是\<table\>的子标签;同样的子标签的子标签,也被称为后代标签
* 兄弟标签:两个或者多个处在相同级别的标签,有相同的父标签,如\<h1\>和\<table\>是兄弟标签,\<head\>和\<body\>是兄弟标签,\<table\>中的两个\<tr\>是兄弟标签等等
* Xpath描述语言的常见语法
和正则表达式相比较,Xpath使用最简单的语法操作完成数据的查询匹配操作

表达式 |描述
-|-
nodename| 选取此节点的所有子节点。
/| 从根节点选取。
//| 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
.| 选取当前节点。
..| 选取当前节点的父节点。
@| 选取属性。
*| 匹配任何元素节点。
@*| 匹配任何属性节点。
node()| 匹配任何类型的节点。
通过如下的方式直接操作上面的文档
路径表达式 | 结果
-|-
html| 选取 html 元素的所有子节点。
/html| 选取根元素 html。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
table/tr/td| 选取属于 table 的子元素的所有 td 元素。
//div \| //table|选取所有的div或者table节点
//table|选取所有 table 子元素,而不管它们在文档中的位置。
html//div|选择属于html元素的后代的所有div元素,而不管它们位于 html之下的什么位置。
//@href |选取名为href 的所有属性。
标签条件筛选查询匹配
路径表达式 | 结果
-|-
//table/tr[1] | 选取属于table子元素的第一个 tr 元素。
//table/tr[last()] | 选取属于 table 子元素的最后一个 tr 元素。
//table/tr[last()-1] | 选取属于 table 子元素的倒数第二个 tr 元素。
//table/tr[position()<3] | 选取最前面的两个属于 table 元素的子元素的tr元素。
//td[@width] | 选取所有拥有名为 width 的属性的 td 元素。
//td[@width='100'] | 选取所有 td 元素,且这些元素拥有属性width并且值为100。
//tr//td[span>10000] | 选取tr元素的所有td子元素,并且其中的span 元素的值须大于10000。


同样,Xpath支持数据运算操作
运算符| 描述| 实例| 返回值
-|-|-|-
+ |加法 |6 + 4| 10
- |减法 6 - 4| 2
* |乘法 6 * 4| 24
div |除法 8 div 4| 2
= |等于| price=9.80 |如果 price 是 9.80,则返回 true。如果 price 是 9.90,则返回 false。
!=|不等于|price!=9.80 |如果 price 是 9.90,则返回 true。如果 price 是9.80,则返回 false。
< |小于| price<9.80 |如果 price 是 9.00,则返回 true。如果 price 是 9.90,则返回 false。
<= |小于或等于 |price<=9.80 |如果 price 是 9.00,则返回 true。如果 price 是 9.90,则返回 false。
> |大于| price>9.80 |如果 price 是 9.90,则返回 true。如果 price 是 9.80,则返回 false。
>= |大于或等于| price>=9.80 |如果 price 是 9.90,则返回 true。如果 price 是 9.70,则返回 false。
or |或| price=9.80 or price=9.70 |如果 price 是 9.80,则返回 true。如果 price 是 9.50,则返回 false。
and |与 |price>9.00 and price<9.90 |如果 price 是 9.80,则返回 true。如果 price 是 8.50,则返回 false。
mod |计算除法的余数 |5 mod 2 |1

xpath在浏览器中进行测试时,可以给谷歌浏览器安装一个插件Xpath Helper插件;就可以直接在浏览器中通过xpath语法来完成对数据的匹配测试
测试通过的xpath语法,就可以直接在程序中使用了!

二、python操作Xpath

python第三方模块lxml可以对Xpath有友好的支持,lxml是C实现的一种高性能python用于HTML/XML的解析模块,可以通过Xpath语法在html文档数据中进行指定表达式数据的索引查询

* 简单etree操作
```
# -*- coding:utf-8 -*-
from lxml import etree
# 模拟得到爬虫数据
content = """
    <html>
        <head>
            <title>大牧</title>
        </head>
        <body>
            <h1>个人简介</h1>
            <div>
                <p>姓名:某某某</p>
                <p>住址:中国 乡下</p>
                <p>座右铭:岂能尽如人意,但求无愧于心</p>
            </div>
        </body>
    </html>
"""
# 转换成html数据
# html = etree.parse("index.html")# 从文件中直接加载html数据
html = etree.HTML(content)# 通过etree.HTML()函数将字符串转换成HTML文档对象
print dir(html)# 查看文档对象的所有函数
print html.getchildren()# 查看文档对象根节点的所有子节点

# 转换成字符数据
str_html = etree.tostring(html)# 将HTML文档对象转换成字符串
print type(str_html)# 查看输出类型
print str_html# 查看输出数据

* xpath操作
```
# -*- coding:utf-8 -*-
from lxml import etree
# 模拟得到爬虫数据
content = u"""
    <html>
        <head>
            <title>大牧</title>
        </head>
        <body>
            <h1 name="title">个人简介</h1>
            <div name="desc">
                <p name="name">姓名:<span>某某某</span></p>
                <p name="addr">住址:中国 乡下</p>
                <p name="info">座右铭:岂能尽如人意,但求无愧于心</p>
            </div>
        </body>
    </html>
"""
# 将爬取到的数据转换成HTML文档
html = etree.HTML(content)
# 查询所有的p标签
p_x = html.xpath("//p")
print(p_x)

# 查询所有Name属性的值
v_attr_name= html.xpath("//@name")
print(v_attr_name)

# 查询所有包含name属性的标签
e_attr_name = html.xpath("//*[@name]")
print(e_attr_name)

# 查询所有包含name属性,并且name属性值为desc的标签
e_v_attr_name = html.xpath("//*[@name='desc']")
print(e_v_attr_name)

# 查询所有p标签的文本内容,不包含子标签
p_t = html.xpath("//p")
for p in p_t:
    print (p.text)

# 查询多个p标签下的所有文本内容,包含子标签中的文本内容
p_m_t = html.xpath("//p")
for p2 in p_m_t:
    print(p2.xpath("string(.)"))

```
案例操作:爬虫智联招聘中前10页的某个工作岗位名称、薪水、公司信息

# coding:utf-8
'''
使用xpath爬取智联招聘职位信息
'''
import requests
from lxml import etree

# 访问路由
url='http://sou.zhaopin.com/jobs/searchresult.ashx?jl=%E5%8C%97%E4%BA%AC%2B%E4%B8%8A%E6%B5%B7%2B%E5%B9%BF%E5%B7%9E%2B%E6%B7%B1%E5%9C%B3&kw=python%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88&p=1&isadv=0'
# 设置访问头
headers={
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
}
# 发送请求
response=requests.get(url,headers=headers)

# 根据网页数据,转换为html
html=etree.HTML(response.text)

# 使用xpath语法进行匹配
# 获取职位名称
job_names=html.xpath("//table[@class='newlist']/tr[1]/td[@class='zwmc']/div")
#job_names=html.xpath("//div[@id='newlist_list_content_table']/table[@class='newlist']/tr[1]/td[@class='zwmc']/div/a")
# 定义职位名称列表
name_list=[]
for job_name in job_names:
    job_name2=job_name.xpath('string(.)').strip()
    name_list.append(job_name2)


# 获取职位月薪
month_nums=html.xpath("//table[@class='newlist']/tr[1]/td[@class='zwyx']")
#定义保存月薪的列表
num_list=[]
for num in month_nums:
    num2=num.xpath('string(.)').strip()
    num_list.append(num2)

# 获取公司名称
company_names=html.xpath("//table[@class='newlist']/tr[1]/td[@class='gsmc']")
#定义保存月薪的列表
company_list=[]
for company_name in company_names:
    company_name2=company_name.xpath('string(.)').strip()
    company_list.append(company_name2)

max_list=[]
max_list.append(name_list)
max_list.append(num_list)
max_list.append(company_list)

f = open('zl.txt', 'w')
i=0
for i in range(0,len(company_list)):
    info= max_list[0][i]+'|'+max_list[1][i]+'|'+max_list[2][i]+"\r\n"
    print info
    f.write(info.encode('utf-8'))
f.close()


# 打开zl.txt文件,保存内容格式如下
'''
python开发工程师|10001-15000|乐飞天下信息技术(北京)有限公司

Python开发工程师|15001-20000|乐飞天下信息技术(北京)有限公司

python开发工程师|6001-8000|北京红枣科技有限公司
......
'''



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值