h5手机网站建设哪家好,如何建自己的网站,wordpress最新文章列表插件,珠海附近交友平台软件阅读目录 一 背景知识二 同步、异步、回调机制三 高性能一 背景知识 爬虫的本质就是一个socket客户端与服务端的通信过程#xff0c;如果我们有多个url待爬取#xff0c;采用串行的方式执行#xff0c;只能等待爬取一个结束后才能继续下一个#xff0c;效率会非常低。 需要… 阅读目录 一 背景知识二 同步、异步、回调机制三 高性能 一 背景知识 爬虫的本质就是一个socket客户端与服务端的通信过程如果我们有多个url待爬取采用串行的方式执行只能等待爬取一个结束后才能继续下一个效率会非常低。 需要强调的是串行并不意味着低效如果串行的都是纯计算的任务那么cpu的利用率仍然会很高之所以爬虫程序的串行低效是因为爬虫程序是明显的IO密集型程序。 关于IO模型详见链接http://www.cnblogs.com/linhaifeng/articles/7454717.html 那么该如何提高爬取性能呢 二 同步、异步、回调机制 1、同步调用即提交一个任务后就在原地等待任务结束等到拿到任务的结果后再继续下一行代码效率低下 import requestsdef get_page(url):responserequests.get(url)if response.status_code 200:return response.texturls[https://www.baidu.com/,http://www.sina.com.cn/,https://www.python.org]
for url in urls:resget_page(url) #调用一个任务就在原地等待任务结束拿到结果后才继续往后执行print(len(res)) 同步调用 2、一个简单的解决方案多线程或多进程 #在服务器端使用多线程或多进程。多线程或多进程的目的是让每个连接都拥有独立的线程或进程这样任何一个连接的阻塞都不会影响其他的连接。 from multiprocessing import Process
from threading import Thread
import requestsdef get_page(url):responserequests.get(url)if response.status_code 200:return response.textif __name__ __main__:urls[https://www.baidu.com/,http://www.sina.com.cn/,https://www.python.org]for url in urls:pProcess(targetget_page,args(url,))p.start()# tThread(targetget_page,args(url,))# t.start() 多进程或多线程 该方案的问题是 #开启多进程或都线程的方式我们是无法无限制地开启多进程或多线程的在遇到要同时响应成百上千路的连接请求则无论多线程还是多进程都会严重占据系统资源降低系统对外界响应效率而且线程与进程本身也更容易进入假死状态。 3、改进方案 线程池或进程池异步调用提交一个任务后并不会等待任务结束而是继续下一行代码 #很多程序员可能会考虑使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率其维持一定合理数量的线程并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池尽量重用已有的连接、减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销都被广泛应用很多大型系统如websphere、tomcat和各种数据库等。 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import requestsdef get_page(url):print(GET : %s %url)responserequests.get(url)if response.status_code 200:return response.textif __name__ __main__:pProcessPoolExecutor()# pThreadPoolExecutor()
urls[https://www.baidu.com/,http://www.sina.com.cn/,https://www.python.org]for url in urls:p.submit(get_page,url)p.shutdown(waitTrue) 进程池或线程池 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import requests
import osdef get_page(url):print(%s GET : %s %(os.getpid(),url))responserequests.get(url)if response.status_code 200:return response.textdef parse_page(res):resres.result()print(%s parsing %os.getpid())if __name__ __main__:pProcessPoolExecutor()# pThreadPoolExecutor()
urls[https://www.baidu.com/,http://www.sina.com.cn/,https://www.python.org]for url in urls:p.submit(get_page,url).add_done_callback(parse_page)p.shutdown(waitTrue) 异步调用回调机制 改进后方案其实也存在着问题 #“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用IO接口带来的资源占用。而且所谓“池”始终有其上限当请求大大超过上限时“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模并根据响应规模调整“池”的大小。 对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求“线程池”或“连接池”或许可以缓解部分压力但是不能解决所有问题。总之多线程模型可以方便高效的解决小规模的服务请求但面对大规模的服务请求多线程模型也会遇到瓶颈可以用非阻塞接口来尝试解决这个问题。 三 高性能 上述无论哪种解决方案其实没有解决一个性能相关的问题IO阻塞无论是多进程还是多线程在遇到IO阻塞时都会被操作系统强行剥夺走CPU的执行权限程序的执行效率因此就降低了下来。 解决这一问题的关键在于我们自己从应用程序级别检测IO阻塞然后切换到我们自己程序的其他任务执行这样把我们程序的IO降到最低我们的程序处于就绪态就会增多以此来迷惑操作系统操作系统便以为我们的程序是IO比较少的程序从而会尽可能多的分配CPU给我们这样也就达到了提升程序执行效率的目的 1、在python3.3之后新增了asyncio模块可以帮我们检测IO只能是网络IO实现应用程序级别的切换 import asyncioasyncio.coroutine
def task(task_id,senconds):print(%s is start %task_id)yield from asyncio.sleep(senconds) #只能检测网络IO,检测到IO后切换到其他任务执行print(%s is end %task_id)tasks[task(task_id1,senconds3),task(task_id2,senconds4)]loopasyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*tasks))
loop.close() 基本使用 2、但asyncio模块只能发tcp级别的请求不能发http协议因此在我们需要发送http请求的时候需要我们自定义http报头 #我们爬取一个网页的过程以https://www.python.org/doc/为例将关键步骤列举如下
#步骤一向www.python.org这台主机发送tcp三次握手是IO阻塞操作
#步骤二封装http协议的报头
#步骤三发送http协议的请求包是IO阻塞操作
#步骤四接收http协议的响应包是IO阻塞操作
import asyncioasyncio.coroutine
def get_page(host,port80,url/):#步骤一IO阻塞发起tcp链接是阻塞操作因此需要yield fromrecv,sendyield from asyncio.open_connection(host,port)#步骤二封装http协议的报头因为asyncio模块只能封装并发送tcp包因此这一步需要我们自己封装http协议的包requset_headersGET %s HTTP/1.0\r\nHost: %s\r\n\r\n % (url, host,)# requset_headersPOST %s HTTP/1.0\r\nHost: %s\r\n\r\nnameegonpassword123 % (url, host,)requset_headersrequset_headers.encode(utf-8)#步骤三IO阻塞发送http请求包send.write(requset_headers)yield from send.drain()#步骤四IO阻塞接收http协议的响应包textyield from recv.read()#其他处理print(host,url,text)send.close()print(-)return 1tasks[get_page(hostwww.python.org,url/doc),get_page(hostwww.cnblogs.com,urllinhaifeng),get_page(hostwww.openstack.org)]loopasyncio.get_event_loop()
resultsloop.run_until_complete(asyncio.gather(*tasks))
loop.close()print(,results) #[1, 1, 1] asyncio自定义http协议报头 3、自定义http报头多少有点麻烦于是有了aiohttp模块专门帮我们封装http报头然后我们还需要用asyncio检测IO实现切换 import aiohttp
import asyncioasyncio.coroutine
def get_page(url):print(GET:%s %url)responseyield from aiohttp.request(GET,url)datayield from response.read()print(url,data)response.close()return 1tasks[get_page(https://www.python.org/doc),get_page(https://www.cnblogs.com/linhaifeng),get_page(https://www.openstack.org)
]loopasyncio.get_event_loop()
resultsloop.run_until_complete(asyncio.gather(*tasks))
loop.close()print(,results) #[1, 1, 1] asyncioaiohttp 4、此外还可以将requests.get函数传给asyncio就能够被检测了 import requests
import asyncioasyncio.coroutine
def get_page(func,*args):print(GET:%s %args[0])loogasyncio.get_event_loop()furtureloop.run_in_executor(None,func,*args)responseyield from furtureprint(response.url,len(response.text))return 1tasks[get_page(requests.get,https://www.python.org/doc),get_page(requests.get,https://www.cnblogs.com/linhaifeng),get_page(requests.get,https://www.openstack.org)
]loopasyncio.get_event_loop()
resultsloop.run_until_complete(asyncio.gather(*tasks))
loop.close()print(,results) #[1, 1, 1] asynciorequests模块的方法 5、还有之前在协程时介绍的gevent模块 from gevent import monkey;monkey.patch_all()
import gevent
import requestsdef get_page(url):print(GET:%s %url)responserequests.get(url)print(url,len(response.text))return 1# g1gevent.spawn(get_page,https://www.python.org/doc)
# g2gevent.spawn(get_page,https://www.cnblogs.com/linhaifeng)
# g3gevent.spawn(get_page,https://www.openstack.org)
# gevent.joinall([g1,g2,g3,])
# print(g1.value,g2.value,g3.value) #拿到返回值#协程池
from gevent.pool import Pool
poolPool(2)
g1pool.spawn(get_page,https://www.python.org/doc)
g2pool.spawn(get_page,https://www.cnblogs.com/linhaifeng)
g3pool.spawn(get_page,https://www.openstack.org)
gevent.joinall([g1,g2,g3,])
print(g1.value,g2.value,g3.value) #拿到返回值 geventrequests 6、封装了geventrequests模块的grequests模块 #pip3 install grequestsimport grequestsrequest_list[grequests.get(https://wwww.xxxx.org/doc1),grequests.get(https://www.cnblogs.com/linhaifeng),grequests.get(https://www.openstack.org)
]##### 执行并获取响应列表 #####
# response_list grequests.map(request_list)
# print(response_list)##### 执行并获取响应列表处理异常 #####
def exception_handler(request, exception):# print(request,exception)print(%s Request failed %request.url)response_list grequests.map(request_list, exception_handlerexception_handler)
print(response_list) grequests 7、twisted是一个网络框架其中一个功能是发送异步请求检测IO并自动切换
#问题一error: Microsoft Visual C 14.0 is required. Get it with Microsoft Visual C Build Tools: http://landinghub.visualstudio.com/visual-cpp-build-tools
https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
pip3 install C:\Users\Administrator\Downloads\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
pip3 install twisted#问题二ModuleNotFoundError: No module named win32api
https://sourceforge.net/projects/pywin32/files/pywin32/#问题三openssl
pip3 install pyopenssl
#twisted基本用法
from twisted.web.client import getPage,defer
from twisted.internet import reactordef all_done(arg):# print(arg)reactor.stop()def callback(res):print(res)return 1defer_list[]
urls[http://www.baidu.com,http://www.bing.com,https://www.python.org,
]
for url in urls:objgetPage(url.encode(utf-8),)obj.addCallback(callback)defer_list.append(obj)defer.DeferredList(defer_list).addBoth(all_done)reactor.run()#twisted的getPage的详细用法
from twisted.internet import reactor
from twisted.web.client import getPage
import urllib.parsedef one_done(arg):print(arg)reactor.stop()post_data urllib.parse.urlencode({check_data: adf})
post_data bytes(post_data, encodingutf8)
headers {bContent-Type: bapplication/x-www-form-urlencoded}
response getPage(bytes(http://dig.chouti.com/login, encodingutf8),methodbytes(POST, encodingutf8),postdatapost_data,cookies{},headersheaders)
response.addBoth(one_done)reactor.run() twisted的用法 8、tornado from tornado.httpclient import AsyncHTTPClient
from tornado.httpclient import HTTPRequest
from tornado import ioloopdef handle_response(response):处理返回值内容需要维护计数器来停止IO循环调用 ioloop.IOLoop.current().stop():param response: :return: if response.error:print(Error:, response.error)else:print(response.body)def func():url_list [http://www.baidu.com,http://www.bing.com,]for url in url_list:print(url)http_client AsyncHTTPClient()http_client.fetch(HTTPRequest(url), handle_response)ioloop.IOLoop.current().add_callback(func)
ioloop.IOLoop.current().start() Tornado 转载于:https://www.cnblogs.com/richiewlq/p/8318703.html