zoukankan      html  css  js  c++  java
  • 爬虫5

    1 数据存储到mongodb(pipeline持久化)

    深度优先和广度优先

    ​ scrapy中通过队列和栈和优先级队列实现该方案

    把地址存入数据库:如下4个地方需要操作

    ​ settings配置,之后才能调度到pipeline中去执行

    cnblogs.py
        def parse(self, response):
            item_list  = response.css('#post_list .post_item')
            for item in item_list:
                article_url = item.css('.post_item_body a::attr(href)').extract_first()
                article_name = item.css('.titlelnk::text').extract_first()# 取a标签里面的内容用a::text
                commit_count = item.css('.article_comment a::text').extract_first()
                auther_name = item.css('.post_item_foot a::text').extract_first()
    
                article_item = ArticleItem()
                article_item['article_url']=article_url# 这里只能写[]取值,因为他(ArticleItem)没有写getattr和settattr方法!!
                article_item['article_name']=article_name
                article_item['commit_count']=commit_count
                article_item['auther_name']=auther_name
                yield article_item
                # yield Request(url, callback=self.parse_detail)# 注意这个callback不写,默认就回调到parse这个地方,我们可以指定回调的地方!!
    
            next_url=response.css('.pager a:last-child::attr(href)').extract_first()
            print('https://www.cnblogs.com'+next_url)
            yield Request('https://www.cnblogs.com'+next_url)
    
    items.py
    class ArticleItem(scrapy.Item):
        article_name = scrapy.Field()
        article_url = scrapy.Field()
        auther_name = scrapy.Field()
        commit_count = scrapy.Field()
    
    pipelines.py
    from pymongo import MongoClient
    
    class ArticleMongodbPipeline(object):
        def process_item(self, item, spider):
            # 1、链接
            client = MongoClient('localhost', 27017)
            # 2、use 数据库
            db = client['db2']  # 等同于:client.db1
            # 3、查看库下所有的集合
            # print(db.collection_names(include_system_collections=False))
            # 4、创建集合
            table_user = db['userinfo']  # 等同于:db.user
            table_user.save(dict(item))
            # return item
    

    settings

    在setting中配置pipeline
    ITEM_PIPELINES = {
    'myscrapy.pipelines.ArticleMongodbPipeline': 300,   #数字越小越先执行
    'myscrapy.pipelines.ArticleFilePipeline': 100,
    }# 这里是对应pipelines.py的类名写的!!!!
    

    2 去重规则(系统自带去重)

    针对yeild的url链接可能是重复的

    先采用MD5加密,减少内存占用,并且对可能对如下出现MD5值不一样的情况,系统也做了处理,使得一致。

    -把url放到集合中
        -存在缺陷:
        1 可能很长,占内存非常大————md5值()
        2 	www.baidu.com?name=lqz&age=18
        	www.baidu.com?age=18&name=lqz
    -BloomFilter去重(了解)
    # 备注
    
    源码入口:
    from scrapy.dupefilters import RFPDupeFilter# 点击最后一个
    

    image-20191129190340945

    不去重:

    ​ dont_filter=True(request的参数)

    yield Request('https://www.cnblogs.com'+next_url,dont_filter=True)# 这样就不去重!!!
    

    3 下载中间件(middlewares.py)

    image-20191129200632036

    作用在什么时候?

    ​ 下载东西过来的时候触发

    -使用cookie
    -使用代理池
    -集成selenium
    -使用:
    	-写一个类:MyscrapyDownloaderMiddleware
    		-process_request
    			加代理,加cookie,集成selenium。。。。
    			return None,Response,Resquest
    		-process_response
    	-在setting中配置		-
    		 DOWNLOADER_MIDDLEWARES = {'myscrapy.middlewares.MyscrapyDownloaderMiddleware': 543}
    
    #自己写
    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
            # 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 会放到调度器重新调度.这个地方写的不太好,他又走中间件,又进入循环了。因此代理完全可以卸载cnblogs中!
            return request
    
        def spider_opened(self, spider):
            spider.logger.info('Spider opened: %s' % spider.name)
    

    4 爬虫中间件

    -写一个类MyscrapySpiderMiddleware
    	-写一堆方法
    -在setting中配置
    	SPIDER_MIDDLEWARES = {
    		'myscrapy.middlewares.MyscrapySpiderMiddleware': 543,
    	}
    

    5 信号

    ​ 在某个位置要执行一个功能

    有内置信号,只需要给他关联函数。

    		-写一个类:class MyExtension(object):
    			-在from_crawler绑定一些信号
    			-当scrapy执行到信号执行点的时候,会自动触发这些函数
    		-在setting中配置	
    			EXTENSIONS = {
    			   'extentions.MyExtension': 100,
    			}
    

    6 布隆过滤器

    查找效率:

    ​ 哈希冲突--二叉树(因为深度没有这么深)--红黑树

    缓存穿透:

    image-20191129144834918

    7 分布式爬虫scrapy-redis

    目的:提高爬虫效率,将项目部署在多个机器上

    重复问题--统一做过滤,统一调度(redis)

    原理:(将爬虫程序分布在多个机器上面,起始Url交给另个需要下载模块的redis来处理,并且不会爬取重复的链接)
    	-pip3 install scrapy-redis
    	-在setting中配置:
            SCHEDULER = "scrapy_redis.scheduler.Scheduler"
            DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
            ITEM_PIPELINES = {
                'scrapy_redis.pipelines.RedisPipeline': 300
            }
    		(-调度器:使用scrapy-redis提供的调度器
    		-去重规则:使用scrapy-redis提供的去重规则
    		-可选:
    			-pipelines配置成scrapy-redis提供的持久化类)
            
    	-在爬虫类中:
        	-继承RedisSpider
    		-把start_url去掉(在redis中统一调度)
    		-新增:redis_key = 'cnblogs:start_urls'
    
         CMD中:lpush cnblogs(这个是关联的redis_key):start_urls https://www.cnblogs.com。l代表从列表的左侧插入
    
    # 使用注意事项
                
    1. 使用的时候,刚开始会停住,因为起始url在redis中统一调度,因此在cmd打开redis-cli
    2. 通过cmd命令行专跳到pip安装的项目路径下,才能打开redis!!设置统一起始url,
    
    补充知识点(切换到其他盘符的路径下):

    image-20191201200326049

  • 相关阅读:
    通过登入IP记录Linux所有用户登录所操作的日志
    PHP写的异步高并发服务器,基于libevent
    PHP event 事件机制
    PHP高级工程师的要求
    TBS 手册 --phpv 翻译
    两局域网互联解决方案
    比ngx_http_substitutions_filter_module 更强大的替换模块sregex的replace-filter-nginx-module
    直播平台虚拟币与人民币的关系
    查询出来的东西异步缓存
    如何解决GBK的编码的文件中的中文转换成为UTF-8编码的文件而且不乱码
  • 原文地址:https://www.cnblogs.com/ZDQ1/p/11967590.html
Copyright © 2011-2022 走看看