1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > SEO工具 网站优化软件 亲情奉献

SEO工具 网站优化软件 亲情奉献

时间:2020-11-18 17:02:04

相关推荐

SEO工具 网站优化软件  亲情奉献

本人用爬虫写了一个程序。优化确实挺有用的,现在分享给大家。有需要的可以下载,使用中有什么问题可以联系我,使用的时候 请关闭杀d软件,会误报错

爬虫性能优化爬虫性能优化# 引入爬虫的本质就是一个socket客户端与服务端的通信过程,如果我们有多个url待爬取,只用一个线程且采用串行的方式执行,那只能等待爬取一个结束后才能继续下一个,效率会非常低。需要强调的是:对于单线程下串行N个任务,并不完全等同于低效,如果这N个任务都是纯计算的任务,那么该线程对cpu的利用率仍然会很高,之所以单线程下串行多个爬虫任务低效,是因为爬虫任务是明显的IO密集型程序。那么该如何提高爬取性能呢?这就不得不说到线程进程相关的概念了。### 阻塞非阻塞,同步、异步、回调#### 1、同步调用:即提交一个任务后就在原地等待任务结束,等到拿到任务的结果后再继续下一行代码,效率低下```pythonimport requestsdef parse_page(res):print('解析 %s' %(len(res)))def get_page(url):print('下载 %s' %url)response=requests.get(url)if response.status_code == 200:return response.texturls=['/','/','']for url in urls:res=get_page(url) #调用一个任务,就在原地等待任务结束拿到结果后才继续往后执行parse_page(res)```#### 2、解决方案1:多线程或多进程在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。```python#IO密集型程序应该用多线程import requestsfrom threading import Thread,current_threaddef parse_page(res):print('%s 解析 %s' %(current_thread().getName(),len(res)))def get_page(url,callback=parse_page):print('%s 下载 %s' %(current_thread().getName(),url))response=requests.get(url)if response.status_code == 200:callback(response.text)if __name__ == '__main__':urls=['/','/','']for url in urls:t=Thread(target=get_page,args=(url,))t.start()```**该方案的问题是:**开启多进程或都线程的方式,我们是无法无限制地开启多进程或多线程的:在遇到要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,降低系统对外界响应效率,而且线程与进程本身也更容易进入假死状态。#### 3、改进方案: 线程池或进程池+异步调用很多程序员可能会考虑使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池,尽量重用已有的连接、减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,如websphere、tomcat和各种数据库等。```python#IO密集型程序应该用多线程,所以此时我们使用线程池import requestsfrom threading import current_threadfrom concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutordef parse_page(res):res=res.result()print('%s 解析 %s' %(current_thread().getName(),len(res)))def get_page(url):print('%s 下载 %s' %(current_thread().getName(),url))response=requests.get(url)if response.status_code == 200:return response.textif __name__ == '__main__':urls=['/','/','']pool=ThreadPoolExecutor(50)# pool=ProcessPoolExecutor(50)for url in urls:pool.submit(get_page,url).add_done_callback(parse_page)pool.shutdown(wait=True)进程池或线程池:异步调用+回调机制```**改进后方案其实也存在着问题:**“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用IO接口带来的资源占用。而且,所谓“池”始终有其上限,当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,并根据相应规模调整“池”的大小。上例中的所面临的问题是可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型也会遇到瓶颈,解决方案就是使用非阻塞IO接口。### 非阻塞IO上述无论哪种解决方案其实没有解决一个性能相关的问题:IO阻塞,无论是多进程还是多线程,在遇到IO阻塞时都会被操作系统强行剥夺走CPU的执行权限,程序的执行效率因此就降低了下来。​ 解决这一问题的关键在于,我们自己从应用程序级别检测IO阻塞然后切换到我们自己程序的其他任务执行,这样把我们程序的IO降到最低,我们的程序处于就绪态就会增多,以此来迷惑操作系统,操作系统便以为我们的程序是IO比较少的程序,从而会尽可能多的分配CPU给我们,这样也就达到了提升程序执行效率的目的#### 1、asyncio模块在python3.3之后新增了asyncio模块,可以帮我们检测IO(只能是网络IO),实现应用程序级别的切换,原理同gevent一直,都是在遇到io时切换到另一个任务执行,也就是协程。##### 基本使用```pythonimport asyncio@asyncio.coroutinedef 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_id="任务1",senconds=3),task("任务2",2),task(task_id="任务3",senconds=1)]loop=asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))loop.close()```##### 自定义http报头但asyncio模块只能发tcp级别的请求,不能发http协议,因此,在我们需要发送http请求的时候,需要我们自定义http报头```pythonimport asyncioimport requestsimport uuiduser_agent='Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'def parse_page(host,res):print('%s 解析结果 %s' %(host,len(res)))with open('%s.html' %(uuid.uuid1()),'wb') as f:f.write(res)@asyncio.coroutinedef get_page(host,port=80,url='/',callback=parse_page,ssl=False):print('下载 http://%s:%s%s' %(host,port,url))#步骤一(IO阻塞):发起tcp链接,是阻塞操作,因此需要yield fromif ssl:port=443recv,send=yield from asyncio.open_connection(host=host,port=443,ssl=ssl)# 步骤二:封装http协议的报头,因为asyncio模块只能封装并发送tcp包,因此这一步需要我们自己封装http协议的包request_headers="""GET %s HTTP/1.0\r\nHost: %s\r\nUser-agent: %s\r\n\r\n""" %(url,host,user_agent)# requset_headers="""POST %s HTTP/1.0\r\nHost: %s\r\n\r\nname=name&password=123""" % (url, host,)request_headers=request_headers.encode('utf-8')# 步骤三(IO阻塞):发送http请求包send.write(request_headers)yield from send.drain()# 步骤四(IO阻塞):接收响应头while True:line=yield from recv.readline()if line == b'\r\n':breakprint('%s Response headers:%s' %(host,line))# 步骤五(IO阻塞):接收响应体text=yield from recv.read()# 步骤六:执行回调函数callback(host,text)# 步骤七:关闭套接字send.close() #没有recv.close()方法,因为是四次挥手断链接,双向链接的两端,一端发完数据后执行send.close()另外一端就被动地断开if __name__ == '__main__':tasks=[get_page('',url='/s?wd=美女',ssl=True),get_page('',url='/',ssl=True),]loop=asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))loop.close()```##### asyncio+requests也可以将request的请求方法交给asyncio来执行```pythonimport requestsimport asyncio@asyncio.coroutinedef get_page(func,*args):print('GET:%s' %args[0])loog=asyncio.get_event_loop()furture=loop.run_in_executor(None,func,*args)response=yield from furtureprint(response.url,len(response.text))return 1tasks=[get_page(requests.get,'/doc'),get_page(requests.get,'/linhaifeng'),get_page(requests.get,'')]loop=asyncio.get_event_loop()results=loop.run_until_complete(asyncio.gather(*tasks))loop.close()print('=====>',results) #[1, 1, 1]```#### 2、gevent模块```pythonfrom gevent import monkey;monkey.patch_all()import geventimport requestsdef get_page(url):print('GET:%s' %url)response=requests.get(url)print(url,len(response.text))return 1# g1=gevent.spawn(get_page,'/doc')# g2=gevent.spawn(get_page,'/linhaifeng')# g3=gevent.spawn(get_page,'')# gevent.joinall([g1,g2,g3,])# print(g1.value,g2.value,g3.value) #拿到返回值#协程池from gevent.pool import Poolpool=Pool(2)g1=pool.spawn(get_page,'/doc')g2=pool.spawn(get_page,'/linhaifeng')g3=pool.spawn(get_page,'')gevent.joinall([g1,g2,g3,])print(g1.value,g2.value,g3.value) #拿到返回值```#### 3、grequests模块封装了gevent+requests模块```python#pip3 install grequestsimport grequestsrequest_list=[grequests.get('/doc1'),grequests.get('/linhaifeng'),grequests.get('')]##### 执行并获取响应列表 ###### 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_handler=exception_handler)print(response_list)```#### 4、twistedTwisted是用Python实现的基于事件驱动的网络引擎框架,Twisted支持许多常见的传输及应用层协议,包括TCP、UDP、HTTP、等。注意,python3中,字符串必须转码成utf8的格式,否则无法发送。比如`str("test").encode("utf8")`即可```python'''安装时容易出现的问题#问题一:error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": /visual-cpp-build-toolshttps://www.lfd.uci.edu/~gohlke/pythonlibs/#twistedpip3 install C:\Users\Administrator\Downloads\Twisted-17.9.0-cp36-cp36m-win_amd64.whlpip3 install twisted#问题二:ModuleNotFoundError: No module named 'win32api'/projects/pywin32/files/pywin32/#问题三:opensslpip3 install pyopenssl'''``````python#twisted基本用法from twisted.web.client import getPage,deferfrom twisted.internet import reactordef all_done(arg):# print(arg)reactor.stop()def callback(res):print(res)return 1defer_list=[]urls=['','','',]for url in urls:obj=getPage(url.encode('utf=-8'),)obj.addCallback(callback)defer_list.append(obj)defer.DeferredList(defer_list).addBoth(all_done)reactor.run()``````python# post请求from twisted.web.client import getPagefrom twisted.internet import reactorimport urllib.parsedef one_done(arg):print(arg)reactor.stop()post_data = urllib.parse.urlencode({'check_data': 'adf'})post_data = bytes(post_data, encoding='utf8')headers = {b'Content-Type': b'application/x-www-form-urlencoded'}response = getPage(bytes('/login', encoding='utf8'),method=bytes('POST', encoding='utf8'),postdata=post_data,cookies={},headers=headers)```#### 5、tornadoTornado是使用Python编写的一个强大的、可扩展的Web服务器。它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。```pythonfrom tornado.httpclient import AsyncHTTPClientfrom tornado.httpclient import HTTPRequestfrom 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 = ['','',]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()```###### 添加计数器发现上例在所有任务都完毕后也不能正常结束,为了解决该问题,让我们来加上计数器```pythonfrom tornado.httpclient import AsyncHTTPClientfrom tornado.httpclient import HTTPRequestfrom tornado import ioloopcount=0def handle_response(response):"""处理返回值内容(需要维护计数器,来停止IO循环),调用 ioloop.IOLoop.current().stop():param response::return:"""if response.error:print("Error:", response.error)else:print(len(response.body))global countcount-=1 #完成一次回调,计数减1if count == 0:ioloop.IOLoop.current().stop() def func():url_list = ['','',]global countfor url in url_list:print(url)http_client = AsyncHTTPClient()http_client.fetch(HTTPRequest(url), handle_response)count+=1 #计数加1ioloop.IOLoop.current().add_callback(func)ioloop.IOLoop.current().start()```

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。