摘要:项目介绍本文将展示如何利用中的异步模块来提高爬虫的效率。使用用的爬虫爬取了条数据,耗时小时,该爬虫爬取条数据,耗时半小时。如果是同样的数据量,那么爬取条数据耗时约小时,该爬虫仅用了爬虫的四分之一的时间就出色地完成了任务。
项目介绍
本文将展示如何利用Pyhton中的异步模块来提高爬虫的效率。
我们需要爬取的目标为:融360网站上的理财产品信息(https://www.rong360.com/licai...),页面如下:
我们需要爬取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 re import time import aiohttp import asyncio import pandas as pd import 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])+" "+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期FGAB15015A 2018-10-17 14:03:35,257 - INFO: 86391 润鑫月月盈2号 总共耗时:1787.4312353134155 **************************************************可以看到,在这个爬虫中,我们爬取了86391条数据,耗时1787.4秒,不到30分钟。虽然数据比预期的少了3条,但这点损失不算什么。来看一眼csv文件中的数据:
OK,离我们的目标还差一步,将这个csv文件存入至MySQL,具体的操作方法可参考文章:Python之使用Pandas库实现MySQL数据库的读写:https://www.jianshu.com/p/238... 。完整的Python代码如下:# -*- coding: utf-8 -*- # 导入必要模块 import pandas as pd from 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_1 2018-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_1 2018-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_1 2018-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 ROLLBACK 2018-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 COMMIT 2018-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中的数据:
总结让我们来比较该爬虫与使用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;输出结果如下:
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/44801.html
相关文章
分享几个YYDS的Pycharm插件
摘要:大家好,我是一行之前一行分享过好用的几种编辑器,测试有没有下载成功,用来做数据分析,开发的大杀器,等等,小众猿群使用那在用这个开发大杀器的同时,一行也来分享几个它很好用的插件,来给你的搬砖提提速可以作为摸鱼好助手次下载 ...
【Python】一文弄懂python装饰器(附源码例子)
摘要:装饰器的使用符合了面向对象编程的开放封闭原则。三简单的装饰器基于上面的函数执行时间的需求,我们就手写一个简单的装饰器进行实现。函数体就是要实现装饰器的内容。类装饰器的实现是调用了类里面的函数。类装饰器的写法比我们装饰器函数的写法更加简单。 目录 前言 一、什么是装饰器 二、为什么要用装饰器 ...
Python爬虫理论之cookie验证,不回顾下历史,套路都不知道怎么来的!
摘要:在发明之初,为了帮助服务器同步网页上的用户信息,同时保存用户操作,以此减轻服务器压力。由正在浏览的网站创建的被称为第一方。这些第三方怎么来的呢他们又有什么作用了。写在最后了解历史,有助于,我们更好的定位问题。 ...
提速30%:FoxOne 使用 Electron browserview 的最佳实践
摘要:最初,也在使用,并且最初看来功能安好。和的区别最大的区别在于托管于而不是。存在的问题在使用中,我们发现存在的问题主要表现在两方面。使用考虑到的独立性,我们设计了一个来管理所有,并使用和建立通讯。 在 FoxOne 1.5.1 版更新中,打开各个交易所网页的速度得到了巨大提升。 我们分别在不同的网络环境下,测算了新版 FoxOne 在 Dom 加载和页面加载条件下的所需时间: showI...
我的第一个豆瓣短评爬虫
摘要:,借鉴之前使用的经验,尝试直接使用与发现,豆瓣的短评,最一开始还好,但是在爬取将近十多页的短评时,会报出的异常,查询后得知,应该是豆瓣对于游客用户的限制,需要登录才可以。爬虫实践战狼豆瓣影评分析 豆瓣上有着大量的影视剧的评论,所以说,要是想要实现对广大人民群众的观点的分析,对一部片子的理解,综合来看大家的评论是很有必要的。而短评作为短小精干的快速评论入口,是值得一谈的。 所以先要实现对...
发表评论
0条评论
yanest
男|高级讲师
TA的文章
阅读更多
云主机什么配置-云主机哪种配置才算好?
阅读 3391·2021-09-22 15:17
c学习笔记——自定义qsort函数
阅读 2739·2021-09-02 15:15
css 布局2
阅读 1748·2019-08-30 15:54
ABAP的权限检查跟踪(Authorization trace)工具
阅读 2000·2019-08-30 14:02
去重方法小结
阅读 2529·2019-08-29 16:58
vue实现选中效果
阅读 2987·2019-08-29 16:08
ReactNative实现tab标签组合
阅读 1330·2019-08-26 12:24
es6/es7之Decorator装饰器
阅读 1652·2019-08-26 10:41
阅读需要支付1元查看