異步非阻塞socket的實現

在學習使用scrapy爬蟲框架以前,須要瞭解一些基礎原理html

  咱們知道HTTP請求是基於socket模塊進行發送和接受的,可是socket套接字的在使用的中存在着阻塞,不利用爬蟲的高性能運行,因此咱們就須要對框架進行一些高性能設置,使用select模塊,檢測socket請求的IO操做,實現對socket的高性能運行:app

如下是代碼示例:框架

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\r\nhost:%s\r\n\r\n" %(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()
相關文章
相關標籤/搜索