Python爬虫框架Scrapy 学习笔记 7------- scrapy.Item源码剖析

在前面的example中,我们知道定义一个Item类很简单,只要继承scrapy.Item,然后添加几个类型为scrapy.Field的对象作为类属性,就像下面这样

import scrapy
class Product(scrapy.Item):
    name = scrapy.Field()
    price = scrapy.Field()
    stock = scrapy.Field()
    last_updated = scrapy.Field(serializer=str)

前面我们使用Item的方法也很简单,就像使用一个Dict一样来使用Item。例如在最初的那个spider中:

torrent = TorrentItem()
torrent[‘url‘] = response.url
torrent[‘name‘] = response.xpath("//h1/text()").extract()
torrent[‘description‘] = response.xpath("//div[@id=‘description‘]").extract()
torrent[‘size‘] = response.xpath("//div[@id=‘specifications‘]/p[2]/text()[2]").extract()

这里有几个问题:

  1. 上面的name, price, stock,last_updated真的是类属性吗?

2.  为什么可以像使用字典一样使用Item的实例 ?

3.   Filed有什么用?

按着ctrl键,鼠标放在scrapy.Item上,点进去,答案立马呈现在眼前。

item.py源码

"""
Scrapy Item

See documentation in docs/topics/item.rst
"""

from pprint import pformat
from UserDict import DictMixin

from scrapy.utils.trackref import object_ref

class BaseItem(object_ref):
    """Base class for all scraped items."""
    pass

class Field(dict):
    """Container of field metadata"""

class ItemMeta(type):

    def __new__(mcs, class_name, bases, attrs):
        fields = {}
        new_attrs = {}
        for n, v in attrs.iteritems():
            if isinstance(v, Field):
                fields[n] = v
            else:
                new_attrs[n] = v

        cls = super(ItemMeta, mcs).__new__(mcs, class_name, bases, new_attrs)
        cls.fields = cls.fields.copy()
        cls.fields.update(fields)
        return cls

class DictItem(DictMixin, BaseItem):

    fields = {}

    def __init__(self, *args, **kwargs):
        self._values = {}
        if args or kwargs:  # avoid creating dict for most common case
            for k, v in dict(*args, **kwargs).iteritems():
                self[k] = v

    def __getitem__(self, key):
        return self._values[key]

    def __setitem__(self, key, value):
        if key in self.fields:
            self._values[key] = value
        else:
            raise KeyError("%s does not support field: %s" %
                (self.__class__.__name__, key))

    def __delitem__(self, key):
        del self._values[key]

    def __getattr__(self, name):
        if name in self.fields:
            raise AttributeError("Use item[%r] to get field value" % name)
        raise AttributeError(name)

    def __setattr__(self, name, value):
        if not name.startswith(‘_‘):
            raise AttributeError("Use item[%r] = %r to set field value" %
                (name, value))
        super(DictItem, self).__setattr__(name, value)

    def keys(self):
        return self._values.keys()

    def __repr__(self):
        return pformat(dict(self))

    def copy(self):
        return self.__class__(self)

class Item(DictItem):

    __metaclass__ = ItemMeta

类Item继承了DictItem,类Item的类实例是由ItemMeta创建的。(关于Python元类的内容可以参考<<Python核心编程>>)

类DictItem模仿了dict的一些方法,并继承了DictMinx使它具有了类似字典的API

ItemMeta的__new__方法就做了两件事:1.将类型为scrapy.Field的属性放入字典fields中。2.将其它属性放入字典new_attrs中。

所以 name, price, stock,last_updated已经不再是类属性,而是被包含在了类属性fields中。

再看scrapy.Field到底是什么

class Field(dict):
    """Container of field metadata"""

不是别的,就是原原本本的dict,只不过换了个名字

Filed的作用是(见官方文档):

Field 对象指明了每个字段的元数据(metadata)。例如下面例子中 last_updated 中指明了该字段的序列化函数。

您可以为每个字段指明任何类型的元数据。 Field 对象对接受的值没有任何限制。也正是因为这个原因,文档也无法提供所有可用的元数据的键(key)参考列表。 Field 对象中保存的每个键可以由多个组件使用,并且只有这些组件知道这个键的存在。您可以根据自己的需求,定义使用其他的Field 键。 设置 Field 对象的主要目的就是在一个地方定义好所有的元数据。 一般来说,那些依赖某个字段的组件肯定使用了特定的键(key)。您必须查看组件相关的文档,查看其用了哪些元数据键(metadata key)。

官方文档:http://scrapy-chs.readthedocs.org/zh_CN/latest/topics/items.html

时间: 2024-10-18 15:34:15

Python爬虫框架Scrapy 学习笔记 7------- scrapy.Item源码剖析的相关文章

型学习笔记5:C源码理解

型学习笔记5:C源码理解 http://jfsqhwhat2.eju.cn/ http://13660038501.i.sohu.com/v2/guestbook/index.htm http://15306736050.i.sohu.com/v2/guestbook/index.htm http://15090269366.i.sohu.com/v2/guestbook/index.htm http://13377896359.i.sohu.com/v2/guestbook/index.htm

LDA主题模型学习笔记5:C源码理解

1,说明 本文对LDA原始论文的作者所提供的C代码中LDA的主要逻辑部分做注释,代码可在这里下载:https://github.com/Blei-Lab/lda-c 这份代码实现论文<Latent Dirichlet Allocation>中介绍的LDA模型,用变分EM算法求解参数. 为了使代码在vs2013中运行做了一些微小改动,但不影响原代码的逻辑. vs2013工程可在我的资源中下载: http://download.csdn.net/detail/happyer88/8861773 -

Bootstrap学习笔记上(带源码)

做好笔记方便日后查阅o(╯□╰)o bootstrap简介: ?  简单灵活可用于架构流行的用户界面和交互接口的html.css.javascript工具集. ?  基于html5.css3的bootstrap,具有大量的诱人特性:友好的学习曲线,卓越的兼容性,响应式设计,12列格网,样式向导文档. ?  自定义JQuery插件,完整的类库,基于Less等. bootstrap模板为使IE6.7.8版本(IE9以下版本)浏览器兼容html5新增的标签,引入下面代码文件即可. <script sr

Android(java)学习笔记203:网页源码查看器

1.项目框架图: 2.首先是布局文件activity_main.xml: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="m

Junit学习笔记(二): 源码分析(1)

使用ModelGoon画出来的UML图如下: 图中可以分析出: 1)Test是一个接口,TestSuit和TestCase,JUnit4TestAdapter,JUnit4TestCaseFacade都实现了Test类,这一种命令模式,只需要使用Test接口就可以使用到具体的类: 2)JUnit4TestAdapter是适配器, Filterable实现了对用例的过滤, Sortable实现了对用例的排序(按照字母进行排序): 3)TestResult实现了返回结果,TestFailure记录失

【学习笔记-集合】HashMap 源码浅析

/** * HashMap主要方法解析,jdk1.7版本的HashMap * 一.构造 * 4个构造相对之前的jdk版本功能基本不变,但是代码封装更完善. * 构造前一个参数是容量,相当于数组大小,后一个是负载因子 */ public HashMap(int initialCapacity, float loadFactor) { //当初始容量<0,抛出异常非法的参数容量 if (initialCapacity < 0) throw new IllegalArgumentException(

Junit学习笔记(二): 源码分析(2)-命令和组合模式

命令模式 命令模式的优点: 命令模式将调用操作的对象与如何实现该操作的对象解耦. 将命令当成一个头等对象,它们可以像一般对象那样进行操纵和扩展 可以将多个命令复合成一个命令,与Composite模式结合使用 增加新的命令很容易,隔离对现有类的影响 可以与备忘录模式配合,实现撤销功能. 命令模式图: 由此带来的好处:1.客户无需使用任何条件语句去判断测试的类型,可以用统一的方式调用测试和测试套件,解除了客户与具体测试子类的耦合2.如果要增加新的TestCase也很容易,实现Test接口即可,不会影

教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神

欢迎加入Python学习交流群:535993938  禁止闲聊 ! 名额有限 ! 非喜勿进 ! 本博文将带领你从入门到精通爬虫框架Scrapy,最终具备爬取任何网页的数据的能力.本文以校花网为例进行爬取,校花网:http://www.xiaohuar.com/,让你体验爬取校花的成就感. Scrapy,Python开发的一个快速,高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据.Scrapy用途广泛,可以用于数据挖掘.监测和自动化测试. Scrapy吸引人的地方在于

教你分分钟学会用python爬虫框架Scrapy爬取你想要的内容

教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神 python爬虫学习课程,下载地址:https://pan.baidu.com/s/1v6ik6YKhmqrqTCICmuceug 课程代码原件:课程视频: 原文地址:http://blog.51cto.com/aino007/2123341