Python爬蟲之scrapy高級(jí)(全站爬取,分布式,增量爬蟲)

1 scrapy全站爬取

1.1 全站爬取簡(jiǎn)介

CrawlSpider:全站數(shù)據(jù)爬蟲的方式本昏,它是一個(gè)類供汛,屬于Spider的子類
如果不使用CrawlSpider,那么就相當(dāng)于基于spider涌穆,手動(dòng)發(fā)送請(qǐng)求怔昨,太不方便
基于CrawlSpider可以很方便地進(jìn)行全站數(shù)據(jù)爬取

1.2 CrawlSpider

1.2.1 基本講解

基本步驟:

  • 創(chuàng)建一個(gè)工程:scrapy startproject ProjectName
  • 切換到爬蟲工程中后,創(chuàng)建爬蟲文件:scrapy genspider -t crawl xxx www.xxx.com

使用CrawlSpiderspider產(chǎn)生的爬蟲文件除了繼承類不一樣外還有一個(gè)rules的規(guī)則解析器

 rules = (
        Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    )

rules規(guī)則解析器內(nèi)有一個(gè)鏈接提取器LinkExtractor(allow=r'Items/')蒲犬,callback是規(guī)則解析器指定的解析方法朱监,follow是指爬取頁(yè)面內(nèi)可見部分頁(yè)面還是全部

頁(yè)面內(nèi)可見部分頁(yè)面如下:

在這里插入圖片描述

鏈接提取器作用:根據(jù)指定的規(guī)則allow=r'Items/'進(jìn)行指定的鏈接的提取
規(guī)則解析器作用:把鏈接提取器提取到的鏈接進(jìn)行指定規(guī)則callback='parse_item'的解析操作
follow作用:True可以把 ==鏈接提取器== 繼續(xù)作用到 鏈接提取器提取到的鏈接所對(duì)應(yīng)的 頁(yè)面 中,False爬取頁(yè)面內(nèi)可見部分頁(yè)面

1.2.2 使用CrawlSpider

1.2.2.1 爬蟲文件

使用CrawlSpider生成爬蟲文件時(shí)原叮,在規(guī)則解析器rules里面添加正則表達(dá)式進(jìn)而發(fā)起請(qǐng)求赫编,如果要一個(gè)請(qǐng)求內(nèi)需要再次發(fā)起請(qǐng)求巡蘸,就需要在rules中添加鏈接請(qǐng)求并指定對(duì)應(yīng)的解析方法

注意xpath中最好不要出現(xiàn)tbody標(biāo)簽

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule

from sunPro.items import SunproItem,DetailItem
class SunSpider(CrawlSpider):
    name = 'sun'#爬蟲文件名
    # allowed_domains = ['www.xxx.com']#允許的url
    start_urls = ['http://dk.test.com/mail/?ac=list&tid=1']#url列表
  
    #規(guī)則解析器 
    rules = (
      #LinkExtractor(allow=r'Items/')連接提取器,就是用來提取連接擂送,根據(jù)指定規(guī)則(allow=r'Items/')進(jìn)行指定連接的提取
        Rule(LinkExtractor(allow=r'ac=list&tid=1&order=1&page=\d+'), callback='parse_item', follow=False),
        #獲取詳情信息
        Rule(LinkExtractor(allow=r'ct=index&ac=detail&id=\d+'), callback='parse_detail', follow=False),
    )
 
    def parse_item(self, response):
        tr_list=response.xpath('/html/body/table[2]//tr/td/table//tr[3]/td/table//tr/td[1]/table//tr/td/table//tr[1]/td/div/table//tr[@bgcolor="#FFFFFF"]')
        # print(tr_list)
        for tr in tr_list:
            news_num = tr.xpath('./td[1]/text()').extract_first()
            news_title = tr.xpath('./td[2]/a/text()').extract_first()
            print(news_num,news_title)
            """ item=SunproItem()
            item['news_title']=news_title
            item['news_num']=news_num
            yield item """
        
    def parse_detail(self,response):
        news_id=response.xpath('/html/body/table[2]//tr/td/table//tr[3]/td/table//tr/td[1]/table//tr[1]/td/table//tr/td/table//tr[2]/td/table//tr[1]/td[1]/span/text()').extract_first()
        news_content=response.xpath('/html/body/table[2]//tr/td/table//tr[3]/td/table//tr/td[1]/table//tr[1]/td/table//tr/td/table//tr[3]/td/table//tr[1]/td/table//tr[2]/td//text()').extract()
        news_content=''.join(news_content)
        item=DetailItem()
        item['news_id']=news_id
        item['news_content']=news_content
        yield item

1.2.2.2 items.py文件

由于不能發(fā)送請(qǐng)求時(shí)傳參因此悦荒,需要兩個(gè)item類文件

import scrapy

class SunproItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    news_title=scrapy.Field()    
    news_num=scrapy.Field()
    

class DetailItem(scrapy.Item):
    news_id=scrapy.Field()
    news_content=scrapy.Field()

2 分布式爬蟲

2.1 分布式爬蟲概念

分布式爬蟲:需要搭建一個(gè)分布式的集群,讓其對(duì)一組資源進(jìn)行分布聯(lián)合爬取嘹吨,主要是為了提升爬取數(shù)據(jù)效率

2.2 環(huán)境安裝

安裝一個(gè)scrapy-redis的組件:pip install scrapy-redis搬味,由于原生的scrapy不可以失效分布式爬蟲,必須讓scrapy結(jié)合scrapy-redis組件一起實(shí)現(xiàn)分布式爬蟲
那么為什么原生scrapy不可以實(shí)現(xiàn)分布式蟀拷?

  • 調(diào)度器不可以被分布式集群共享
  • 管道不可以被分布式集群共享

但是scrapy-redis組件可以提供共享的管道和調(diào)度器

2.3 使用方法

2.3.1 CrawlSpider配置

基本使用步驟:

  • 創(chuàng)建基于CrawlSpider的爬蟲文件碰纬,修改爬蟲文件

導(dǎo)包:from scrapy_redis.spiders import RedisCrawlSpider
start_urlsallowed_domains注釋掉
添加一個(gè)新屬性:redis_key='sun'作為可以被共享的調(diào)度器隊(duì)列名稱
編寫數(shù)據(jù)解析相關(guān)操作
把當(dāng)前父類修改為RedisCrawlSpider

  • 修改配置文件settings.py,不要開啟項(xiàng)目自帶的pipelines不然還是走的原來的管道问芬,需要指定共享的管道RedisPipeline悦析,還要指定調(diào)度器
指定管道
ITEM_PIPELINES = {
   #'sunPro.pipelines.SunproPipeline': 300,
   'scrapy_redis.pipelines.RedisPipeline':400
}

指定調(diào)度器
#增加一個(gè)去重容器類的配置,作用使用redis的set集合來存儲(chǔ)請(qǐng)求的指紋數(shù)據(jù)此衅,從而實(shí)現(xiàn)請(qǐng)求去重的持久化
DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
#使用scrapy-redis組件自己的調(diào)度器
SCHEDULER='scrapy_redis.scheduler.Scheduler'
#配置調(diào)度器是否需要持久化强戴,也就是當(dāng)爬蟲結(jié)束了,要不要清空reids中請(qǐng)求隊(duì)列
#如果服務(wù)器宕機(jī)了挡鞍,重啟后從爬取的位置繼續(xù)爬取
SCHEDULER_PERSIST = True

指定redis地址和端口
REDIS_HOST='127.0.0.1'
REDIS_PORT='6379'

2.3.2 redis相關(guān)配置

redis.windows-server.conf文件修改把bind 127.0.0.1給注釋掉骑歹,由于要把爬到的數(shù)據(jù)庫(kù)儲(chǔ)存到不同地方,因此不要綁定本地
關(guān)閉保護(hù)模式protected-mode yes修改為protected-mode no墨微,如果開啟了保護(hù)模式道媚,那么其他客戶端只能讀取redis而不能寫入

2.3.3 啟動(dòng)工程

分布式爬蟲啟動(dòng)和scrapy工程不同,需要定位到爬蟲文件.py目錄內(nèi)翘县,執(zhí)行scrapy runspider xxx.py
工程啟動(dòng)后在redis客戶端中向redis添加調(diào)度隊(duì)列:lpush sun www.xxx.com(由于之前寫過redis_key='sun'的共享調(diào)度屬性)

3 增量式爬蟲

3.1 概念講解

增量式爬蟲:檢測(cè)網(wǎng)站數(shù)據(jù)更新的情況衰琐,只會(huì)爬取網(wǎng)站最新出來的數(shù)據(jù)
還是基于CrawlSpider獲取其他頁(yè)碼鏈接處理的,每次爬取時(shí)炼蹦,都會(huì)對(duì)已經(jīng)爬取的數(shù)據(jù)進(jìn)行比較羡宙,若爬取過了,就不再爬取

3.2 使用

3.2.1 爬蟲文件

主要通過redis來判斷是否已經(jīng)存儲(chǔ)過

from redis import Redis
from sunPro.items import SunproItem
class SunSpider(CrawlSpider):
    name = 'sun'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://www.xxx.com/']

    rules = (
        Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    )
    #創(chuàng)建redis對(duì)象
    conn = Redis(host='127.0.0.1',port=6379)
    def parse_item(self, response):
        li_list=response.xpath('xxxxx');
        for li in li_list:
            # 獲取詳情url
            detail_url=li.xpath('xxxxxxxxxx').extract_first()

            ex=self.conn.sadd('urls',detail_url)
            if ex==1:
                print('該url沒有爬取過掐隐,可以進(jìn)行數(shù)據(jù)爬取')
                yield scrapy.Request(url=detail_url,callback=self.parse_detail)
            else:
                print('數(shù)據(jù)沒有更新狗热,暫無新數(shù)據(jù)可爬取')

    def parse_detail(self,response):
        item = SunproItem()
        item['name']=response.xpath('xxxxxxxxxxxxx').extract()

3.2.2 管道文件

在管道文件中獲取redis


class SunproPipeline:
    conn=None
    # 開啟爬蟲時(shí)執(zhí)行,只執(zhí)行一次
    def open_spider(self,spider):
        self.conn=spider.conn
    #理提取的數(shù)據(jù)(保存數(shù)據(jù))
    def process_item(self, item, spider):
        dict={
                'name':item['name']
            }
        self.conn.lpush('test',dict)
        return item

    # 關(guān)閉爬蟲時(shí)執(zhí)行虑省,只執(zhí)行一次匿刮。 (如果爬蟲中間發(fā)生異常導(dǎo)致崩潰,close_spider可能也不會(huì)執(zhí)行)
    def close_spider(self, spider):
        # 可以關(guān)閉數(shù)據(jù)庫(kù)等
        pass
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末探颈,一起剝皮案震驚了整個(gè)濱河市熟丸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌伪节,老刑警劉巖光羞,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绩鸣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡纱兑,警方通過查閱死者的電腦和手機(jī)呀闻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來潜慎,“玉大人捡多,你說我怎么就攤上這事☆盱牛” “怎么了垒手?”我有些...
    開封第一講書人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)倒信。 經(jīng)常有香客問我淫奔,道長(zhǎng),這世上最難降的妖魔是什么堤结? 我笑而不...
    開封第一講書人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮鸭丛,結(jié)果婚禮上竞穷,老公的妹妹穿的比我還像新娘。我一直安慰自己鳞溉,他們只是感情好瘾带,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著熟菲,像睡著了一般看政。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抄罕,一...
    開封第一講書人閱讀 49,850評(píng)論 1 290
  • 那天允蚣,我揣著相機(jī)與錄音,去河邊找鬼呆贿。 笑死嚷兔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的做入。 我是一名探鬼主播冒晰,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼竟块!你這毒婦竟也來了壶运?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤浪秘,失蹤者是張志新(化名)和其女友劉穎蒋情,沒想到半個(gè)月后埠况,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡恕出,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年询枚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浙巫。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡金蜀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出的畴,到底是詐尸還是另有隱情渊抄,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布丧裁,位于F島的核電站护桦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一颁股、第九天 我趴在偏房一處隱蔽的房頂上張望蜡娶。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至票髓,卻和暖如春攀涵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背洽沟。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工以故, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人裆操。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓据德,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親跷车。 傳聞我的和親對(duì)象是個(gè)殘疾皇子棘利,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

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