本文将展示如何利用Pyhton中的异步模块来提高爬虫的效率。
融360页面上的理财产品
我们需要爬取86394条理财产品的信息,每页10条,也就是8640个页面。
在文章Python爬虫(16)利用Scrapy爬取银行理财产品信息(共12多万条)中,我们使用爬虫框架Scrapy实现了该爬虫,爬取了127130条数据,并存入MongoDB,整个过程耗时3小时。按道理来说,使用Scrapy实现爬虫是较好的选择,但是在速度上,是否能有所提升呢?本文将展示如何利用Pyhton中的异步模块(aiohtpp和asyncio)来提高爬虫的效率。
我们的爬虫分两步走:
爬取融360网页上的理财产品信息并存入csv文件;
读取csv文件并存入至MySQL数据库。
首先,我们爬取融360网页上的理财产品信息并存入csv文件,我们使用aiohttp和asyncio来加速爬虫,完整的Python代码如下:
import reimport timeimport aiohttpimport asyncioimport pandas as pdimport logging# 设置日志格式logging.basicConfig(level = logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')
logger = logging.getLogger(__name__)
df = pd.Dataframe(columns=['name', 'bank', 'currency', 'startDate', 'endDate', 'period', 'proType', 'profit', 'amount'])# 异步HTTP请求async def fetch(sem, session, url):
async with sem:
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'} async with session.get(url, headers=headers) as response: return await response.text()# 解析网页async def parser(html):
# 利用正则表达式解析网页
tbody = re.findall(r"[sS]*?", html)[0]
trs = re.findall(r"", tbody) for tr in trs:
tds = re.findall(r"", tr)
name,bank = re.findall(r'title="(.+?)"', ''.join(tds))
name = name.replace('&', '').replace('quot;', '')
currency, startDate, endDate, amount = re.findall(r' (.+?) ', ''.join(tds))
period = ''.join(re.findall(r'(.+?) ', tds[5]))
proType = ''.join(re.findall(r'(.+?) ', tds[6]))
profit = ''.join(re.findall(r'(.+?) ', tds[7]))
df.loc[df.shape[0] + 1] = [name, bank, currency, startDate, endDate,
period, proType, profit, amount]
logger.info(str(df.shape[0])+'t'+name)# 处理网页async def download(sem, url):
async with aiohttp.ClientSession() as session: try:
html = await fetch(sem, session, url) await parser(html) except Exception as err:
print(err)# 全部网页urls = ["https://www.rong360.com/licai-bank/list/p%d"%i for i in range(1, 8641)]# 统计该爬虫的消耗时间print('*' * 50)
t3 = time.time()# 利用asyncio模块进行异步IO处理loop = asyncio.get_event_loop()
sem=asyncio.Semaphore(100)
tasks = [asyncio.ensure_future(download(sem, url)) for url in urls]
tasks = asyncio.gather(*tasks)
loop.run_until_complete(tasks)
df.to_csv('E://rong360.csv')
t4 = time.time()
print('总共耗时:%s' % (t4 - t3))
print('*' * 50)输出的结果如下(中间的输出已省略,以......代替):
**************************************************
2018-10-17 13:33:50,717 - INFO: 10 金百合第245期
2018-10-17 13:33:50,749 - INFO: 20 金荷恒升2018年第26期
......
2018-10-17 14:03:34,906 - INFO: 86381 翠竹同益1M22期FGAB15015A2018-10-17 14:03:35,257 - INFO: 86391 润鑫月月盈2号
总共耗时:1787.4312353134155**************************************************
可以看到,在这个爬虫中,我们爬取了86391条数据,耗时1787.4秒,不到30分钟。虽然数据比预期的少了3条,但这点损失不算什么。来看一眼csv文件中的数据:
csv文件中的数据
OK,离我们的目标还差一步,将这个csv文件存入至MySQL,具体的操作方法可参考文章:Python之使用Pandas库实现MySQL数据库的读写:https://www.jianshu.com/p/238a13995b2b 。完整的Python代码如下:
# -*- coding: utf-8 -*-# 导入必要模块import pandas as pdfrom sqlalchemy import create_engine# 初始化数据库连接,使用pymysql模块engine = create_engine('mysql+pymysql://root:******@localhost:33061/test', echo=True)
print("Read CSV file...")# 读取本地CSV文件df = pd.read_csv("E://rong360.csv", sep=',', encoding='gb18030')# 将新建的Dataframe储存为MySQL中的数据表,不储存index列df.to_sql('rong360',
con=engine,
index= False,
index_label='name'
)
print("Write to MySQL successfully!")输出结果如下(耗时十几秒):
Read CSV file...2018-10-17 15:07:02,447 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'sql_mode'2018-10-17 15:07:02,447 INFO sqlalchemy.engine.base.Engine {}2018-10-17 15:07:02,452 INFO sqlalchemy.engine.base.Engine SELECt DATAbase()2018-10-17 15:07:02,452 INFO sqlalchemy.engine.base.Engine {}2018-10-17 15:07:02,454 INFO sqlalchemy.engine.base.Engine show collation where `Charset` = 'utf8mb4' and `Collation` = 'utf8mb4_bin'2018-10-17 15:07:02,454 INFO sqlalchemy.engine.base.Engine {}2018-10-17 15:07:02,455 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS CHAr(60)) AS anon_12018-10-17 15:07:02,456 INFO sqlalchemy.engine.base.Engine {}2018-10-17 15:07:02,456 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS CHAr(60)) AS anon_12018-10-17 15:07:02,456 INFO sqlalchemy.engine.base.Engine {}2018-10-17 15:07:02,457 INFO sqlalchemy.engine.base.Engine SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_bin AS anon_12018-10-17 15:07:02,457 INFO sqlalchemy.engine.base.Engine {}2018-10-17 15:07:02,458 INFO sqlalchemy.engine.base.Engine DESCRIBE `rong360`2018-10-17 15:07:02,458 INFO sqlalchemy.engine.base.Engine {}2018-10-17 15:07:02,459 INFO sqlalchemy.engine.base.Engine ROLLBACK2018-10-17 15:07:02,462 INFO sqlalchemy.engine.base.Engine
CREATE TABLE rong360 ( `Unnamed: 0` BIGINT,
name TEXT,
bank TEXT,
currency TEXT,
`startDate` TEXT,
`endDate` TEXT,
enduration TEXT,
`proType` TEXT,
profit TEXT,
amount TEXT
)2018-10-17 15:07:02,462 INFO sqlalchemy.engine.base.Engine {}2018-10-17 15:07:02,867 INFO sqlalchemy.engine.base.Engine COMMIT2018-10-17 15:07:02,909 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)2018-10-17 15:07:03,973 INFO sqlalchemy.engine.base.Engine INSERT INTO rong360 (`Unnamed: 0`, name, bank, currency, `startDate`, `endDate`, enduration, `proType`, profit, amount) VALUES (%(Unnamed: 0)s, %(name)s, %(bank)s, %(currency)s, %(startDate)s, %(endDate)s, %(enduration)s, %(proType)s, %(profit)s, %(amount)s)2018-10-17 15:07:03,974 INFO sqlalchemy.engine.base.Engine ({'Unnamed: 0': 1, 'name': '龙信20183773', 'bank': '龙江银行', 'currency': '人民币', 'startDate': '2018-10-12', 'endDate': '2018-10-14', 'enduration': '99天', 'proType': '不保本', 'profit': '4.8%', 'amount': '5万'}, {'Unnamed: 0': 2, 'name': '福瀛家NDHLCS20180055B', 'bank': '宁波东海银行', 'currency': '人民币', 'startDate': '2018-10-12', 'endDate': '2018-10-17', 'enduration': '179天', 'proType': '保证收益', 'profit': '4.8%', 'amount': '5万'}, {'Unnamed: 0': 3, 'name': '薪鑫乐2018年第6期', 'bank': '无为农商行', 'currency': '人民币', 'startDate': '2018-10-12', 'endDate': '2018-10-21', 'enduration': '212天', 'proType': '不保本', 'profit': '4.8%', 'amount': '5万'}, {'Unnamed: 0': 4, 'name': '安鑫MTLC18165', 'bank': '民泰商行', 'currency': '人民币', 'startDate': '2018-10-12', 'endDate': '2018-10-15', 'enduration': '49天', 'proType': '不保本', 'profit': '4.75%', 'amount': '5万'}, {'Unnamed: 0': 5, 'name': '农银私行·如意ADRY181115A', 'bank': '农业银行', 'currency': '人民币', 'startDate': '2018-10-12', 'endDate': '2018-10-16', 'enduration': '90天', 'proType': '不保本', 'profit': '4.75%', 'amount': '100万'}, {'Unnamed: 0': 6, 'name': '稳健成长(2018)176期', 'bank': '威海市商业银行', 'currency': '人民币', 'startDate': '2018-10-12', 'endDate': '2018-10-15', 'enduration': '91天', 'proType': '不保本', 'profit': '4.75%', 'amount': '5万'}, {'Unnamed: 0': 7, 'name': '季季红J18071', 'bank': '温州银行', 'currency': '人民币', 'startDate': '2018-10-12', 'endDate': '2018-10-16', 'enduration': '96天', 'proType': '不保本', 'profit': '4.75%', 'amount': '1万'}, {'Unnamed: 0': 8, 'name': '私人银行客户84618042', 'bank': '兴业银行', 'currency': '人民币', 'startDate': '2018-10-12', 'endDate': '2018-10-17', 'enduration': '99天', 'proType': '不保本', 'profit': '4.75%', 'amount': '50万'} ... displaying 10 of 86391 total bound parameter sets ... {'Unnamed: 0': 86390, 'name': '润鑫月月盈3号RX1M003', 'bank': '珠海华润银行', 'currency': '人民币', 'startDate': '2015-06-24', 'endDate': '2015-06-30', 'enduration': '35天', 'proType': '不保本', 'profit': '4.5%', 'amount': '5万'}, {'Unnamed: 0': 86391, 'name': '润鑫月月盈2号', 'bank': '珠海华润银行', 'currency': '人民币', 'startDate': '2015-06-17', 'endDate': '2015-06-23', 'enduration': '35天', 'proType': '不保本', 'profit': '4.4%', 'amount': '5万'})2018-10-17 15:07:14,106 INFO sqlalchemy.engine.base.Engine COMMIT
Write to MySQL successfully! 如果你还不放心,也许我们可以看一眼MySQL中的数据:
MySQL中的数据
总结 让我们来比较该爬虫与使用Scrapy的爬虫。使用Scrap用的爬虫爬取了127130条数据,耗时3小时,该爬虫爬取86391条数据,耗时半小时。如果是同样的数据量,那么Scrapy爬取86391条数据耗时约2小时,该爬虫仅用了Scrapy爬虫的四分之一的时间就出色地完成了任务。
最后,让我们看看前十名的银行及理财产品数量(按理财产品数量从高到低排列),输入以下MySQL命令:
use test;
SELECT bank, count(*) as product_num
FROM rong360
GROUP BY bank
ORDER BY product_num DESC
LIMIT 10;
输出结果如下:
作者:但盼风雨来_jc
链接:https://www.jianshu.com/p/e7871ca12664
Python相关栏目本月热门文章
- 1【Linux驱动开发】设备树详解(二)设备树语法详解
- 2别跟客户扯细节
- 3Springboot+RabbitMQ+ACK机制(生产方确认(全局、局部)、消费方确认)、知识盲区
- 4【Java】对象处理流(ObjectOutputStream和ObjectInputStream)
- 5【分页】常见两种SpringBoot项目中分页技巧
- 6一文带你搞懂OAuth2.0
- 7我要写整个中文互联网界最牛逼的JVM系列教程 | 「JVM与Java体系架构」章节:虚拟机与Java虚拟机介绍
- 8【Spring Cloud】新闻头条微服务项目:FreeMarker模板引擎实现文章静态页面生成
- 9JavaSE - 封装、static成员和内部类
- 10树莓派mjpg-streamer实现监控及拍照功能调试
- 11用c++写一个蓝屏代码
- 12从JDK8源码中看ArrayList和LinkedList的区别
- 13idea 1、报错java: 找不到符号 符号: 变量 log 2、转换成Maven项目
- 14在openwrt使用C语言增加ubus接口(包含C uci操作)
- 15Spring 解决循环依赖
- 16SpringMVC——基于MVC架构的Spring框架
- 17Andy‘s First Dictionary C++ STL set应用
- 18动态内存管理
- 19我的创作纪念日
- 20Docker自定义镜像-Dockerfile
热门相关搜索
路由器设置
木托盘
宝塔面板
儿童python教程
心情低落
朋友圈
vim
双一流学科
专升本
我的学校
日记学校
西点培训学校
汽修学校
情书
化妆学校
塔沟武校
异形模板
西南大学排名
最精辟人生短句
6步教你追回被骗的钱
南昌大学排名
清朝十二帝
北京印刷学院排名
北方工业大学排名
北京航空航天大学排名
首都经济贸易大学排名
中国传媒大学排名
首都师范大学排名
中国地质大学(北京)排名
北京信息科技大学排名
中央民族大学排名
北京舞蹈学院排名
北京电影学院排名
中国戏曲学院排名
河北政法职业学院排名
河北经贸大学排名
天津中德应用技术大学排名
天津医学高等专科学校排名
天津美术学院排名
天津音乐学院排名
天津工业大学排名
北京工业大学耿丹学院排名
北京警察学院排名
天津科技大学排名
北京邮电大学(宏福校区)排名
北京网络职业学院排名
北京大学医学部排名
河北科技大学排名
河北地质大学排名
河北体育学院排名



