美文网首页
CSDN热榜、华为云博客都可用来练习Python scrapy

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

作者: 梦想橡皮擦 | 来源:发表于2022-02-21 09:20 被阅读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 选择器不支持选择文本节点或者属性值,所以衍生出下述扩展写法。

    • 选择标签文本,使用 ::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>。

    更多精彩

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

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

    相关文章

      网友评论

          本文标题:CSDN热榜、华为云博客都可用来练习Python scrapy

          本文链接:https://www.haomeiwen.com/subject/icbblrtx.html