码迷,mamicode.com
首页 > 编程语言 > 详细

python之路 -- 爬虫 -- 高性能相关

时间:2018-07-12 20:47:50      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:协程   org   false   recv   分享   epoll   http请求   yield   方式   

高性能爬虫方案:

  多进程

  多线程

  利用“异步非阻塞”模块实现单线程并发请求。

本质

 1 sk = socket()
 2 # 阻塞
 3 sk.connect((www.cnblogs.com,80))
 4 
 5 sk.sendall(b"GET /wupeiqi http1.1\r\n.....\r\n\r\n")
 6 sk.sendall(b"POST /wupeiqi http1.1\r\n.....\r\n\r\nuser=alex&pwd=123")
 7 
 8 # 阻塞
 9 data = sk.recv(8096)
10 
11 sk.close()

IO多路复用:

  监听多个socket是否发生变化

IO多路复用的作用:

  1.select,内部循环检测socket是否发生变化;最多只能检测1024个socket

  2.poll,内部循环检测socket是否发生变化;检测socket数不限

  3.epoll,通过回调的方式检测socket是否发生变化;检测socket数不限

什么是异步非阻塞?

非阻塞:

   不等待(可能会报错,捕捉异常)
   代码:
    sk = socket.socket()
    sk.setblocking(False)
异步:
  回调,当达到某个指定的状态之后,自动调用特定函数。

如何自定义异步非阻塞模块?   

本质:socket+IO多路复用

  基于socket设置setblocking和IO多路复用来实现。
  爬虫发送Http请求本质创建socket对象;
  IO多路复用"循环"监听socket是否发生变化,一旦发生变化, 我们可以自定义操作(触发某个函数的执行)

 什么是协程?

  1. 是“微线程”,不存在;是由程序员人为创造出来并控制程序:先执行某段代码、再跳到某处执行某段代码。
  2.如果遇到非IO请求来回切换:性能更低。

  3. 如果遇到IO(耗时)请求来回切换:性能高、实现并发(本质上利用IO等待的过程,再去干一些其他的事)

 

 通过yield实现一个协程:

技术分享图片
def func1():
                        
                        print(adsfasdf)
                        print(adsfasdf)
                        print(adsfasdf)
                        yield 1
                        print(adsfasdf)
                        print(adsfasdf)
                        print(adsfasdf)
                        
                        yield 2
                        yield 3
                        yield 4
                        
                    def func2():
                        print(adsfasdf)
                        print(adsfasdf)
                        print(adsfasdf)
                        yield 11
                        yield 12
                        yield 19
                        
                        
                    g1=func1()
                    g2=func2()
                    
                    g1.send(None)
                    g1.send(None)
                    g2.send(None)
View Code

通过greenlet模块实现一个协程:

技术分享图片
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()
View Code

Python内置以及第三方模块提供异步IO请求模块,使用简便大大提高效率,而对于异步IO请求的本质则是【非阻塞Socket】+【IO多路复用】:

 常用的3种:

技术分享图片
import asyncio
import requests

@asyncio.coroutine
def fetch_async(func, *args):
    loop = asyncio.get_event_loop()
    future = loop.run_in_executor(None, func, *args)
    response = yield from future
    print(response.url, response.content)

tasks = [
    fetch_async(requests.get, http://www.cnblogs.com/wupeiqi/),
    fetch_async(requests.get, http://dig.chouti.com/pic/show?nid=4073644713430508&lid=10273091)
]

loop = asyncio.get_event_loop()
results = loop.run_until_complete(asyncio.gather(*tasks))
loop.close()
asyncio+requests
技术分享图片
import gevent
import requests
from gevent import monkey

monkey.patch_all()

def fetch_async(method, url, req_kwargs):
    print(method, url, req_kwargs)
    response = requests.request(method=method, url=url, **req_kwargs)
    print(response.url, response.content)

# ##### 发送请求 #####
gevent.joinall([
    gevent.spawn(fetch_async, method=get, url=https://www.python.org/, req_kwargs={}),
    gevent.spawn(fetch_async, method=get, url=https://www.yahoo.com/, req_kwargs={}),
    gevent.spawn(fetch_async, method=get, url=https://github.com/, req_kwargs={}),
])

# ##### 发送请求(协程池控制最大协程数量) #####
# from gevent.pool import Pool
# pool = Pool(None)
# gevent.joinall([
#     pool.spawn(fetch_async, method=‘get‘, url=‘https://www.python.org/‘, req_kwargs={}),
#     pool.spawn(fetch_async, method=‘get‘, url=‘https://www.yahoo.com/‘, req_kwargs={}),
#     pool.spawn(fetch_async, method=‘get‘, url=‘https://www.github.com/‘, req_kwargs={}),
# ])

4.gevent + requests
gevent+requests
技术分享图片
                from twisted.web.client import getPage, defer
                from twisted.internet import reactor


                def all_done(arg):
                    reactor.stop()


                def callback(contents):
                    print(contents)


                d_list = []

                url_list = [http://www.bing.com, http://www.baidu.com, ]
                for url in url_list:
                    d = getPage(bytes(url, encoding=utf8))
                    d.addCallback(callback)

                    d_list.append(d)

                # 用于检查是否页面已经全部下载完成,如果已下载完成那么,就停止循环。
                dlist = defer.DeferredList(d_list)
                dlist.addBoth(all_done) #

                reactor.run()
Twisted示例

 

python之路 -- 爬虫 -- 高性能相关

标签:协程   org   false   recv   分享   epoll   http请求   yield   方式   

原文地址:https://www.cnblogs.com/aberwang/p/9301746.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!