增量式爬虫

 

 

 

增量式爬虫

 

需求: 定时 更新程序 以便爬取网站中最近更新的数据

 

一、增量式爬虫

 
  • 概念: 通过爬虫程序检测某网站数据更新的情况,以便可以爬取到该网站更新出的新数据
  • 如何进行增量式的爬取工作:
    • 在发送请求之前判断 此 URL 是不是之前爬过
    • 在解析内容之后判断 这部分内容 之前是否爬过
    • 在写入 存储介质时 判断 内容是不是已经在介质中存在
 
  • 分析: 不难发现,其实增量式爬取的核心是 去重 ,至于说去重的操作在哪个步骤起作用,只能说各有利弊,在我看来, 前两种思路需要根据实际情况取一个(也可能都用)。
    • 第一种思路适合有不断新页面的出现,比如说小说的新章节,每天的最新新闻等等;
    • 第二种思路则适合页面内容会不断更新的网站。
    • 第三种思路是相当于最后一道防线。这样做可以最大程度上达到去重的目的。
 

去重方法:

 
  • 思路: 通过已有的机制达到去重的目的 1、redis的 set集合。 2、python 的 set 集合
  • 我们选择 redis 的 set 集合, 以求最大效率。
  • 将爬取过程中产生的 URL 进行存储,存储在 redis 的 set 中,
    • 根据 Redis.sadd(key,value) 的返回结果判断此 URL 是否已爬取过,
    • 1 表示存在,则发起请求; 0 表示不存在,则不进行请求。
  • 对爬取到的 网页内容进行唯一标识的制定, 然后将该唯一标识存储在 redis 的 set 中,当下次爬取到网页数据内容的时候,在进行持久化存储之前, 首先判断一下该 数据的 唯一标识在 redis 的 set 中是否存在,再决定 是否执行入库操作。
 

案例 一、

 

需求:爬取4567tv网站中所有的 电影名 和 作者名

In [ ]:
- 说明 1 : 项目配置文件 settings.py :
    - 默认配置
# 添加 UA
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
# 是否遵循爬虫协议 , 不遵从
ROBOTSTXT_OBEY = False
# 开启 scrapy 默认管道 
ITEM_PIPELINES = {
   'increment1_Pro.pipelines.Increment1ProPipeline': 300,
}
- 说明 2: items.py 文件 自己根据代码编写
 

爬虫文件

In [ ]:
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from redis import Redis
from increment1_Pro.items import Increment1ProItem


class MovieSpider(CrawlSpider):
    name = 'movie'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.4567tv.tv/index.php/vod/show/class/%E6%81%90%E6%80%96/id/9.html']

    rules = (
        Rule(LinkExtractor(allow=r'/index.php/vod/show/class/%E6%81%90%E6%80%96/id/9/page/\d+\.html'), callback='parse_item', follow=True),
    )
    def parse_item(self, response):
        conn = Redis(host='127.0.0.1',port=6379)

        detail_url_list ='https://www.4567tv.tv' + response.xpath('//li[@class="col-md-6 col-sm-4 col-xs-3"]/div/a/@href')

        for url in detail_url_list:
            # ex 若 为 1 ,表示 为新数据
            ex = conn.sadd('movies_url',url)
            if ex == 1:
                yield  scrapy.Request(url=url,callback=self.self.parse_detail)
            else:
                print("此站<%s>无更新数据,暂无新数据可爬"%url)

    def parse_detail(self,response):
        item = Increment1ProItem()
        item['name'] = response.xpath('//div[@class="stui-content__detail"]/h1/text()').extract_first()
        item['actor'] = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[3]/a/text()').extract_first()

        yield item
 

管道文件:

In [ ]:
# -*- coding: utf-8 -*-
from redis import Redis
class Increment1ProPipeline(object):
    def open_spider(self,spider):
        self.conn=Redis(host='127.0.0.1',port=6379)

    def process_item(self, item, spider):
        # dic = {
        #     'name': item['name'],
        #     'actor': item['actor'],
        # }
        print('正在入库!')
        self.conn.lpush('movie_data',item)
        return item
 

案例 二、

 

需求:爬取糗事百科中的 段子内容 和 作者名。

 

爬虫文件:

In [ ]:
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from increment_data.items import IncrementDataItem
from redis import Redis
import hashlib

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

    rules = (
        Rule(LinkExtractor(allow=r'/text/page/\d+/'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        div_list = response.xpath('//div[@class="article block untagged mb15 typs_hot"]')
        conn = Redis(host='127.0.0.1',port=6379)
        for div in div_list:
            item = IncrementDataItem()
            item['author'] = div.xpath('./div[1]/a[2]/h2/text() | ./div[1]/span[2]/h2/text()').extract_first()
            # item['content'] = response.xpath('./a[1]/div/span/text()').extract_first()
            item['content'] = div.xpath('.//div[@class="content"]/span/text()').extract()
            item['content'] = ''.join(item['content'])
            source = item['author'] + item['content']

            # 自定制 一种形式的 数据指纹, 是数据的唯一标识
            hashValue = hashlib.sha256(source.encode()).hexdigest()

            ex = conn.sadd("qiubai_hash",hashValue)
            if ex == 1:
                yield item
            else:
                print("此数据 已 爬")
                
 

管道文件:

In [ ]:
# -*- coding: utf-8 -*-
from redis import Redis
#####################  注意  ########################
"""
    在这里 向 redis 的列表中 lpush 字典时 ,则python  中 redis 的版本需要为 2.10.6,否则报错
        pip3 install redis==2.10.6
"""
class IncrementDataPipeline(object):
    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('qiubai_data',dic)
        print('爬取到一条数据, 正在入库')
        return item
    
posted @ 2019-05-27 19:32  梭梭666  阅读(175)  评论(0编辑  收藏  举报
返回顶部