zoukankan      html  css  js  c++  java
  • 爬虫入门之Scrapy框架基础框架结构及腾讯爬取(十)

    Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据。

    如果安装了 IPython ,Scrapy终端将使用 IPython (替代标准Python终端)。 IPython 终端与其他相比更为强大,提供智能的自动补全,高亮输出,及其他特性。(推荐安装IPython)

    1 启动Scrapy Shell

    进入项目的根目录,执行下列命令来启动shell:

    scrapy shell "https://hr.tencent.com/position.php?&start=0#a"
    

    Scrapy Shell根据下载的页面会自动创建一些方便使用的对象,例如 Response 对象,以及Selector 对象 (对HTML及XML内容)

    • 当shell载入后,将得到一个包含response数据的本地 response 变量,输入response.body将输出response的包体,输出response.headers可以看到response的包头。
    • 输入response.selector时, 将获取到一个response 初始化的类 Selector 的对象,此时可以通过使用response.selector.xpath()response.selector.css()来对 response 进行查询。
    • Scrapy也提供了一些快捷方式, 例如response.xpath()response.css()同样可以生效(如之前的案例)。

    2 Selectors选择器

    Scrapy Selectors 内置 XPath 和 CSS Selector 表达式机制

    Selector有四个基本的方法,最常用的还是xpath:

    • xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表
    • extract(): 序列化该节点为Unicode字符串并返回list
    • css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表,语法同 BeautifulSoup4
    • re(): 根据传入的正则表达式对数据进行提取,返回Unicode字符串list列表
    response.xpath('//title')
    

    3 Item Pipeline

    当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item。

    每个Item Pipeline都是实现了简单方法的Python类,比如决定此Item是丢弃而存储。以下是item pipeline的一些典型应用:

    • 验证爬取的数据(检查item包含某些字段,比如说name字段)
    • 查重(并丢弃)
    • 将爬取结果保存到文件或者数据库中

    编写item pipeline很简单,item pipiline组件是一个独立的Python类,其中process_item()方法必须实现:

    import something
    
    class SomethingPipeline(object):
        def __init__(self):    
            # 可选实现,做参数初始化等
            # doing something
    
        def process_item(self, item, spider):
            # item (Item 对象) – 被爬取的item
            # spider (Spider 对象) – 爬取该item的spider
            # 这个方法必须实现,每个item pipeline组件都需要调用该方法,
            # 这个方法必须返回一个 Item 对象,被丢弃的item将不会被之后的pipeline组件所处理。
            return item
    
        def open_spider(self, spider):
            # spider (Spider 对象) – 被开启的spider
            # 可选实现,当spider被开启时,这个方法被调用 (也可以放在__init__方法中)
    
        def close_spider(self, spider):
            # spider (Spider 对象) – 被关闭的spider
            # 可选实现,当spider被关闭时,这个方法被调用 (也可放入析构函数__del__方法中)
    

    Pipeline实现文件的写入打开操作

    以下pipeline将所有(从所有'spider'中)爬取到的item,存储到一个独立地txt文件

    class TianyaPipeline(object):
        def __init__(self):
            self.f = open("tianya.txt", "w", encoding="utf-8")
        def process_item(self, item, spider):
            self.f.write(str(item))
            # return item
        def __del__(self):
            self.f.close()
    #附Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
    #replace用于替换指定字符
    #join用于合并列表 元组等
    

    启用一个Item Pipeline组件

    为了启用Item Pipeline组件,必须将它的类添加到 settings.py文件ITEM_PIPELINES 配置,就像下面这个例子:

    ITEM_PIPELINES = {
       'tianya.pipelines.TianyaPipeline': 300,
    }
    

    分配给每个类的整型值,确定了他们运行的顺序,item按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内(0-1000随意设置,数值越低,组件的优先级越高)

    4 Spider

    Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及分析某个网页(或者是有些网页)的地方。

    class scrapy.Spider是最基本的类,所有编写的爬虫必须继承这个类。

    主要用到的函数及调用顺序为:

    __init__(): 初始化爬虫名字和start_urls列表

    start_requests() 调用make_requests_from url():生成Requests对象交给Scrapy下载并返回response

    parse(): 解析response,并返回Item或Requests(需指定回调函数)。Item传给Item pipline持久化 , 而Requests交由Scrapy下载,并由指定的回调函数处理(默认parse()),一直进行循环,直到处理完所有的数据为止。

    源码参考

    #所有爬虫的基类,用户定义的爬虫必须从这个类继承
    class Spider(object_ref):
    
        #定义spider名字(string)。spider的名字定义了Scrapy如何定位(并初始化)spider,所以其必须是唯一的。
        #name是spider最重要的属性,而且是必须的。
        #一般做法是以该网站(domain)(加或不加 后缀 )来命名spider。例如,爬取百度命名为: baidu
        name = None
    
        #初始化,提取爬虫名字,start_ruls
        def __init__(self, name=None, **kwargs):
            if name is not None:
                self.name = name
            # 如果爬虫没有名字,中断后续操作则报错
            elif not getattr(self, 'name', None):
                raise ValueError("%s must have a name" % type(self).__name__)
    
            # python 对象或类型通过内置成员__dict__来存储成员信息
            self.__dict__.update(kwargs)
    
            #URL列表。当没有指定的URL时,spider将从该列表中开始进行爬取。 
            #因此,第一个被获取到的页面的URL将是该列表之一。后续的URL将会从获取到的数据中提取。
            if not hasattr(self, 'start_urls'):
                self.start_urls = []
    
        # 打印Scrapy执行后的log信息
        def log(self, message, level=log.DEBUG, **kw):
            log.msg(message, spider=self, level=level, **kw)
    
        # 判断对象object的属性是否存在,不存在做断言处理
        def set_crawler(self, crawler):
            assert not hasattr(self, '_crawler'), "Spider already bounded to %s" % crawler
            self._crawler = crawler
    
        @property
        def crawler(self):
            assert hasattr(self, '_crawler'), "Spider not bounded to any crawler"
            return self._crawler
    
        @property
        def settings(self):
            return self.crawler.settings
    
        #该方法将读取start_urls内的地址,并为每一个地址生成一个Request对象,交给Scrapy下载并返回Response
        #该方法仅调用一次
        def start_requests(self):
            for url in self.start_urls:
                yield self.make_requests_from_url(url)
    
        #start_requests()中调用,实际生成Request的函数。
        #Request对象默认的回调函数为parse(),提交的方式为get
        def make_requests_from_url(self, url):
            return Request(url, dont_filter=True)
    
        #默认的Request对象回调函数,处理返回的response。
        #生成Item或者Request对象。用户必须实现这个类
        def parse(self, response):
            raise NotImplementedError
    
        @classmethod
        def handles_request(cls, request):
            return url_is_from_spider(request.url, cls)
    
        def __str__(self):
            return "<%s %r at 0x%0x>" % (type(self).__name__, self.name, id(self))
    
        __repr__ = __str__
    

    主要属性和方法

    • name

      定义spider名字的字符串。

      例如,如果spider爬取 mywebsite.com ,该spider通常会被命名为 mywebsite

    • allowed_domains

      包含了spider允许爬取的域名(domain)的列表,可选。

    • start_urls

      初始URL元祖/列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。

    • start_requests(self)

      该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取(默认实现是使用 start_urls 的url)的第一个Request。

      当spider启动爬取并且未指定start_urls时,该方法被调用。

    • parse(self, response)

      当请求url返回网页没有指定回调函数时,默认的Request对象回调函数。用来处理网页返回的response,以及生成Item或者Request对象。

    • log(self, message[, level, component])

      使用 scrapy.log.msg() 方法记录(log)message。 更多数据请参见logging

    5 案例:腾讯招聘网自动翻页采集

    • 创建一个新的爬虫:

    scrapy genspider tencent "tencent.com"

    • 编写items.py

    获取职位名称、详细信息、

    class TencentItem(scrapy.Item):
        # 定义需要爬取的字段
        jobTitle = scrapy.Field()
        jobCategories = scrapy.Field()
        number = scrapy.Field()
        location = scrapy.Field()
        releasetime = scrapy.Field()
    
    • 编写tencent.py
    # -*- coding: utf-8 -*-
    import re
    import scrapy
    from Tencent import items
    
    class MytencentSpider(scrapy.Spider):
        name = 'myTencent'
        allowed_domains = ['hr.tencent.com']
        start_urls = ['https://hr.tencent.com/position.php?lid=2218&start=0#a']
    
        def parse(self, response):
            for data in response.xpath("//tr[@class="even"] | //tr[@class="odd"]"):
                item = items.TencentItem()
                item["jobTitle"] = data.xpath("./td[1]/a/text()")[0].extract()
                item["jobLink"] = data.xpath("./td[1]/a/@href")[0].extract()
                item["jobCategories"] = data.xpath("./td[1]/a/text()")[0].extract()
                item["number"] = data.xpath("./td[2]/text()")[0].extract()
                item["location"] = data.xpath("./td[3]/text()")[0].extract()
                item["releasetime"] = data.xpath("./td[4]/text()")[0].extract()
                yield item
    
                for i in range(1, 200):
                    newurl = "https://hr.tencent.com/position.php?lid=2218&start=%d#a" % (i*10)
                    yield scrapy.Request(newurl, callback=self.parse)
    
    • 编写pipeline.py文件
    class TencentPipeline(object):
        def __init__(self):
            self.file = open("tencent.txt", "w", encoding="utf-8")  #初始化即打开
    
        def process_item(self, item, spider):
            line = str(item) + "
    "
            self.file.write(line)
            self.file.flush()
            return item
    
        def __del__(self):  #数据清除时关闭
            self.file.close()
    
    • 在 setting.py 里设置ITEM_PIPELINES
    ITEM_PIPELINES = {
    	"mySpider.pipelines.TencentJsonPipeline":300
    }
    
    • 执行爬虫:

      scrapy crawl tencent.py

  • 相关阅读:
    Android 多渠道打包,上百渠道,秒打签名
    Failed to collect certificates from /data/app/vmdl201020547.tmp/base.apk: META-INF/CERT.SF indicates /data/app/vmdl201020547.tmp/base.apk is signed using APK Signature Scheme v2, but no such signature
    React java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/com.edaixi.activity/lib-main/libgnustl_shared.so" is 32-bit instead of 64-bit
    Effective Java 电子书 apk版本下载
    javascript数组遍历的几种常用方法性能分析对比
    微信小程序开发——列表分页上拉加载封装实现(订单列表为例,订单状态改变后刷新列表滚动位置不变)
    微信小程序开发——点击防重的解决方案
    微信小程序开发——点击按钮退出小程序的实现
    css选择器的优先级
    html页面的CSS、DIV命名规则(仅供参考学习)
  • 原文地址:https://www.cnblogs.com/why957/p/9271795.html
Copyright © 2011-2022 走看看