scrapy 源碼閱讀筆記(1)-- Spider

數(shù)據(jù)流向

關(guān)于Spider

在我看來珊楼,Spider主要負(fù)責(zé)Request的生成,和Response的處理(解析)度液。不過除了這兩個功能外厕宗,如果想在多場景下合理定制Spider画舌,必須對每一個屬性/方法都有所了解(最好閱讀源代碼)。一下是我的一些總結(jié)已慢。(必須是指就流程而言)

屬性方法 功能 必須 描述
name id scrapy識別spider的id
start_urls 種子 scrapy推薦的爬蟲入口
allowd_doamins 正則 過濾非匹配url
custom_settings 參數(shù) 對于每個spider獨(dú)有的配置參數(shù)
crawler 交互 綁定spider曲聂,與engine交互
settings 配置 導(dǎo)入?yún)?shù)
logger 日志 直接來自python標(biāo)準(zhǔn)庫
from_crawler 實(shí)例化入口 scrapy風(fēng)格的實(shí)例化入口
start_requests 初始化 scrapy推薦的初始Request生成器
make_requests_from_url 構(gòu)造Request, dont_filter
parse 解析 Request的callback,返回Item或者Request
log 日志 封裝logger
close 信號處理 可定制佑惠,處理spider_closed信號

分析

  • parse(response)
    作為Request的回掉函數(shù)朋腋,功能簡單,邏輯清晰膜楷,不過大概是 開發(fā) 最費(fèi)時的一步旭咽,也非常容易把代碼寫丑。歸根結(jié)底是 解析字段數(shù)據(jù)清洗 的復(fù)雜赌厅。

scrapy推薦的做法是將解析/清洗方案抽象出來穷绵,利用Itemloader導(dǎo)入,代碼可以異常簡潔特愿。我正在計(jì)劃仲墨,將字段定義/解析規(guī)則/清晰規(guī)則序列化到數(shù)據(jù)庫,每次針對url的特征(例如domain洽议,path),進(jìn)行選擇宗收。

  • crawler
    了解scrapy如何運(yùn)作,躲不開河玩意兒亚兄。scrapy具有模塊化的特征混稽,但在很多模塊/插件初始化的時候都通過crawler導(dǎo)入settings;你想在后臺調(diào)用spider审胚,也需要對crawler有所了解匈勋。在我看來,crawler就是用來管理Spider膳叨,封裝了spider初始化洽洁,啟動,終止的api菲嘴。如果足夠好奇饿自,仔細(xì)看看scrapy.crawler.CrawlerProcess。俺3個月前第一次嘗試將scrapy掛到flask上時差點(diǎn)被搞死(關(guān)于twisted的一堆報(bào)錯)龄坪。

提示:單獨(dú)開進(jìn)程執(zhí)行昭雌。

  • from_crawler(crawler, *args, **kwargs)
    scrapy 推薦的代碼風(fēng)格,用于實(shí)例化某個對象(中間件健田,模塊)

"This is the class method used by Scrapy to create your spiders". crawler 常常出現(xiàn)在對象的初始化烛卧,負(fù)責(zé)提供crawler.settings

  • close
    從scrapy的風(fēng)格來看,是一個 異步信號處理器 妓局。更常見的方案是在from_settings 中利用信號(Signal)和指定方法關(guān)聯(lián)总放。使用它可以做一些有趣的事兒呈宇,比如在爬蟲終止時給自己發(fā)一封郵件;定時統(tǒng)計(jì)爬蟲的進(jìn)展局雄。
    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(Filter, cls).from_crawler(crawler, *args, **kwargs)
        crawler.signals.connect(spider.spider_closed, signal=signals.spider_opened)
        crawler.signals.connect(spider.spider_closed, signal=signals.spider_closed)
        return spider
  • other spider
    scrapy還維護(hù)了 CrawlSpider, XMLFeedSpider, SitemapSpider. 大致就是簡單修改了Respone的處理規(guī)則, Request的過濾甥啄。相較于不同的Spider設(shè)計(jì), 大家或許會對FormRequest感興趣, 用于提交表單比較方便。

后續(xù)跟進(jìn)

  1. 核心模塊, Scheduler, Engine, Downloader, Item Pipeline, MiddleWare

關(guān)于每個核心模塊都會記錄閱讀經(jīng)驗(yàn)/筆記, 并交流一些重載方案

  1. 處理javascript, 處理ajax

處理javascript可以用scrapy_splash的方案哎榴;雖然說splash看起來很雜糅型豁,但尼瑪效率高,并發(fā)渲染js尚蝌。作為對比, phantomjs webserver支持10個并發(fā), 也足夠強(qiáng)迎变。但就是不想去造輪子。

  1. “智能處理”Response

用流行的詞兒來說就是 data-driven programming飘言。之前提到 抽象解析方案 就是一個例子衣形。不過對這方面的概念還比較模糊

  1. 分布式爬蟲

scrapy官方也維護(hù)了分布式爬蟲的版本--frontera--集成了scheduler, strategy, backend api, message bus, 可以與任意下載器匹配使用,也可以使用frontera中的scrapy wrapper姿鸿,只需更改配置文件就可以穩(wěn)定運(yùn)行谆吴。

scrapy.spider.Spider

"""
Base class for Scrapy spiders

See documentation in docs/topics/spiders.rst
"""
import logging
import warnings

from scrapy import signals
from scrapy.http import Request
from scrapy.utils.trackref import object_ref
from scrapy.utils.url import url_is_from_spider
from scrapy.utils.deprecate import create_deprecated_class
from scrapy.exceptions import ScrapyDeprecationWarning


class Spider(object_ref):
    """Base class for scrapy spiders. All spiders must inherit from this
    class.
    """

    name = None
    custom_settings = None

    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__)
        self.__dict__.update(kwargs)
        if not hasattr(self, 'start_urls'):
            self.start_urls = []

    @property
    def logger(self):
        logger = logging.getLogger(self.name)
        return logging.LoggerAdapter(logger, {'spider': self})

    def log(self, message, level=logging.DEBUG, **kw):
        """Log the given message at the given log level

        This helper wraps a log call to the logger within the spider, but you
        can use it directly (e.g. Spider.logger.info('msg')) or use any other
        Python logger too.
        """
        self.logger.log(level, message, **kw)

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = cls(*args, **kwargs)
        spider._set_crawler(crawler)
        return spider

    def set_crawler(self, crawler):
        warnings.warn("set_crawler is deprecated, instantiate and bound the "
                      "spider to this crawler with from_crawler method "
                      "instead.",
                      category=ScrapyDeprecationWarning, stacklevel=2)
        assert not hasattr(self, 'crawler'), "Spider already bounded to a " \
                                             "crawler"
        self._set_crawler(crawler)

    def _set_crawler(self, crawler):
        self.crawler = crawler
        self.settings = crawler.settings
        crawler.signals.connect(self.close, signals.spider_closed)

    def start_requests(self):
        for url in self.start_urls:
            yield self.make_requests_from_url(url)

    def make_requests_from_url(self, url):
        return Request(url, dont_filter=True)

    def parse(self, response):
        raise NotImplementedError

    @classmethod
    def update_settings(cls, settings):
        settings.setdict(cls.custom_settings or {}, priority='spider')

    @classmethod
    def handles_request(cls, request):
        return url_is_from_spider(request.url, cls)

    @staticmethod
    def close(spider, reason):
        closed = getattr(spider, 'closed', None)
        if callable(closed):
            return closed(reason)

    def __str__(self):
        return "<%s %r at 0x%0x>" % (type(self).__name__, self.name, id(self))

    __repr__ = __str__
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市苛预,隨后出現(xiàn)的幾起案子句狼,更是在濱河造成了極大的恐慌,老刑警劉巖热某,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腻菇,死亡現(xiàn)場離奇詭異,居然都是意外死亡昔馋,警方通過查閱死者的電腦和手機(jī)筹吐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秘遏,“玉大人丘薛,你說我怎么就攤上這事“钗#” “怎么了洋侨?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長倦蚪。 經(jīng)常有香客問我凰兑,道長,這世上最難降的妖魔是什么审丘? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮勾给,結(jié)果婚禮上滩报,老公的妹妹穿的比我還像新娘锅知。我一直安慰自己,他們只是感情好脓钾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布售睹。 她就那樣靜靜地躺著,像睡著了一般可训。 火紅的嫁衣襯著肌膚如雪昌妹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天握截,我揣著相機(jī)與錄音飞崖,去河邊找鬼。 笑死谨胞,一個胖子當(dāng)著我的面吹牛固歪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胯努,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼牢裳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了叶沛?” 一聲冷哼從身側(cè)響起蒲讯,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎灰署,沒想到半個月后判帮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氓侧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年脊另,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片约巷。...
    茶點(diǎn)故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡偎痛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出独郎,到底是詐尸還是另有隱情踩麦,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布氓癌,位于F島的核電站谓谦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贪婉。R本人自食惡果不足惜反粥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧才顿,春花似錦莫湘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尾组,卻和暖如春忙芒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背讳侨。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工呵萨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人甘桑。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像咆耿,于是被迫代替她去往敵國和親德谅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容