这篇博客补充一下 scrapy
选择器相关知识。
scrapy 选择器
scrapy 框架自带数据提取机制,相关内容被称为选择器 seletors
,其通过 XPath
,CSS
表达式可以选择 HTML 中的指定部分。
scrapy
选择器是基于 parsel
库实现的,该库也是一个解析库,底层使用的是 lxml
,所以它的用法和效率都接近 lxml
,在《爬虫 120 例》专栏后续部分,会针对性的补充一下该库相关知识点。
selectors 基本使用
本次学习过程中,使用 CSDN 的 专栏排行榜 进行测试。
选择器对象,可以直接通过 response 对象调用
import scrapy
class CSpider(scrapy.Spider):
name = 'c'
allowed_domains = ['csdn.net']
start_urls = ['https://blog.csdn.net/rank/list/column']
def parse(self, response):
# 选择器对象,可以直接通过 response 对象调用
print(response.selector)
复制代码
由于 XPath 和 CSS 选择器经常被使用,所以使用 response
对象可以直接调用这两个方法,例如:
def parse(self, response):
# 选择器对象,可以直接通过 response 对象调用
# print(response.selector)
response.xpath("XPath 表达式")
response.css("CSS 表达式")
复制代码
如果你查看上述两个方法的源码会发现,其核心还是调用的 selector
对象的相关方法。源码查阅
def xpath(self, query, **kwargs):
return self.selector.xpath(query, **kwargs)
def css(self, query):
return self.selector.css(query)
复制代码
在代码的编写过程中,使用 response
对象的方法可以满足大多数需求,但 selector
也适用于部分特殊场景,例如从本地文件读入一段 HTML 代码:
import scrapy
from scrapy.selector import Selector
class CSpider(scrapy.Spider):
name = 'c'
allowed_domains = ['csdn.net']
start_urls = ['https://blog.csdn.net/rank/list/column']
def parse(self, response):
body ="""
<html>
<head>
<title>这是一个标题</title>
</head>
<body>
这是内容
</body>
</html>
"""
# 实例化 Selector 对象,并调用 xpath 方法
ret = Selector(text=body).xpath("//title").get()
print(ret)
复制代码
通过 scrapy 命令行学习 selectors
使用下述命令进入匹配模式,案例使用的是华为云博客地址,https://bbs.huaweicloud.com/blogs。
> scrapy shell https://bbs.huaweicloud.com/blogs
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x0000000004E64320>
[s] item {}
[s] request <GET bbs.huaweicloud.com/blogs>
[s] response <200 bbs.huaweicloud.com/blogs>
[s] settings <scrapy.settings.Settings object at 0x0000000004E640F0>
[s] spider <CSpider 'c' at 0x5161080>
[s] Useful shortcuts:
[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s] fetch(req) Fetch a scrapy.Request and update local objects
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser
>>>
复制代码
此时如果输入 response
,就可以得到对应的对象。
>>> response
<200 bbs.huaweicloud.com/blogs>
>>>
复制代码
尝试获取网页标题
>>> response.xpath("//title")
[<Selector xpath='//title' data='<title>华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华...'>]
>>> response.xpath("//title/text()")
[<Selector xpath='//title/text()' data='华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云'>]
>>>
复制代码
由于得到的数据是序列,所以通过下述方法进行提取。
>>> response.xpath("//title/text()").get()
'华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云'
>>> response.xpath("//title/text()").getall()
['华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云']
>>>
复制代码
获取网页的 title
属性意义不大,接下来获取一下网页中的博客标题。
>>> response.xpath("//a[@class='blogs-title two-line']/@title").get()
'AppCube实践之标准页面开发丨【玩转应用魔方】'
>>> response.xpath("//a[@class='blogs-title two-line']/@title").getall()
['AppCube实践之标准页面开发丨【玩转应用魔方】', '鸿蒙轻内核M核源码分析系列十七(3) 异常信息ExcInfo', '1024征集令——【有奖征文】玩转应用魔方,玩转低代码构建平台', '前端需要写自动化测试吗','''''内容省略]
复制代码
此时你应该已经注意到,想要提取 Selector 对象中的内容,需要使用 get()
和 getall()
方法,它们分别返回单一元素和多个元素。
CSS 选择器除了选择器部分语法外,与 xpath()
方法一致,返回的都是 SelectorList
对象。该对象与 Selector
对象一样,也存在自己的实例方法,例如 xpath()
,css()
,getall()
,get()
,re()
,re_first()
,以及 attrib
属性。
还有一点需要注意 get()
方法,存在一个别名 extract_first()
,也经常被开人人员使用。
在使用 get()
方法时,如果标签没有被查找到,可以判断是否为 None(是返回 True) ,或者提供一个默认值。
# 判断是否为 None
response.xpath("//a[@class='blogs-title']/@title").get() is None
# 提供一个默认值
>>> response.xpath("//a[@class='blogs-title']/@title").get(default='无数据')
'无数据'
复制代码
上述的 title
属性也可以不使用 @title
,而用对象的 attrib
属性获取,下述代码将获取匹配到的第一个元素的所有属性。
>>> response.xpath("//a[@class='blogs-title two-line']").attrib
复制代码
CSS 选择器注意以下事项
CSS 选择器不支持选择文本节点或者属性值,所以衍生出下述扩展写法。
测试代码如下所示:
>>> response.css("a.two-line::text")
>>> response.css("a.two-line::attr(title)")
复制代码
在上面的文章中,你是否注意到 re()
方法
使用 re()
方法,可以将正则作用于提取结果,例如在提取到的所有标题中,匹配 鸿蒙 二字开头的数据。
>>> response.xpath("//a[@class='blogs-title two-line']/@title").re(r'鸿蒙.*')
['鸿蒙轻内核M核源码分析系列十七(3) 异常信息ExcInfo']
复制代码
XPath 和 CSS 的一个使用场景差异如果网页某个元素的 class
属性特别多,那使用 XPath 会变得不方便,CSS 选择器更加适合这种场景。如果用 XPath 模糊匹配,就会出现下述代码:
*[contains(concat(' ', normalize-space(@class), ' '), ' someclass ')]
复制代码
这种情况下 CSS 选择器就会变得非常方面,只需要如下一行简短的代码即可。
其它补充说明
如果返回的数据中出现空格,可以使用 Selector
对象的 remove_namespaces()
方法去除空格。
选择器的使用,很多时候依赖于 XPath
表达式使用的熟练程度,该知识的基本学习,可以参考之前的一篇 博客。
这里补充一些高阶部分:
写在后面
今天是持续写作的第 <font color=red>252</font> / 365 天。期待 <font color=#04a9f4>关注</font>,<font color=#04a9f4>点赞</font>、<font color=#04a9f4>评论</font>、<font color=#04a9f4>收藏</font>。
评论