• 异步非阻塞socket的实现


    在学习使用scrapy爬虫框架之前,需要了解一些基础原理

      我们知道HTTP请求是基于socket模块进行发送和接受的,但是socket套接字的在使用的中存在着阻塞,不利用爬虫的高性能运行,所以我们就需要对框架进行一些高性能设置,使用select模块,检测socket请求的IO操作,实现对socket的高性能运行:

    以下是代码示例:

    import socket
    import select
    
    
    class Request(object):
        '''
        request类的定义是应对请求的连接不同时,做的低耦合操作
        '''
        def __int__(self,sock,info):
            self.sock=sock
            self.info=info
    
        def fileno(self):
            '''
            因为select模块在检测IO操作但是针对socket对象,该对象中必须有fileno方法才能调用,
            因此需要我们自己定义一个request类,在类下包含fileno方法
            :return:
            '''
            return self.sock.fileno()
    
    
    
    class Mysocket(object):
        def __int__(self):
            '''
            初始化两个列表,存储socket对象
            :return:
            '''
            self.sock_list=[]
            self.conns=[]
    
    
        def add_request(self,req_info):
            '''
            创建请求
            :param req_info: {'host':'www.baidu.com','port':80}
            :return:
            '''
            sock=socket.socket()
            sock.setblocking(False)#设置socket为非阻塞状态
            try:
                sock.connect((req_info['host'],req_info['post']))
            except BaseException as e:
                pass
            #使用try方法防止sock在非阻塞状态下报错
    
            obj=Request(sock,req_info)#示例话Request类,此类就是socket实例化的对象
            self.sock_list.append(obj)
            self.conns.append(obj)
    
        def run(self):
            '''
            开始事件循环,检测:连接是否成功,是否有数据返回
            :return:
            '''
            while True:
                r,w,e=select.select(self.sock_list,self.conns,[],0.05)
                #select。select([socket对象,]),可以是任何对象,但是对象一定要有
                #fileno方法,所以需要自己去定义request类
                #在此处就调用request对象
    
                #seclet参数w数值就是检测请求是否成功
                for obj in w:
                    #检查obj.request对象
                    data="GET %s http/1.1
    host:%s
    
    " %(obj.info['path'],obj.info['host'])
                    obj.sock.send(data.encode('utf8'))
                    self.conns.remove(obj)#该连接在成功请求过后,为防止重复发送请求,需请求列表中将其删除
                    
                    
                #数据返回,接受到数据
                for obj in r:
                    response=obj.sock.recv(8096)
                    obj.info["callback"](response)
                    self.sock_list.remove(obj)
    
    from .. import Mysocket
    def data(response):
        '''
        回调函数,对返回的数据进行操作
        :param response:
        :return:
        '''
        print(response)
    
    def file(response):
        '''
        回调函数,对返回数值的第二种操作方式
        :param response:
        :return:
        '''
        print(response)
    
    url_list = [
        {'host': 'www.baidu.com', 'port': 80, 'path': '/','callback': data},
        {'host': 'www.cnblogs.com', 'port': 80, 'path': '/index.html','callback': file},
        {'host': 'www.bing.com', 'port': 80, 'path': '/','callback': data},
    ]
    
    obj=Mysocket()
    for item in url_list:
        obj.add_request(item)
    
    obj.run()
  • 相关阅读:
    写给QA/软件测试新人
    互联网产品线上故障管理规范
    爬了世纪佳缘后发现了一个秘密,世纪佳缘找对象靠谱吗?
    网传美团今年应届生年薪 35w+,严重倒挂老员工,为什么互联网大厂校招的薪资一年比一年高?...
    MySQL大表优化方案
    步入AI领域2年连升3级,我只是找对了学习方法而已……
    BZOJ 4008 亚瑟王(概率DP 奥妙重重)
    BZOJ 4318 OSU! (概率DP)
    BZOJ 3812 主旋律 (状压DP+容斥) + NOIP模拟赛 巨神兵(obelisk)(状压DP)
    BZOJ 4145 [AMPPZ2014]The Prices (状压DP)
  • 原文地址:https://www.cnblogs.com/lzh1118/p/7460822.html
Copyright © 2020-2023  润新知