热榜、华为云博客都可用来练习Python scrapy 爬虫
这篇博客补充一下 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 选择器不支持选择文本节点或者属性值,所以衍生出下述扩展写法。
- 选择标签文本,使用
::text
; - 选择属性值,使用
::attr(attr_name)
。
测试代码如下所示:
>>> 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 选择器就会变得非常方面,只需要如下一行简短的代码即可。
*.someclass
其它补充说明
如果返回的数据中出现空格,可以使用 Selector
对象的 remove_namespaces()
方法去除空格。
选择器的使用,很多时候依赖于 XPath
表达式使用的熟练程度,该知识的基本学习,可以参考之前的一篇 博客。
这里补充一些高阶部分:
starts-with()
:判断开头内容;contains
:检测包含内容;re:text()
:可以在里面用正则;has-class
:判断是否包含某个class
;normalize-space
:去除前后空格。
写在后面
今天是持续写作的第 252 / 365 天。
期待 关注,点赞、评论、收藏。
- 点赞
- 收藏
- 关注作者
评论(0)