高性能相關----爬蟲


2. 高性能相關 

基本原理:
IO多路復用:select,用於檢測socket對象是否發生變化(是否連接成功,是否有數據到來)
Socket:socket客戶端

import socket
import select

class Request(object):
def __init__(self,sock,func,url):
self.sock = sock
self.func = func
self.url = url

def fileno(self):
return self.sock.fileno()

def async_request(url_list):

input_list = []
conn_list = []

for url in url_list:
client = socket.socket()
client.setblocking(False)
# 創建連接,不阻塞
try:
client.connect((url[0],80,)) # 100個向百度發送的請求
except BlockingIOError as e:
pass

obj = Request(client,url[1],url[0])

input_list.append(obj)
conn_list.append(obj)

while True:
# 監聽socket是否已經發生變化 [request_obj,request_obj....request_obj]
# 如果有請求連接成功:wlist = [request_obj,request_obj]
# 如果有響應的數據: rlist = [request_obj,request_obj....client100]
rlist,wlist,elist = select.select(input_list,conn_list,[],0.05)
for request_obj in wlist:
# print('連接成功')
# # # # 發送Http請求
# print('發送請求')
request_obj.sock.sendall("GET / HTTP/1.0\r\nhost:{0}\r\n\r\n".format(request_obj.url).encode('utf-8'))
conn_list.remove(request_obj)

for request_obj in rlist:
data = request_obj.sock.recv(8096)
request_obj.func(data)
request_obj.sock.close()
input_list.remove(request_obj)

if not input_list:
break

使用一個線程完成並發操作,如何並發?
當第一個任務到來時,先發送連接請求,此時會發生IO等待,但是我不等待,我繼續發送第二個任務的連接請求....

IO多路復用監聽socket變化
先連接成功:
發送請求信息: GET / http/1.0\r\nhost....
遇到IO等待,不等待,繼續檢測是否有人連接成功:
發送請求信息: GET / http/1.0\r\nhost....
遇到IO等待,不等待,繼續檢測是否有人連接成功:
發送請求信息: GET / http/1.0\r\nhost....

有結果返回:
讀取返回內容,執行回調函數
讀取返回內容,執行回調函數
讀取返回內容,執行回調函數
讀取返回內容,執行回調函數
讀取返回內容,執行回調函數
讀取返回內容,執行回調函數
讀取返回內容,執行回調函數



問題:什么是協程?
單純的執行一端代碼后,調到另外一端代碼執行,再繼續跳...

異步IO:
- 【基於協程】可以用 協程+非阻塞socket+select實現,gevent
- 【基於事件循環】完全通用socket+select實現,Twsited

1. 如何提高爬蟲並發?
利用異步IO模塊,如:asyncio,twisted,gevent
本質:
- 【基於協程】可以用 協程+非阻塞socket+select實現,gevent
- 【基於事件循環】完全通用socket+select實現,Twsited,tornado

2. 異步非阻塞
異步:回調 select
非阻塞:不等待 setblocking(False)

3. 什么是協程?
pip3 install gevent

from greenlet import greenlet

def test1():
print(12)
gr2.switch()
print(34)
gr2.switch()


def test2():
print(56)
gr1.switch()
print(78)

gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM