爬虫基础--IO多路复用单线程异步非阻塞

时间:2022-09-28 08:16:01

最近一直的学习爬虫  ,进行基础的学习

性能相关 参考

https://www.cnblogs.com/wupeiqi/p/6229292.html

 # 目标:单线程实现并发HTTP请求
#
# socket
# IO多路复用
# HTTP协议
#
# 流程
# http://www.163.com/new/
# 1. sk连接 IP 禾端口进行连接
# 2.请求信息
# 请求头
# k=v\r\n
# k=v\r\n
# k=v\r\n
# \r\n\r\n
# 请求体 import select
import socket
import time class AsyncTimeoutException(TimeoutError):
"""
请求超时异常类
""" def __init__(self, msg):
self.msg = msg
super(AsyncTimeoutException, self).__init__(msg) class HttpContext(object):
"""封装请求和相应的基本数据""" def __init__(self, sock, host, port, method, url, data, callback, timeout=5):
"""
sock: 请求的客户端socket对象
host: 请求的主机名
port: 请求的端口
method: 请求方式
url: 请求的URL
data: 请求时请求体中的数据
callback: 请求完成后的回调函数
timeout: 请求的超时时间
"""
self.sock = sock #sock: 请求的客户端socket对象
self.callback = callback #callback: 请求完成后的回调函数
self.host = host #host: 请求的主机名
self.port = port # port: 请求的端口
self.method = method #method: 请求方式
self.url = url #url: 请求的URL
self.data = data #data: 请求时请求体中的数据 self.timeout = timeout #timeout: 请求的超时时间 self.__start_time = time.time() #当前时间
self.__buffer = [] #在buffer中写入响应内容 def is_timeout(self):
"""当前请求是否已经超时"""
current_time = time.time()
if (self.__start_time + self.timeout) < current_time:
return True def fileno(self):
"""请求sockect对象的文件描述符,用于select监听"""
return self.sock.fileno() def write(self, data):
"""在buffer中写入响应内容"""
self.__buffer.append(data) def finish(self, exc=None):
"""在buffer中写入响应内容完成,执行请求的回调函数"""
if not exc:
response = b''.join(self.__buffer)
self.callback(self, response, exc)
else:
self.callback(self, None, exc) def send_request_data(self): #发送请求 伪造请求头 请求体
content = """%s %s HTTP/1.0\r\nHost: %s\r\n\r\n%s""" % (
# 请求方式 请求的URL 请求的主机名 请求时请求体中的数据
self.method.upper(), self.url, self.host, self.data,) return content.encode(encoding='utf8') class AsyncRequest(object):
def __init__(self):
self.fds = [] #用于存放 连接有返回值的请求
self.connections = []#用于存放需要连接的请求 def add_request(self, host, port, method, url, data, callback, timeout):
"""创建一个要请求"""
client = socket.socket()
client.setblocking(False)
try:
client.connect((host, port))
except BlockingIOError as e:
pass
# print('已经向远程发送连接的请求')
req = HttpContext(client, host, port, method, url, data, callback, timeout)
self.connections.append(req)
self.fds.append(req) def check_conn_timeout(self):
"""检查所有的请求,是否有已经连接超时,如果有则终止"""
timeout_list = [] #超时列表
for context in self.connections:
if context.is_timeout(): #进行超时检测 如果是超时
timeout_list.append(context) #加入超时列表
for context in timeout_list: #进行超时处理
context.finish(AsyncTimeoutException('请求超时'))
self.fds.remove(context) #进行移除 请求 待返回列表
self.connections.remove(context) #进行移除 请求 待发送列表 def running(self):
"""事件循环,用于检测请求的socket是否已经就绪,从而执行相关操作"""
while True:
if not self.fds: #如果没有请求 直接返回
return
r, w, e = select.select(self.fds, self.connections, self.fds, 0.05) #监测socket对象的变化 for context in r:
sock = context.sock #接收请求 连接
while True:
try:
data = sock.recv(8096)# 取返回值
if not data:#如果没有返回值
self.fds.remove(context) #移除等待返回值 的请求
context.finish()#完成请求
break
else:
context.write(data)
except BlockingIOError as e:
break
except TimeoutError as e: #如果超时,,移除 发送的请求和接收的请求 取消请求
self.fds.remove(context)
self.connections.remove(context)
context.finish(e)
break for context in w:
# 已经连接成功远程服务器,开始向远程发送请求数据
if context in self.fds:
data = context.send_request_data()#请求头 请求体
context.sock.sendall(data)#进行连接
self.connections.remove(context) #移除已经连接成功的请求 self.check_conn_timeout() #检测 是否超时 if __name__ == '__main__':
def callback_func(context, response, ex):
"""
:param context: HttpContext对象,内部封装了请求相关信息
:param response: 请求响应内容
:param ex: 是否出现异常(如果有异常则值为异常对象;否则值为None)
:return:
"""
print(context, response, ex) obj = AsyncRequest()
url_list = [
{'host': 'www.google.com', 'port': 80, 'method': 'GET', 'url': '/', 'data': '', 'timeout': 5,
'callback': callback_func},
{'host': 'www.baidu.com', 'port': 80, 'method': 'GET', 'url': '/', 'data': '', 'timeout': 5,
'callback': callback_func},
{'host': 'www.bing.com', 'port': 80, 'method': 'GET', 'url': '/', 'data': '', 'timeout': 5,
'callback': callback_func},
]
for item in url_list:
print(item)
obj.add_request(**item) obj.running()

爬虫基础--IO多路复用单线程异步非阻塞的更多相关文章

  1. IO多路复用与异步非阻塞

    1.基于socket,发送http请求 import socket import requests # 方式一 list=['li','gh ','nn'] for i in list: ret=re ...

  2. 为什么IO多路复用需要采用非阻塞式IO

    近段时间开始学习<Unix网络编程>,代码实现了一个简单的IO多路复用+阻塞式的服务端,在学习了非阻塞式IO后,有一个疑问,即: 假如调用了select,并且关注了几个描述字,当关注的描述 ...

  3. node 单线程异步非阻塞

    链接:http://www.runoob.com/nodejs/nodejs-callback.html 首先什么是单线程异步非阻塞? 单线程的意思整个程序从头到尾但是运用一个线程,程序是从上往下执行 ...

  4. Python异步非阻塞IO多路复用Select&sol;Poll&sol;Epoll使用,线程,进程,协程

    1.使用select模拟socketserver伪并发处理客户端请求,代码如下: import socket import select sk = socket.socket() sk.bind((' ...

  5. 转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select&sol;Poll&sol;Epoll使用】

    下面这篇,原理理解了, 再结合 这一周来的心得体会,整个框架就差不多了... http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架, ...

  6. java的高并发IO原理,阻塞BIO同步非阻塞NIO&comma;异步非阻塞AIO

    原文地址: IO读写的基础原理 大家知道,用户程序进行IO的读写,依赖于底层的IO读写,基本上会用到底层的read&write两大系统调用.在不同的操作系统中,IO读写的系统调用的名称可能不完 ...

  7. IO同步、异步与阻塞、非阻塞

    一.同步与异步同步/异步, 它们是消息的通知机制 1. 概念解释A. 同步所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回. 按照这个定义,其实绝大多数函数都是同步调用(例如si ...

  8. nodejs的异步非阻塞IO

    简单表述一下:发启向系统IO操作请求,系统使用线程池IO操作,执行完放到事件队列里,node主线程轮询事件队列,读取结果与调用回调.所以说node并非真的单线程,还是使用了线程池的多线程. 上个图看看 ...

  9. nginx学习(二)——基础概念之异步非阻塞

    上面讲了很多关于nginx的进程模型,接下来,我们来看看nginx是如何处理事件的. 有人可能要问了,nginx采用多worker的方式来处理请求,每个worker里面只有一个主线程,那能够处理的并发 ...

随机推荐

  1. AndroidUI自动化测试工具-UIautomator

    转自:http://www.cnblogs.com/rexmzk/archive/2012/12/26/2834380.html 最近公司在开展Android的自动化测试,美国那边的开发人员利用And ...

  2. ORACLE 导空表结构

    exp username/psd@sid file='E:\xx.dmp' tables=(xxx_%) ROWS=N 以下代码没什么用,我就乱写 set oracle_sid=ora11gsqlpl ...

  3. R语言学习笔记:向量化

    R语言最强大的方面之一就是函数的向量化,这些函数可以直接对向量的每个元素进行操作.例如: 对每个元素进行开方 > v<-c(4,3,8,16,7.3) > v [1]  4.0  3 ...

  4. 公布windows的&amp&semi;quot&semi;Universal Apps&amp&semi;quot&semi; Unity3D游戏

    转载请注明出处:http://blog.csdn.net/u010019717 更全的内容请看我的游戏蛮牛地址:http://www.unitymanual.com/space-uid-18602.h ...

  5. &lpar;转&rpar;JAVA排序汇总

    JAVA排序汇总 package com.softeem.jbs.lesson4; import java.util.Random; /** * 排序测试类 * * 排序算法的分类如下: * 1.插入 ...

  6. 【leetcode】92&period; Reverse Linked List II

    Reverse a linked list from position m to n. Do it in-place and in one-pass. For example:Given 1-> ...

  7. Hadoop的safeMode

    当集群启动的时候,会首先进入到安全模式.系统在安全模式下,会检查数据块的完整性.假设我们设置的副本数(即参数dfs.replication)是5,那么在dataNode上就应该有5个副本存在,假设只存 ...

  8. 三&period;SQL语句实例

    1.查询A表中存在而B表中不存在的数据 1.1 描述:表A中有一tel字段,表B中有一tel字段,两个字段存储的内容部分相同,现要查询A表tel字段中有而B表tel字段中没有的数据 1.2 有三个se ...

  9. commons-lang3工具类学习(三)

    六.ObjectUtils Object工具类 allNotNull(Object... values) 检查所有元素是否为空,返回一个boolean 如果有一个元素为空返回false,所有元素不为空 ...

  10. linux:文件打包与压缩

    学习内容介绍:Linux 上常用的压缩/解压工具,介绍了zip.rar.tar的使用. 先总结一下常用命令: zip: 打包 :zip something.zip something (目录请加 -r ...