前面比较了单线程与多线程的I/O密集型,多线程访问速度远远优于单线程,今天我们再测试下单线程与协程并发访问多个网页看看结果如何。做这个测试的原因是,很多爬虫高手会推荐用协程,并且go语言并发高性能也是用的协程,横向比较的话,协程比线程耗费资源少。纵向比较,go语言的高并发协程耗费资源少于python语言。所以将来go语言可能会在高并发领域应用越来越广。扯远了哈。我们进入正题,说下比较思路:
- get_url获取基金网站的首页内容和返回结果(当然后面的协程函数get_each_url会引用get_url,作用是获取每个基金连接的网页内容);
- handle_response 是处理get_url获取的首页内容,从中提取每个基金的链接等内容;
- 协程函数get_each_url,后面将每个基金的url传入这个函数,并发访问;
- main里面分两部分,一部分是单线程访问30个网页,一个是协程并发访问;
- 协程部分主要用了asyncio这个模块。定义一个task列表,列表中存放的是每个协程函数返回的协程对象,后面会把这个列表扔进协程loop中自动循环执行
# -*- encoding=UTF-8 -*-
__author__ = 'wjj1982'
__date__ = '2019/8/19 20:46'
__product__ = 'PyCharm'
__filename__ = '协程'
from bs4 import BeautifulSoup as bs
import requests
import re
import time
import asyncio
# 输入一个url,然后get页面信息,最后返回页面content和页面code
def get_url(url):
if url is None:
return None
try:
response = requests.get(url)
except Exception as e:
print('get url failed,error is:{}'.format(e))
return None
if response.status_code != 200:
return None
return response.status_code, response.content
def handle_response(content):
bs_content = bs(content, 'html.parser', from_encoding='gb18030')
urls_fund = bs_content.find_all('ul', class_='num_right')
fund_list = []
for url_fund in urls_fund:
for each_li in url_fund.find_all('li'):
fund_info_dict = {'fund_id': '',
'fund_name': '',
'fund_url': ''}
each_a = each_li.find_all('a')
if len(each_a) > 0:
each_a = each_a[0]
fund_info_dict['fund_id'] = re.findall(r'\d+', each_a.text)[0]
fund_info_dict['fund_name'] = each_a.text.split(')')[1]
fund_info_dict['fund_url'] = each_a['href']
# fund_info_dict['fund_url'] = each_a.attrs['href']
fund_list.append(fund_info_dict)
return fund_list
# 定义一个协程函数,传入url,调用get_url访问页面并返回访问结果和页面内容
async def get_each_url(url):
code_response1, content_response1 = get_url(url)
print(code_response1)
if __name__ == '__main__':
# 这一部分是获取所有基金的url
url = 'http://****.com/****
code_response, content_response = get_url(url)
fund_list = handle_response(content_response)
# 单线程处理30个url
print('单线程开始处理30个url')
start = time.time()
for fund in fund_list[:29]:
code_response, content_response = get_url(fund['fund_url'])
print(code_response)
end = time.time()
print('单线程处理30个url时的耗时:{}'.format(end - start))
# 多协程处理30个url
print('多协程处理30个url')
start1 = time.time()
# 定义一个task列表,列表中存放的是每个协程函数返回的协程对象,后面会把这个列表扔进协程loop中自动循环执行
task_list = []
# 协程函数get_each_url返回对象coroutine,然后存入task列表
for fun in fund_list[:29]:
coroutine = get_each_url(fun['fund_url'])
task_list.append(asyncio.ensure_future(coroutine))
# 开启一个协程loop循环,然后把task列表扔进这个loop中,并run开始执行
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(task_list))
end1 = time.time()
print('多协程处理30个url时的耗时:{}'.format(end1 - start1))
![](https://img.haomeiwen.com/i18474631/47c447ccf4ed7bc0.jpg)
网友评论