• 11_29


    一。数据存储到mongodb

      爬取的数据如果需要存储到mongodb中,要通过item,定义一个存储类。再yield一个类。

      数据存储的时候需要进过pipelines,再到setting中配置。

    from pymongo import MongoClient
    class ArticleMongodbPipeline(object):
        def process_item(self, item, spider):
    
            # client = MongoClient('mongodb://localhost:27017/')
            #连接
            client = MongoClient('localhost', 27017)
            #创建article数据库,如果没有叫创建,如果有,叫使用
            db = client['article']
            # print(db)
            #如果有使用articleinfo,如果没有,创建这个表
            article_info=db['articleinfo']
    
            article_info.insert(dict(item))
            # article_info.save({'article_name':item['article_name'],'aritcle_url':item['article_url']})
            # 如果retrun None ,下一个就取不到item了,取到的就是None
    数据库使用
    # -*- coding: utf-8 -*-
    import scrapy
    from myscrapy.items import ArticleItem
    from scrapy import Request
    from scrapy.core.scheduler import Scheduler
    from scrapy.dupefilters import RFPDupeFilter
    class CnblogsSpider(scrapy.Spider):
        name = 'cnblogs'   #爬虫名,必须唯一
        allowed_domains = ['cnblogs.com']   #允许的域名,
        start_urls = ['https://www.cnblogs.com/']  #起始的url
        custom_settings={"BB":"xxxxx"}
        #深度优先,广度优先
        #爬虫去重:好多策略
        #爬虫起始入口 start_requests
        # def parse_detail(self,response):
        #     print(len(response.text))
    
    
        # def parse(self, response):
        #     div_list=response.css('.post_item')
        #     for div in div_list:
        #         url=div.css('.post_item_body a::attr(href)').extract_first()
        #         article_name=div.css('.titlelnk::text').extract_first()
        #         auther_name=div.css('.post_item_foot a::text').extract_first()
        #         commit_count=div.css('.post_item_foot span a::text').extract_first()
        #         article_item=ArticleItem()
        #         #把地址存入数据库,yield item对象
        #         article_item['article_name']=article_name
        #         article_item['article_url']=url
        #         article_item['auther_name']=auther_name
        #         article_item['commit_count']=commit_count
        #         yield article_item
        #
        #     next_url=response.css('.pager a:last-child::attr(href)').extract_first()
        #     print('https://www.cnblogs.com'+next_url)
        #     #dont_filter=True 表示不去重,默认去重
        #     yield Request('https://www.cnblogs.com'+next_url,dont_filter=True,cookies={'name':'xxx'})
        def parse(self, response):
            print(response)
            # print(response.url)
            # print(response.status)
            # print(response.body)
            # obj=Request('https://www.cnblogs.com' + next_url, dont_filter=True, cookies={'name': 'xxx'})
            # obj.meta["aa"]="aa"
            # yield obj
            # yield [Request,Request]
            yield Request('https://www.cnblogs.com')
    spiders层

      如果用户需要存储到其他地方,只要再配置文件中继续配置,并将类写成如下规定,

    class ArticleFilePipeline(object):
        # def __init__(self,host,port):
        def __init__(self):
            # self.mongo_conn=MongoClient(host,port)
            pass
    
        #如果这个类中有from_crawler,首先会执行from_crawler,aa=ArticleFilePipeline.from_crawler(crawler)
        #如果没有直接aa=ArticleFilePipeline()
        @classmethod
        def from_crawler(cls, crawler):
            print('')
            #mongodb的配置信息在setting中
            # host = '从配置文件中拿出来的'
            # port='从配置文件中拿出来的'
            #crawler.settings总的配置文件
            print('asdfasdfasfdasfd',crawler.settings['AA'])
            # return cls(host,port)
            return cls()
    
        def open_spider(self, spider):
            # print('----',spider.custom_settings['AA'])
            self.f = open('article.txt','a')
    
    
        def close_spider(self, spider):
            self.f.close()
            print('close spider')
    自定义

      setting配置:

    ITEM_PIPELINES = {
       'myscrapy.pipelines.ArticleMongodbPipeline': 300,   #数字越小越先执行
       'myscrapy.pipelines.ArticleFilePipeline': 100,
    }

    二。去重。

      scrapy中的去重方式RFPDupeFilter是将url进行排序,再获取md5,保证长度,最后每有一个请求就和这个集合进行对比。

      setting配置:

    DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter' #默认的去重规则帮我们去重,去重规则在内存中

      自定义去重

    from scrapy.dupefilters import  BaseDupeFilter
    #自己定制去重方案
    class MyDupeFilter(BaseDupeFilter):
        """Request Fingerprint duplicates filter"""
    
        def __init__(self, path=None, debug=False):
           self.aa=set()
    
    
    
        def request_seen(self, request):
            if request.url in self.aa:
                return True
    
        def close(self, reason):
            if self.file:
                self.file.close()
    
        def log(self, request, spider):
            if self.debug:
                msg = "Filtered duplicate request: %(request)s (referer: %(referer)s)"
                args = {'request': request, 'referer': referer_str(request) }
                self.logger.debug(msg, args, extra={'spider': spider})
            elif self.logdupes:
                msg = ("Filtered duplicate request: %(request)s"
                       " - no more duplicates will be shown"
                       " (see DUPEFILTER_DEBUG to show all duplicates)")
                self.logger.debug(msg, {'request': request}, extra={'spider': spider})
                self.logdupes = False
    
            spider.crawler.stats.inc_value('dupefilter/filtered', spider=spider)
    编写去重类

      再setting中配置。

      其他去重方法亦可以通过redis进行,或者布隆过滤器(比特位去重)

    三。下载中间件

      中间件可以拦截各种请求,需要再setting中配置

    class MyscrapyDownloaderMiddleware(object):
        @classmethod
        def from_crawler(cls, crawler):
            s = cls()
            return s
    
        def process_request(self, request, spider):
    
            print('来了')
            print(request.url)
    
            #headers可以改
            print(request.headers)
            #从cookie池中取出cookie赋值进去
            print(request.cookies)
            #使用代理
            # request.meta['download_timeout'] = 20
            # request.meta["proxy"] = 'http://192.168.1.1:7878'
            # print(request)
            # print(spider)
            # 返回值:None,Request对象,Response对象
            #None 继续走下一个下载中间件
            #Response 直接返回,进入spider中做解析
            #Request 回到调度器,重新被调度
            #可以使用selenium
            return HtmlResponse(url="www.baidu.com", status=200,  body=b'sdfasdfasfdasdfasf')
    
        def process_response(self, request, response, spider):
            print('走了')
            print(request)
            print(spider)
            print(type(response))
            return response
    
        def process_exception(self, request, exception, spider):
            print('代理%s,访问%s出现异常:%s' % (request.meta['proxy'], request.url, exception))
            import time
            time.sleep(5)
            #删除代理
            # delete_proxy(request.meta['proxy'].split("//")[-1])
            #重新获取代理,放进去
            # request.meta['proxy'] = 'http://' + get_proxy()
            #return request 会放到调度器重新调度
            return request
    
        def spider_opened(self, spider):
            spider.logger.info('Spider opened: %s' % spider.name)
    View Code

      其中request是任务来时做的动作。respons是任务走是做的动作,

      可以再cookies中设置代理(meta)和cookies池(cookies)

      再spriders中返回的parse中的request中添加对象,就会在下载中间件中的request中获取。

      return None,Response,Resquest

    四。爬虫中间件

      

    #自己写爬虫中间件
    class MyscrapySpiderMiddleware(object):
    
        @classmethod
        def from_crawler(cls, crawler):
            # This method is used by Scrapy to create your spiders.
            s = cls()
            crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
            return s
    
        def process_spider_input(self, response, spider):
            print('我进爬虫的解析')
            return None
    
        def process_spider_output(self, response, result, spider):
            print("我往外走")
            for i in result:
                yield i
    
        def process_spider_exception(self, response, exception, spider):
    
            pass
    
        def process_start_requests(self, start_requests, spider):
            print("process_start_requests")
            for r in start_requests:
                yield r
    
        def spider_opened(self, spider):
            print("spider_opened")
            spider.logger.info('Spider opened: %s' % spider.name)
    View Code

    五。信号

      信号与django中的信号差不多,大体步骤如下:

      1.写一个类:class MyExtension(object):

      2.在from_crawler绑定一些信号  

      3.当scrapy执行到信号执行点的时候,会自动触发这些函数

      4.在setting中配置

      EXTENSIONS = {
    'extentions.MyExtension': 100,
    }

      

    from scrapy import signals
    
    class MyExtension(object):
    
        @classmethod
        def from_crawler(cls, crawler):
            # val = crawler.settings.getint('MMMM')
            obj = cls()
    
            crawler.signals.connect(obj.spider_opened, signal=signals.spider_opened)
            crawler.signals.connect(obj.spider_closed, signal=signals.spider_closed)
    
            return obj
    
        def spider_opened(self, spider):
            print('=============>open')
    
        def spider_closed(self, spider):
            print('=============>close')
    例子

    六。哈希

      哈希就是一个字典。

      当数据进行存储的时候,就为其标记一个记号,放入链表中,当发送哈希冲突的时候,就将该点存储的数据变成一个地址,地址指向另一个列表。

      布隆过滤器。

      当访问不存在数据频繁的时候,redis就有可能被击穿,被击穿后就回直接访问数据库。

      所以,使用过滤器事先判断数据是否有,如果没有直接返回。

      redis自带布隆过滤器。

    七。分布式爬虫。

      分布式爬虫的基本原理就是同一调度统一去重。分布到不同的机器上爬虫。

      安装:

    pip3 install scrapy-redis

      1.设置setting中的调度器:

    SCHEDULER = "scrapy_redis.scheduler.Scheduler"

      2.设置去重规则:

    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

      3.配置指定的持久化类:

    ITEM_PIPELINES = {
        'scrapy_redis.pipelines.RedisPipeline': 300
    }

      4.在爬虫类中,继承RedisSpider,把start_url去掉,新增:redis_key = 'cnblogs:start_urls'。

      cnblogs和输入到redis中有关。

      5.启动项目,redis中发送爬虫指令

    -lpush cnblogs:start_urls https://www.cnblogs.com

      源码组成:

    -connection.py redis的连接
    -defaults.py 配置文件
    -dupefilter.py 去重规则
    -picklecompat.py 序列化相关
    -pipelines.py 持久化
    -queue.py 队列
    -scheduler.py 调度器
    -spiders.py 爬虫相关
    -utils.py py2和py3兼容的

      

  • 相关阅读:
    formData实现图片上传
    input[type='file']样式美化及实现图片预览
    第一个Vue插件从封装到发布
    lastIndex对正则结果的影响
    使用图片地图减少HTTP请求数量
    实现文字颜色渐变
    vue-cli中如何引入jquery
    事件处理详解
    图片载入状态判断及实现百分比效果loading
    页面加载时触发的事件及顺序
  • 原文地址:https://www.cnblogs.com/LZXlzmmddtm/p/11970523.html
Copyright © 2020-2023  润新知