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

2022-02-21  本文已影响0人  梦想橡皮擦

这篇博客补充一下 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 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 选择器就会变得非常方面,只需要如下一行简短的代码即可。

*.someclass

其它补充说明

如果返回的数据中出现空格,可以使用 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>。

更多精彩

《爬虫 100 例,专栏销售中,买完就能学会系列专栏》
[图片上传失败...(image-4ebb62-1645406400184)]

<center>
↓ ↓ ↓ ↓一对一指导你的疑问↓ ↓ ↓ ↓</center>
<center>
↓↓↓扫码添加博主参加【78技术人社群】~Python分部↓↓↓</center>

上一篇下一篇

猜你喜欢

热点阅读