pin_drop当前位置:知识文库 ❯ 图文

Scrapy Selector详解 - CSS与XPath数据提取完整指南

一、Selector概述

Selector(选择器)是Scrapy框架内置的HTML/XML数据提取工具,基于高性能的 lxml库 构建。它提供了两种主要的数据提取方式:CSS选择器XPath表达式,能够满足各种复杂的数据提取需求。

在Scrapy中,response对象自带 css()xpath() 方法,可以直接使用选择器提取页面数据。Selector比BeautifulSoup性能更高,因为它底层使用了C语言编写的lxml解析器,与Scrapy深度集成,是Scrapy爬虫开发中数据提取的首选工具。

二、Selector核心语法

Selector支持三种数据提取方式,可以灵活组合使用:

代码示例

# CSS选择器 - 语法简洁,适合常规提取
response.css('css_selector')
response.css('h1::text').get()          # 获取h1标签的文本
response.css('a::attr(href)').getall()  # 获取所有a标签的href属性

# XPath - 功能更强大,支持复杂条件
response.xpath('xpath_expression')
response.xpath('//h1/text()').get()     # 获取h1标签的文本
response.xpath('//a/@href').getall()    # 获取所有a标签的href属性

# 正则表达式 - 从文本中提取特定模式
response.css('div.price::text').re(r'\d+\.?\d*')  # 提取数字

三、选择器方法与CSS语法详解

选择器常用方法

方法 返回类型 说明
css(query) SelectorList 执行CSS选择器查询
xpath(query) SelectorList 执行XPath查询
get() str/None 获取第一个匹配结果的文本
getall() list 获取所有匹配结果的文本列表
re(regex) list 使用正则表达式匹配并返回结果列表
re_first(regex) str/None 正则匹配第一个结果

CSS选择器常用语法

语法 示例 说明
标签选择 h1 选择所有h1标签
类选择 .title 选择class包含title的标签
ID选择 #main 选择id为main的标签
后代选择 div p 选择div下所有的p(包括间接后代)
子代选择 div > p 选择div的直接子p元素
属性提取 a::attr(href) 获取a标签的href属性值
文本提取 p::text 获取p标签的文本内容
伪类选择 li:nth-child(2) 选择第2个li元素

四、完整代码示例

示例1:CSS选择器提取数据

代码示例

from scrapy.http import HtmlResponse

html = """
<html>
<body>
    <div class="article">
        <p class="author">作者: 张三</p>
        <p class="content">文章内容</p>
        <div class="tags">
            <a href="/tag/python">Python</a>
            <a href="/tag/web">Web</a>
        </div>
    </div>
</body>
</html>
"""

response = HtmlResponse(url='http://example.com', body=html, encoding='utf-8')

# 提取文本 - 使用::text伪元素
title = response.css('h1.title::text').get()
print(f"标题: {title}")

# 提取属性 - 使用::attr()伪元素
links = response.css('div.tags a::attr(href)').getall()
print(f"链接: {links}")

# 提取多个元素
texts = response.css('p::text').getall()
print(f"段落: {texts}")

# 组合选择器
author = response.css('p.author::text').get()
print(f"作者: {author}")

输出结果:

代码示例

标题: 文章标题
链接: ['/tag/python', '/tag/web']
段落: ['作者: 张三', '文章内容']
作者: 作者: 张三

示例2:XPath提取数据

代码示例

from scrapy.http import HtmlResponse

html = """
<html>
<body>
    <table>
        <tr><td>行1列1</td><td>行1列2</td></tr>
        <tr><td>行2列1</td><td>行2列2</td></tr>
    </table>
    <div data-price="99.9" data-stock="50">商品</div>
</body>
</html>
"""

response = HtmlResponse(url='http://example.com', body=html, encoding='utf-8')

# 基本XPath - //表示任意层级
tds = response.xpath('//td/text()').getall()
print(f"所有td: {tds}")

# 属性选择 - @后跟属性名
price = response.xpath('//div/@data-price').get()
print(f"价格: {price}")

# 位置选择 - [1]表示第一个(XPath从1开始计数)
first_row = response.xpath('//tr[1]/td/text()').getall()
print(f"第一行: {first_row}")

# 条件选择 - [@属性名] 过滤有该属性的元素
stock = response.xpath('//div[@data-stock]/@data-stock').get()
print(f"库存: {stock}")

输出结果:

代码示例

所有td: ['行1列1', '行1列2', '行2列1', '行2列2']
价格: 99.9
第一行: ['行1列1', '行1列2']
库存: 50

示例3:正则表达式和链式调用

代码示例

from scrapy.http import HtmlResponse

html = """
<html>
<body>
    <div class="product">
        <span class="price">¥199.90</span>
        <span class="price">¥299.00</span>
        <span class="price">¥99.50</span>
    </div>
    <p class="info">共3件商品,总计¥598.40</p>
</body>
</html>
"""

response = HtmlResponse(url='http://example.com', body=html, encoding='utf-8')

# 正则提取数字 - re()返回列表
prices = response.css('span.price::text').re(r'\d+\.?\d*')
print(f"价格列表: {prices}")

# 正则提取第一个匹配 - re_first()返回单个字符串
first_price = response.css('span.price::text').re_first(r'\d+\.?\d*')
print(f"第一个价格: {first_price}")

# 链式调用 - 先选择容器再精确提取
product_div = response.css('div.product')
price_texts = product_div.css('span.price::text').getall()
print(f"商品价格: {price_texts}")

# 从混合文本中提取总计金额
total = response.css('p.info::text').re_first(r'¥(\d+\.?\d*)')
print(f"总计: {total}")

输出结果:

代码示例

价格列表: ['199.90', '299.00', '99.50']
第一个价格: 199.90
商品价格: ['¥199.90', '¥299.00', '¥99.50']
总计: 598.40

五、CSS与XPath对比

特性 CSS选择器 XPath
语法简洁度 简洁直观 相对复杂
文本提取 ::text /text()
属性提取 ::attr(name) /@name
向上查找 不支持 支持(..
文本条件 不支持 支持(contains()
学习成本 中等

六、实际应用场景

  • 场景1 - 商品列表提取:从电商网站提取商品名称、价格、图片链接和商品详情页URL,使用链式调用先定位商品卡片容器,再分别提取各个字段。

  • 场景2 - 表格数据提取:从网页表格中按行按列提取结构化数据。使用XPath的 //tr[position()>1] 跳过表头,逐行提取数据。

  • 场景3 - 正则提取数字:从混合文本(如"价格:¥199.90(原价¥299)")中使用正则表达式提取纯数字,用于价格比较和数据分析。

小贴士

在Scrapy Shell中可以使用 scrapy shell url 命令快速测试选择器。Shell模式下,response对象已经加载好,可以直接输入 response.css('...')response.xpath('...') 来验证提取结果,大幅提高开发效率。浏览器开发者工具的"检查元素"功能可以复制CSS Selector或XPath,但通常需要微调后才能用于Scrapy。

七、注意事项与最佳实践

注意1:CSS选择器使用 ::text 提取文本,使用 ::attr(name) 提取属性,这与jQuery的语法不同,需要特别注意。

注意2get() 在未找到匹配时返回 Nonegetall() 返回空列表。建议配合默认值使用,如 .get(default='')

注意3:CSS和XPath支持链式调用,先缩小范围再精确提取是最佳实践。例如先 response.css('div.product') 定位容器,再在其中提取各个字段。

注意4re() 方法只能用于已经提取到文本的Selector,不能直接对包含HTML标签的选择器使用正则。

八、练习题

练习1

编写程序,使用Selector从一个HTML页面中提取所有图片的 src 属性和 alt 属性,并以字典列表的形式返回结果,每个字典包含 srcalt 两个键。

练习2

编写程序,使用XPath从一个表格中提取所有偶数行(第2行、第4行...)的数据。使用XPath的 position() 函数和 mod 运算符实现偶数行筛选。


九、常见问题FAQ

常见问题

CSS选择器和XPath应该选择哪个?

对于简单的数据提取,CSS选择器语法更简洁易读;对于需要向上查找父元素、按文本内容过滤、使用复杂条件的场景,XPath更强大。两者可以混合使用,根据具体情况选择最合适的工具。

如何提取包含HTML标签的完整内容?

使用 .get() 会返回带HTML标签的完整内容,而 ::text 只返回纯文本。如果需要保留HTML结构(如富文本内容),不使用 ::text 即可。

如何处理动态加载的内容?

Scrapy只能获取服务器返回的初始HTML,无法执行JavaScript。对于动态加载的内容,可以使用 scrapy-splashscrapy-playwright 中间件来渲染JavaScript,或者分析API接口直接请求数据。

选择器提取结果为None怎么处理?

使用 .get(default='默认值') 设置默认值,或者在代码中进行None检查。页面结构变化是导致提取失败的最常见原因,建议定期验证选择器的有效性。

如何提取同一元素的多个属性?

先定位到元素,然后分别提取各个属性。例如 img = response.css('img'),然后 img.css('::attr(src)').get()img.css('::attr(alt)').get()。也可以使用XPath同时获取: .xpath('//@src | //@alt')

标签: Scrapy Selector CSS选择器 XPath 数据提取 Python爬虫 lxml

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Scrapy Pipeline详解 - 数据处理管道完整指南 下一篇: Scrapy中间件详解 - 下载器与爬虫中间件完整指南

poll相关推荐