自己寫python爬蟲框架(一)

前言

作為一個爬蟲框架,與其他爬蟲差異為:靈活擴展以及入門簡單

整體架構(gòu)

image
  • 調(diào)度器
    從請求管理器中取請求,然后調(diào)用下載器進行下載,調(diào)度解析器進行解析蝶锋,對解析出的請求再次加入到請求管理器中;解析出的數(shù)據(jù)進行緩存什往,最后寫入到文本中
    調(diào)度器為爬蟲框架的核心扳缕,也是爬蟲的入口,其成員變量為下載器、解析器躯舔、請求管理器驴剔、文件寫入類、日志類粥庄,對于不同的爬蟲需求丧失,可以對以上接口有不同的實現(xiàn)。
    核心方法:
    從請求管理器中取用 request,采用模板設(shè)計模式惜互,不可被子類重寫
def run(self, request):
    '''
    運行爬蟲方法布讹,從requestManager中取出可用的request,然后扔進下載器中進行下載训堆,通過解析器對下載到的文檔進行解析描验;
    需要傳入一個或者一組request作為初始request進行抓取

        @param :: request : Request類型請求
        return : None
    '''
    self.__start_icon()
    self.__logger.info('\tStart crawl...')
    self.__requestManager.add_new_request(request)
    while self.__requestManager.has_new_request():
        request = self.__requestManager.get_new_request()
        print(request.__dict__)
        self.crawl(request)
    self.__logger.info('\tEnd crawl...')
  • 調(diào)度下載器與解析器,可被子類繼承擴展坑鱼,可擴展為多線程膘流、多進程等
def crawl(self, request):
    '''
    對request進行請求進行爬取并解析結(jié)果的運行單元,子類可對該方法重寫進行多線程鲁沥、多進程運行或異步抓取與解析呼股;也可裝飾該方法,進行多線程画恰、多進程抓取彭谁。
    下載器對傳入的request進行下載,解析器解析下載到的文檔阐枣,并將解析出的request扔進requestManager中進行管理马靠,以進行深度爬取蔼两;將解析出的data扔進writter中,將數(shù)據(jù)存儲到磁盤上

        @param :: request : Request類型請求
        return None
    '''
    try:
        self.__logger.info('\t'+request.url)
        response = self.__downloader.download(request)
        if response.status_code == 200:
            requests, data = self.__parser.parse(response)
            self.__requestManager.add_new_requests(requests)
            self.__writter.write_buffer(data)
        else:
            self.__logger.warn(
                'crawled data is None and response_status is ' + str(response.status_code))
    except Exception as e:
        self.__logger.exception('\tCrawling occurs error\n' + e.__repr__())

  • 下載器
    對傳入的請求進行請求下載
    抽象方法:
def download(self, request):
  '''
  對request進行請求下載逞度,需要將請求到的response返回

      @param :: request : 請求對象
      return response
  '''
  raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
      self.__class__.__name__, get__function_name()))

  • 解析器
    對傳入的文本進行解析
    抽象方法:
def parse(self, response):
    '''
    對response進行解析额划,需要將解析到的requests與data返回

        @param :: response : 響應(yīng)對象
        return requests,data
    '''
    raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
        self.__class__.__name__, get__function_name()))

  • 請求管理器
    管理所有的請求
    抽象方法:
def add_new_requests(self, requests):
    '''
    模板方法,不需要子類重寫
    添加requests序列到requestManager中進行管理

        @param :: requests : request對象列表
        return None
    '''
    for request in requests:
        self.add_new_request(request)

def add_new_request(self, request):
    '''
    添加request對象到requestManager中進行管理

        @param :: request : request對象
        return None
    '''
    raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
        self.__class__.__name__, get__function_name()))

def has_new_request(self):
    '''
    判斷requestManager中是否還有新的請求档泽,返回布爾類型結(jié)果

        return Bool
    '''
    raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
        self.__class__.__name__, get__function_name()))

def get_new_request(self):
    '''
    從requestManager中取新的請求

        return request
    '''
    raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
        self.__class__.__name__, get__function_name()))
  • 數(shù)據(jù)寫入類
    將數(shù)據(jù)以特定格式寫入到磁盤中
    抽象方法:
def write(self, data):
     '''
     將數(shù)據(jù)data寫入磁盤

         return None
     '''
     raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
         self.__class__.__name__, get__function_name()))

 def write_buffer(self, data):
     '''
     緩存數(shù)據(jù)

         return None
     '''
     raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
         self.__class__.__name__, get__function_name()))

 def flush_buffer(self):
     '''
     刷新緩存數(shù)據(jù)到磁盤上

         return None
     '''
     raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
         self.__class__.__name__, get__function_name()))

  • 日志
    記錄爬蟲運行
    抽象方法:
def debug(self, message):
    '''
    debug級別日志
    '''
    raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
        self.__class__.__name__, get__function_name()))

def info(self, message):
    '''
    info級別日志
    '''
    raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
        self.__class__.__name__, get__function_name()))

def warn(self, message):
    '''
    warn級別日志
    '''
    raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
        self.__class__.__name__, get__function_name()))

def exception(self, message):
    '''
    exception級別日志
    '''
    raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
        self.__class__.__name__, get__function_name()))

def error(self, message):
    '''
    error級別日志
    '''
    raise NotImplementedError("未實現(xiàn)的父類方法: %s.%s" % (
        self.__class__.__name__, get__function_name()))

設(shè)計思想

在 Abstract Factory 模式為將’抽象零件’組裝為’抽象產(chǎn)品’俊戳,因此對于下載器、解析器馆匿、請求管理器抑胎、數(shù)據(jù)寫入類、日志類僅是限定其抽象接口渐北,在調(diào)度器中分別調(diào)用其每個零件的具體實現(xiàn)阿逃。

調(diào)度器則參照了模板方法設(shè)計模式,將開始爬取方法(startcrawl)固定,對于調(diào)度器的多線程多進程擴展可繼承該調(diào)度器恃锉,并重寫調(diào)度爬取方法(crawl)搀菩,提供多線程多進程爬取方法

在爬蟲整體框架設(shè)計中,主體未調(diào)度器破托、下載器肪跋、解析器、請求管理器土砂、數(shù)據(jù)寫入類州既、日志類,滿足了基本爬蟲的需求萝映,在實際中爬蟲進行爬取數(shù)據(jù)時吴叶,需要設(shè)置網(wǎng)絡(luò)代理、設(shè)置不同的 cookie 身份锌俱、以及分布式爬取調(diào)度任務(wù)等晤郑,可對以上基本組件運用裝飾者模式進行裝飾,已達到擴展功能的需求

小白文章贸宏,還請各位多多請教造寝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吭练,隨后出現(xiàn)的幾起案子诫龙,更是在濱河造成了極大的恐慌,老刑警劉巖鲫咽,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件签赃,死亡現(xiàn)場離奇詭異,居然都是意外死亡分尸,警方通過查閱死者的電腦和手機锦聊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來箩绍,“玉大人孔庭,你說我怎么就攤上這事〔闹耄” “怎么了圆到?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長卑吭。 經(jīng)常有香客問我芽淡,道長,這世上最難降的妖魔是什么豆赏? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任挣菲,我火速辦了婚禮富稻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘己单。我一直安慰自己唉窃,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布纹笼。 她就那樣靜靜地躺著纹份,像睡著了一般。 火紅的嫁衣襯著肌膚如雪廷痘。 梳的紋絲不亂的頭發(fā)上蔓涧,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機與錄音笋额,去河邊找鬼元暴。 笑死,一個胖子當(dāng)著我的面吹牛兄猩,可吹牛的內(nèi)容都是我干的茉盏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼枢冤,長吁一口氣:“原來是場噩夢啊……” “哼鸠姨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起淹真,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤讶迁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后核蘸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體巍糯,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年客扎,在試婚紗的時候發(fā)現(xiàn)自己被綠了祟峦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡徙鱼,死狀恐怖搀愧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疆偿,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布搓幌,位于F島的核電站杆故,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏溉愁。R本人自食惡果不足惜处铛,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一饲趋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撤蟆,春花似錦奕塑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至讨衣,卻和暖如春换棚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背反镇。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工固蚤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人歹茶。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓夕玩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親惊豺。 傳聞我的和親對象是個殘疾皇子燎孟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,573評論 2 353

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