Python Socket请求网站获取数据

 Python Socket请求网站获取数据

 

---阻塞 I/O           ->收快递,快递如果不到,就干不了其他的活

 

---非阻塞I/0       ->收快递,不断的去问,有没有送到,有没有送到,...如果送到了就接收

 

---I/O多路复用      ->找个代理人(select), 去收快递。快递到了,就通知用户.  

一 . 阻塞方式 

blocking IO 会一直block 对应的进程,直到操作完成

# 客户端请求网站-阻塞实现(一次一次的请求)
import socket
import time

# 访问网站
ACCESS_URL = 'www.baidu.com'
# 端口
ACCESS_PORT = 80


# socket阻塞请求网站
def blocking(pn):
    sock = socket.socket()
    sock.connect((ACCESS_URL, ACCESS_PORT))  # 连接网站 ,发出一个HTTP请求
    request_url = 'GET {} HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(pn))
    sock.send(request_url.encode())
    response = b''
    chunk = sock.recv(1024)
    while chunk:  # 循环接收数据,因为一次接收不完整
        response += chunk
        chunk = sock.recv(1024)
    # print(response.decode())
    return response


def block_way():
    for i in range(5):
        blocking(i)


if __name__ == '__main__':
    start = time.time()
    block_way()
    print('请求5次页面耗时{}'.format(time.time() - start))
    """
    请求5次页面耗时2.4048924446105957
    """

 

二. 非阻塞方式

non-blcoking在kernel还没准备好数据的情况下,会立即返回(会抛出异常)

# 客户端请求网站-非阻塞实现
import socket
import time

# 访问网站
ACCESS_URL = 'www.baidu.com'
# 端口
ACCESS_PORT = 80


# socket非阻塞请求网站(时间消耗在不断的while循环中,和阻塞的时间差不多)
def blocking(pn):
    sock = socket.socket()
    sock.setblocking(False)  # 设置为非阻塞
    try:
        # connect连接需要一定时间,非阻塞发送完请求,立即返回,如果没有数据会报异常
        sock.connect((ACCESS_URL, ACCESS_PORT))  # 连接网站 ,发出一个HTTP请求
    except BlockingIOError:  # 非阻塞套接字捕获异常
        pass
    request_url = 'GET {} HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(pn))
    while True:  # 不断发送http请求
        try:
            sock.send(request_url.encode())
            break
        except OSError:
            pass
    response = b''
    while True:  # 不断地接收数据
        try:
            chunk = sock.recv(1024)  # 没有数据返回时会收到异常
            while chunk:  # 循环接收数据,因为一次接收不完整
                response += chunk
                chunk = sock.recv(1024)
            break
        except BlockingIOError:  # 处理非阻塞异常
            pass
    # print(response.decode())
    return response


def block_way():
    for i in range(5):
        blocking(i)


if __name__ == '__main__':
    start = time.time()
    block_way()
    print('请求5次页面耗时{}'.format(time.time() - start))
    """
    请求5次页面耗时2.681565046310425
    时间消耗在不断的while循环中,和阻塞的时间差不多
    """

 

三. 多线程方式

# 客户端请求网站-线程池实现
import socket
from multiprocessing.pool import ThreadPool
import time

# 访问网站
ACCESS_URL = 'www.baidu.com'
# 端口
ACCESS_PORT = 80


def blocking(pn):
    sock = socket.socket()
    sock.connect((ACCESS_URL, ACCESS_PORT))  # 连接网站 ,发出一个HTTP请求
    request_url = 'GET {} HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(pn))
    sock.send(request_url.encode())
    response = b''
    chunk = sock.recv(1024)
    while chunk:  # 循环接收数据,因为一次接收不完整
        response += chunk
        chunk = sock.recv(1024)
    # print(response.decode())
    return response


def block_way():
    pool = ThreadPool(5)
    for i in range(10):
        pool.apply_async(blocking, args=(i,))
    pool.close()  # close()执行后不会有新的进程加入到pool
    pool.join()  # join函数等待子进程结束



if __name__ == '__main__':
    start = time.time()
    block_way()
    print('请求10次页面耗时{}'.format(time.time() - start))
    """
    请求10次页面耗时1.1231656074523926 
    """

 

四. 多进程方式

# 客户端请求网站-进程池实现
import socket
from multiprocessing import Pool
import time

# 访问网站
ACCESS_URL = 'www.baidu.com'
# 端口
ACCESS_PORT = 80


def blocking(pn):
    """
    发送请求,接收数据
    :param pn: 
    :return: 
    """
    sock = socket.socket()
    sock.connect((ACCESS_URL, ACCESS_PORT))  # 连接网站 ,发出一个HTTP请求
    request_url = 'GET {} HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(pn))
    sock.send(request_url.encode())
    response = b''
    chunk = sock.recv(1024)
    while chunk:  # 循环接收数据,因为一次接收不完整
        response += chunk
        chunk = sock.recv(1024)
    # print(response.decode())
    return response


def block_way():
    pool = Pool(5)
    for i in range(10):
        pool.apply_async(blocking, args=(i,))
    pool.close()  # close()执行后不会有新的进程加入到pool
    pool.join()  # join函数等待子进程结束



if __name__ == '__main__':
    start = time.time()
    block_way()
    print('请求10次页面耗时{}'.format(time.time() - start))
    """
    请求10次页面耗时1.1685676574707031 略慢于线程池实现方式,因为进程相对于线程开销比较大
    """

 

五. 协程方式

# 客户端请求网站-协程实现
from gevent import monkey;monkey.patch_all()  # 加补丁,实现非阻塞
import socket
import gevent
import time

# 访问网站
ACCESS_URL = 'www.baidu.com'
# 端口
ACCESS_PORT = 80


def blocking(pn):
    """
    发送请求,接收数据
    :param pn: 
    :return: 
    """
    sock = socket.socket()
    sock.connect((ACCESS_URL, ACCESS_PORT))  # 连接网站 ,发出一个HTTP请求
    request_url = 'GET {} HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(pn))
    sock.send(request_url.encode())
    response = b''
    chunk = sock.recv(1024)
    while chunk:  # 循环接收数据,因为一次接收不完整
        response += chunk
        chunk = sock.recv(1024)
    # print(response.decode())
    return response


def block_way():
    tasks = [gevent.spawn(blocking,i) for i in range (10)] #启动协程
    gevent.joinall(tasks)  # 阻塞等待所有操作都执行完毕


if __name__ == '__main__':
    start = time.time()
    block_way()
    print('请求10次页面耗时{}'.format(time.time() - start))
    """
    请求10次页面耗时0.6231002807617188 效率高于线程方式,协程相当于单线程并发(微线程),开销小于线程
    """

六. IO多路复用

I/O多路复用就是通过一种机制,操作系统通过一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

# 客户端请求网站-I/O多路复用
import socket
import selectors
import time

# 访问网站
ACCESS_URL = 'www.baidu.com'
# 端口
ACCESS_PORT = 80

sel = selectors.DefaultSelector()
flag = False  # 结束标志
num_list = [0] * 5


class Crawler(object):
    def __init__(self,pn):
        self.pn = pn
        self.response = b''


    def req_connect(self):
        """
        请求建立连接
        :return:
        """
        sock = socket.socket()
        sock.setblocking(False)
        try:
            sock.connect((ACCESS_URL, ACCESS_PORT))  # 连接网站 ,发出一个HTTP请求
        except BlockingIOError:  # 非阻塞套接字捕获异常
            pass
        sel.register(sock,selectors.EVENT_WRITE, self.conn_send)  # 监听socket,向服务端发送数据WRITE


    def conn_send(self,sock):
        """
        发送请求数据
        :param sock:
        :return:
        """
        # 取消上面注册监听的套接字
        sel.unregister(sock)
        request_url = 'GET {} HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(self.pn))
        sock.send(request_url.encode())  # 当我们发送数据之后,就等接收数据
        sel.register(sock,selectors.EVENT_READ, self.read)

    def read(self, sock):
        global flag
        chunk = sock.recv(1024)
        if chunk:
            self.response += chunk
        else:
            # 没有数据可读
            print(self.response)
            sel.unregister(sock)
            num_list.pop()
            if not num_list:
                flag = True


# 事件循环
def loop():
    while not flag:
        events = sel.select() # 监听发生了变化的套接字
        for key, mask in events:
            callback = key.data
            callback(key.fileobj)


if __name__ == '__main__':
    start = time.time()
    # print(num_list)
    for i in range(5):
        crawler = Crawler(i)  # 实例
        crawler.req_connect()
    loop()
    print('请求5次页面耗时{}'.format(time.time() - start))
    """
    请求5次页面耗时0.5865745544433594 多路复用非阻塞效率要高于非阻塞方式
    """

 

转载于:https://www.cnblogs.com/xiao-apple36/p/8673356.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#coding:utf-8 import time import webbrowser as web import os import random #随机选择一个浏览器打开网页 def open_url_use_random_browser(): #定义要访问的地址 url='http://www.baidu.com' #定义浏览器路径 browser_paths=[r'C:\Program Files (x86)\Mozilla Firefox\firefox.exe', #r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe', #r'C:\Program Files (x86)\Opera\launcher.exe', #r'C:\Users\Administrator\AppData\Roaming\qianying\qianying.exe', #r'C:\Users\Administrator\AppData\Local\115Chrome\Application\115chrome.exe', #r'C:\Program Files (x86)\Internet Explorer\iexplore.exe', #r'D:\Program Files(x86)\SouExplorer\SogouExplorer\SogouExplorer.exe' ] #选择一个浏览器 def chose_a_browser_open_url(browser_path,url): #如果传入的浏览器位置不存在,使用默认的浏览器打开 if not browser_path: print ('using default browser to open') web.open_new_tab(url)#使用默认浏览器,就不再结束进程 else: #判断浏览器路径是否存在 if not os.path.exists(browser_path): print ('current browser path not exists,using default browser') #浏览器位置不存在就使用默认的浏览器打开 browser_path='' chose_a_browser_open_url(chose_a_browser_open_url,url) else: browser_task_name=browser_path.split('\\')[-1]#结束任务的名字 browser_name=browser_task_name.split('.')[0]#自定义的浏览器代号 print (browser_name) web.register(browser_name, None,web.BackgroundBrowser(browser_path)) web.get(browser_name).open_new_tab(url)#使用新注册的浏览器打开网页 print ('using %s browser open url successful' % browser_name) time.sleep(5)#等待打开浏览器 # kill_cmd='taskkill /f /IM '+browser_task_name#拼接结束浏览器进程的命令 # os.system(kill_cmd) #终结浏览器 browser_path=random.choice(browser_paths)#随机从浏览器中选择一个路径 chose_a_browser_open_url(browser_path,url) if __name__ == '__main__': print (''''' ***************************************** ** Welcome to python of browser ** ** Created on 2019-04-28 ** ** @author: Louise_ZOU ** ***************************************** ''') open_url_use_random_browser()

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值