python 管道 异步读取 select_Python高级编程与异步IO并发编程——12“select+callback+event循环获取HTML,和,123select,回调,事件,html...

#1. 默认,阻塞IO实现http请求

# requests 包基于urllib,urllib又是基于socket实现的。 凡是web请求,数据库连接,网络连接,数据通信等,最底层的实现都是基于socket实现的。

# socket是操作系统提供的功能,只是不同的语言将socket封装为不同的接口而已。

# 如何通过socket,完成urlib的get请求?

import socket

from urllib.parse import urlparse # urlparse 只是用于url解析,并不会处理socket

def get_url(url):

# 通过socket请求html,解析url

url = urlparse(url)

host = url.netloc # 提取主域名

path = url.path

if path == "": #如果path为空,直接请求主域名

path = "/"

# 建立socket连接

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

client.connect((host,80)) # http链接一般都为80端口,否则会导致无法连接。

# 发送数据

client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path,host).encode("utf8")) # Get请求,然后是相对路径。

# 将所有数据读取完

data = b"" # 数据为bytes类型

while True:

d = client.recv(1024)

if d:

data += d

else:

break

data = data.decode("utf8")

html_data = data.split("\r\n\r\n")[1] # \r 回车符号 \n 换行符号, 去掉HTTP头的信息

print(html_data)

client.close()

if __name__=="__main__":

get_url("http://www.baidu.com")

#2. 通过非阻塞io实现http请求

# 虽然使用了非阻塞io,整个while循环还是不停的等待,基于上一步执行结果,整个程序的返回时间并没有明显提升,没有显著提高并发。

import socket

from urllib.parse import urlparse # urlparse 只是用于url解析,并不会处理socket

def get_url(url):

# 通过socket请求html,解析url

url = urlparse(url)

host = url.netloc # 提取主域名

path = url.path

if path == "": #如果path为空,直接请求主域名

path = "/"

# 建立socket连接

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

client.setblocking(False) # 此处可用设置client,在client.connect(host,80)后立即返回,不等待连接成功(三次握手)

try: # 如果不用try/excep处理,调用client.connect((host,80)) 后会抛异常“BlockingIOError: [WinError 10035] 无法立即

# 完成一个非阻止性套接字操作。”,虽然抛异常,连接请求还是已经发送出去了

client.connect((host,80)) # 阻塞不会消耗CPU

except BlockingIOError as e:

pass # 继续向下执行

# 发送数据

while True:

try:

client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path,host).encode("utf8")) # Get请求,然后是相对路径。

# 调用该client.send语句是,还是抛出异常,“OSError: [WinError 10057] 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)

# 没有提供地址,发送或接收数据的请求没有被接受。”,原因是这里没有建立好连接。此处发送基于前面的连接,为了实现该功能的成功执行,只有不停的

# 尝试,用while True

break # 如果不成功,不停的尝试,如果成功,就要从while循环中break出来。

except OSError as e:

pass

# 将所有数据读取完

data = b"" # 数据为bytes类型

while True:

try:

d = client.recv(1024) # 如果send出去,没有接收到,此处就会报“BlockingIOError: [WinError 10035] 无法立即完成一个非阻止性套接字操作。”

# 同样此处用try/except处理

except BlockingIOError as e:

continue # 如果抛出异常,则继续while循环

if d:

data += d

else:

break # 如果读取数据为空,说明执行完毕,退出while循环

data = data.decode("utf8")

html_data = data.split("\r\n\r\n")[1] # \r 回车符号 \n 换行符号, 去掉HTTP头的信息

print(html_data)

client.close()

if __name__=="__main__":

get_url("http://www.baidu.com")

def register(self, fileobj, events, data=None): # fileobj是指socket, events代表事件(EVENT_READ & EVENT_WRITE两个事件),data为回调函数

key = super().register(fileobj, events, data)

if events & EVENT_READ:

self._readers.add(key.fd)

if events & EVENT_WRITE:

self._writers.add(key.fd)

return key

#!/usr/bin/env python

# -*- coding:utf-8 -*-

# 通过非阻塞io实现http请求

import socket

from urllib.parse import urlparse

from selectors import DefaultSelector, EVENT_READ, EVENT_WRITE

selector = DefaultSelector()

urls = ['http://www.baidu.com']

stop = False

# 使用select完成http请求

class Fetcher:

def connected(self, key):

# 注销事件

selector.unregister(key.fd)

self.client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(self.path, self.host).encode('utf-8'))

#

selector.register(self.client.fileno(), EVENT_READ, self.readable)

def readable(self, key):

d = self.client.recv(1024)

if d:

self.data += d

else:

# 注销

selector.unregister(key.fd)

self.data = self.data.decode('utf-8')

html_data = self.data.split('\r\n\r\n')[1]

print(self.data)

print(html_data)

self.client.close()

urls.remove(self.spider_url)

if not urls:

global stop

stop = True

def get_url(self, url):

self.spider_url = url

# 通过socket请求html

url = urlparse(url)

self.host = url.netloc

self.path = url.path

self.data = b""

if self.path == '':

self.path = '/'

# 建立连接

self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

self.client.setblocking(False)

try:

self.client.connect((self.host, 80))

except BlockingIOError as e:

pass

# 注册事件

selector.register(self.client.fileno(), EVENT_WRITE, self.connected)

'''

register(fileobj, events, data=None)

fileobj:文件描述符

events:监听事件

data:回调函数

'''

def loop():

# 事件循环,不停的请求socket的状态并调用对应的回调函数

# 1.select本身是不支持register模式。

# 2.socket状态变化以后的回调是由程序员完成的。

while not stop:

# windows下会报错,但是linux下不会报错

ready = selector.select()

for key, mask in ready:

call_back = key.data

call_back(key)

if __name__ == '__main__':

fetcher = Fetcher()

fetcher.get_url('http://www.baidu.com')

loop()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值