增量式爬蟲


一、介紹

1、引言

比如當我們爬取一個小說網站的時候,第一天你把小說網站全部小說都爬下來了,存儲好了。
一個月后,當這個小說網站又新出了幾本小說,你重新爬取這個網站的時候,如果你不是增量式爬蟲,
那么你的程序會重新把這個網站所有小說再爬一次,而實際上我們只需要把新增的小說爬下來即可,
這就是增量式爬蟲。

 

2、增量式爬蟲

1.概念:通過爬蟲程序監測某網站數據更新的情況,以便可以爬取到該網站更新出的新數據。

2.如何進行增量式的爬取工作:
  在發送請求之前判斷這個URL是不是之前爬取過
  在解析內容后判斷這部分內容是不是之前爬取過
  寫入存儲介質時判斷內容是不是已經在介質中存在

3.分析
不難發現,其實增量爬取的核心是去重, 至於去重的操作在哪個步驟起作用,只能說各有利弊。
在我看來,前兩種思路需要根據實際情況取一個(也可能都用)。
第一種思路適合不斷有新頁面出現的網站,比如說小說的新章節,每天的最新新聞等等;
第二種思路則適合頁面內容會更新的網站。
第三個思路是相當於是最后的一道防線。這樣做可以最大程度上達到去重的目的。

4.去重方法
1,將爬取過程中產生的url進行存儲,存儲在redis的set中。當下次進行數據爬取時,首先對即將要發起的請求對應的url在存儲的url的set中做判斷,如果存在則不進行請求,否則才進行請求。
2,對爬取到的網頁內容進行唯一標識的制定,然后將該唯一表示存儲至redis的set中。當下次爬取到網頁數據的時候,在進行持久化存儲之前,首先可以先判斷該數據的唯一標識在redis的set中是否存在,在決定是否進行持久化存儲。

 

二、項目案例

1、爬取4567tv網站中喜劇片的所有電影的標題和上映年份

1. 爬蟲文件
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from redis import Redis
from moviePro.items import MovieproItem


class MovieSpider(CrawlSpider):
    name = 'movie'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.4567tv.tv/index.php/vod/show/id/6/page/23.html']

    rules = (
        Rule(LinkExtractor(allow=r'/index.php/vod/show/id/6/page/\d+.html'), callback='parse_item', follow=True),
    )
    # 創建redis鏈接對象
    conn = Redis(host='127.0.0.1', port=6379)

    def parse_item(self, response):
        li_list = response.xpath('//li[@class="col-md-6 col-sm-4 col-xs-3"]')
        for li in li_list:
            # 獲取詳情頁的url
            detail_url = 'http://www.4567tv.tv' + li.xpath('./div/a/@href').extract_first()
            # 將詳情頁的url存入redis的set中
            ex = self.conn.sadd('urls', detail_url)
            # 設置redis的key-value成功時,會返回1,否則返回0
            if ex == 1:
                print('該url沒有被爬取過,可以進行數據的爬取')
                yield scrapy.Request(url=detail_url, callback=self.parst_detail)
            else:
                print('數據還沒有更新,暫無新數據可爬取!')

    # 解析詳情頁中的電影名稱和類型,進行持久化存儲
    def parst_detail(self, response):
        item = MovieproItem()
        item['title'] = response.xpath('//div[@class="stui-content__detail"]/h3[@class="title"]/text()').extract_first()
        item['year'] = response.xpath('//div[@class="stui-content__detail"]/p[1]/a[2]/@href').extract_first()
        yield item


2. items.py
import scrapy


class MovieproItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()
    year = scrapy.Field()


3. pipelines.py
from redis import Redis


class MovieproPipeline(object):
    conn = None

    def open_spider(self, spider):
        self.conn = Redis(host='127.0.0.1', port=6379)

    def process_item(self, item, spider):
        dic = {
            'title': item['title'],
            'year': item['year']
        }
        print(dic)
        self.conn.lpush('movieData', dic)
        return item

 

2、爬取糗事百科中的段子和作者數據

1. 爬蟲文件
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from qiubaiZ.items import QiubaizItem
from redis import Redis
import hashlib


class QiubaiSpider(CrawlSpider):
    name = 'qiubaiz'
    # allowed_domains = ['https://www.qiushibaike.com/text/']
    start_urls = ['https://www.qiushibaike.com/text/']

    rules = (
        Rule(LinkExtractor(allow=r'/text/page/\d+/'), callback='parse_item', follow=True),
        Rule(LinkExtractor(allow=r'/text/$'), callback='parse_item', follow=True),
    )
    # 創建redis鏈接對象
    conn = Redis(host='127.0.0.1', port=6379)

    def parse_item(self, response):
        div_list = response.xpath('//div[@id="content-left"]/div')
        for div in div_list:
            item = QiubaizItem()
            # 爬取作者
            author = div.xpath('.//div[@class="author clearfix"]/a/h2/text()')
            if author:
                author = author[0].extract()
            else:
                author = "匿名用戶"
            # 爬取這個用戶的段子的內容contents
            contents = div.xpath('.//div[@class="content"]/span/text()')  # 遇到換行br就會生成一個Selector對象
            content = ''.join([selector.extract().strip() for selector in contents])
            item['author'] = author
            item['content'] = content
            # 設置數據的存儲格式
            source = item['author'] + item['content']
            # 將解析到的數據值生成一個唯一的標識進行redis存儲
            source_id = hashlib.sha256(source.encode()).hexdigest()
            # 將解析內容的唯一表示存儲到redis的data_id中
            ex = self.conn.sadd('data_id', source_id)
            if ex == 1:
                print('該條數據沒有爬取過,可以爬取')
                yield item
            else:
                print('該條數據已經爬取過了,不需要再次爬取了!')


2. items.py
class QiubaizItem(scrapy.Item):
    # define the fields for your item here like:
    author = scrapy.Field()
    content = scrapy.Field()


3. pipelines.py
from redis import Redis


class QiubaizPipeline(object):
    conn = None

    def open_spider(self, spider):
        self.conn = Redis(host='127.0.0.1', port=6379)

    def process_item(self, item, spider):
        dic = {
            'author': item['author'],
            'content': item['content']
        }
        self.conn.lpush('qiubaizData', dic)
        return item

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM