写点什么

CSDN 热榜、华为云博客都可用来练习 Python scrapy 爬虫

作者:梦想橡皮擦
  • 2021 年 12 月 13 日
  • 本文字数:3084 字

    阅读完需:约 10 分钟

这篇博客补充一下 scrapy 选择器相关知识。

scrapy 选择器

scrapy 框架自带数据提取机制,相关内容被称为选择器 seletors,其通过 XPathCSS 表达式可以选择 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 scrapyfrom 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) ,或者提供一个默认值。


# 判断是否为 Noneresponse.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:去除前后空格。

写在后面

今天是持续写作的第 <font color=red>252</font> / 365 天。期待 <font color=#04a9f4>关注</font>,<font color=#04a9f4>点赞</font>、<font color=#04a9f4>评论</font>、<font color=#04a9f4>收藏</font>。


发布于: 13 小时前阅读数: 5
用户头像

爬虫 100 例作者,蓝桥签约作者,博客专家 2021.02.06 加入

6 年产品经理+教学经验,3 年互联网项目管理经验; 互联网资深爱好者; 沉迷各种技术无法自拔,导致年龄被困在 25 岁; CSDN 爬虫 100 例作者。 个人公众号“梦想橡皮擦”。

评论

发布
暂无评论
CSDN热榜、华为云博客都可用来练习Python scrapy 爬虫