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

举报
梦想橡皮擦 发表于 2022/02/15 15:59:01 2022/02/15
【摘要】 这篇博客补充一下 scrapy 选择器相关知识。 scrapy 选择器scrapy 框架自带数据提取机制,相关内容被称为选择器 seletors,其通过 XPath,CSS 表达式可以选择 HTML 中的指定部分。scrapy 选择器是基于 parsel 库实现的,该库也是一个解析库,底层使用的是 lxml,所以它的用法和效率都接近 lxml,在《爬虫 120 例》专栏后续部分,会针对性的补...

这篇博客补充一下 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 选择器不支持选择文本节点或者属性值,所以衍生出下述扩展写法。

  • 选择标签文本,使用 ::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 天。
期待 关注点赞评论收藏

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。