为你的爬虫提提速?(代码片段)

jclian91 jclian91     2023-01-08     160

关键词:

项目介绍

??本文将展示如何利用Pyhton中的异步模块来提高爬虫的效率。
??我们需要爬取的目标为:融360网站上的理财产品信息(https://www.rong360.com/licai-bank/list/p1),页面如下:

技术分享图片

我们需要爬取86394条理财产品的信息,每页10条,也就是8640个页面。
??在文章Python爬虫(16)利用Scrapy爬取银行理财产品信息(共12多万条)中,我们使用爬虫框架Scrapy实现了该爬虫,爬取了127130条数据,并存入MongoDB,整个过程耗时3小时。按道理来说,使用Scrapy实现爬虫是较好的选择,但是在速度上,是否能有所提升呢?本文将展示如何利用Pyhton中的异步模块(aiohtpp和asyncio)来提高爬虫的效率。

爬虫项目

??我们的爬虫分两步走:

  1. 爬取融360网页上的理财产品信息并存入csv文件;
  2. 读取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"<tbody>[sS]*?</tbody>", html)[0]
    trs = re.findall(r"<tr [sS]*?</tr>", tbody)
    for tr in trs:
        tds = re.findall(r"<td[sS]*?</td>", tr)
        name,bank = re.findall(r‘title="(.+?)"‘, ‘‘.join(tds))
        name = name.replace(‘&amp;‘, ‘‘).replace(‘quot;‘, ‘‘)
        currency, startDate, endDate, amount = re.findall(r‘<td>(.+?)</td>‘, ‘‘.join(tds))
        period = ‘‘.join(re.findall(r‘<td class="td7">(.+?)</td>‘, tds[5]))
        proType = ‘‘.join(re.findall(r‘<td class="td7">(.+?)</td>‘, tds[6]))
        profit = ‘‘.join(re.findall(r‘<td class="td8">(.+?)</td>‘, 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/238a13995b2b 。完整的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;

输出结果如下:

技术分享图片





利用腾讯云为你的域名申请并配置免费ssl一年(代码片段)

我想,点进来的朋友,应该都知道SSL的重要性吧。这里就简单提一下,大型网站域名只有配置了SSL后,才会更加安全。现在,微信小程序也开始要求后台必须是SSL配置后的域名了。说了这么多,估计有些人还是有些晕。没关系,... 查看详情

python爬虫提速小技巧,多线程与多进程(附源码示例)(代码片段)

目录前言一、线程与进程1.1进程(Process)1.2线程(Thread)1.3小结二、Threading模块2.1创建多线程2.1.1直接调用2.1.2继承调用(推荐使用)2.2多线程传参2.2.1直接调用传参2.2.2继承调用传参(推荐使用)2.... 查看详情

pytorchio提速

...,加快了io。如何给你PyTorch里的Dataloader打鸡血轻轻松松为你的Linux系统创建RAMDisk把内存当硬盘,提速你的linux系统Linux创建使用内存硬盘(RAMDISK) 2.使用英伟达的 NVIDIA/DALI 模块Alibrarycontainingbothhighlyoptimized 查看详情

比requests更强大python库,让你的爬虫效率提高一倍!

来自早起Python最近公司 Python后端项目进行重构,整个后端逻辑基本都变更为采用"异步"协程的方式实现。看着满屏幕经过asyncawait(协程在Python中的实现)修饰的代码,我顿时感到一脸懵逼,不知所措。... 查看详情

比requests更强大python库,让你的爬虫效率提高一倍

最近公司 Python后端项目进行重构,整个后端逻辑基本都变更为采用"异步"协程的方式实现。看着满屏幕经过asyncawait(协程在Python中的实现)修饰的代码,我顿时感到一脸懵逼,不知所措。虽然之前有了... 查看详情

为你的macosapp添加开机自启动(swift)(代码片段)

猴子原创,欢迎转载。转载请注明:转载自Cocos2Der-CSDN,谢谢!原文地址:http://blog.csdn.net/cocos2der/article/details/52104828关于Mac下如何给自己App添加开机自启动功能,你可以了解下MacDeveloperLibrary中的说明。Therearetwow... 查看详情

想开发网页爬虫,发现被反爬了?想对app抓包,发现数据被加密了?不要担心,这里可以为你解决。(代码片段)

 全面超越Appium,使用Airtest超快速开发App爬虫想开发网页爬虫,发现被反爬了?想对App抓包,发现数据被加密了?不要担心,使用Airtest开发App爬虫,只要人眼能看到,你就能抓到,最快只需要2分钟,兼容Unity3D、Cocos2dx-*、Andr... 查看详情

为你的go应用创建轻量级docker镜像?(代码片段)

缩小Go二进制文件大小环境youmen@youmendeMacBook-Pro%gcc-dumpversion12.0.5youmen@youmendeMacBook-Pro%goversiongoversiongo1.16.5darwin/amd64gobuild使用的是静态编译,会将程序的依赖一起打包,这样一来编译得到的可执行文件可以直接在目标平台运行,无... 查看详情

集成华为imagekit美化功能为你的图片增添新元素(代码片段)

...任意添加、拖动、缩放,且可以自定义花字的文本内容,为你的图片增添新活力。应用场景贴纸花字大多数可用于修图软件里,你可选择与图片风格相搭配的贴纸花字,且类型丰富多样。开发实战下面给大家介绍怎么集成Imagekit... 查看详情

为你的sublimetext编辑器安装变量命名插件神器codelf(代码片段)

...个是缓存失效,一个是命名。”因此,有一款能为你的变量自动提供命名的工具是不是特别关键呢?Code 查看详情

爬虫相关法律知识(代码片段)

网络爬虫道德的话:客户授权or爬取公开数据、尽量放慢你的速度、尽量遵循robots、不要公开你的爬虫源码、不要分享你的爬虫数据。2017.06.01号《中华人民共和国网络安全法》开始实施,这个安全法在爬虫的这一块宝地上掀一阵... 查看详情

你可能需要为你的app适配ios11(代码片段)

本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/AZFrqL9dnlgA6Vt2sVhxIw作者:sonialiu导语:iOS11为整个生态系统的UI元素带来了一种更加大胆、动态的新... 查看详情

网络爬虫入门:你的第一个爬虫项目(requests库)(代码片段)

0.采用requests库虽然urllib库应用也很广泛,而且作为Python自带的库无需安装,但是大部分的现在python爬虫都应用requests库来处理复杂的http请求。requests库语法上简洁明了,使用上简单易懂,而且正逐步成为大多数网络爬取的标准。... 查看详情

ubuntu下为你的jupyternotebook配置桌面快捷方式和应用图标(代码片段)

文章目录前言一、配置相关脚本文件1.创建脚本文件jupyter.sh2.配置相关脚本文件3.设置可执行权限二、桌面文件的配置1.创建桌面文件jupyter.desktop2.移动脚本文件到命令环境3.配置图标4.配置相关桌面文件5.设置可执行权限三、配置... 查看详情

情人节要到了,为你的女友拼一张照片墙吧!(代码片段)

如何用Python将你的生活照片简单拼接为人像照、照片墙前言一、pip安装相关库二、照片准备二、图片拼接1.引入库2.变量设置3.功能函数4.主函数5.完整代码运行结果总结前言身为程序员,每天陪女友的时间还不如敲键盘的时间... 查看详情

200行js代码为你的网页挂上红灯笼(代码片段)

 目录一、前言二、效果展示局部效果全局效果三、代码讲解1.确定位置2.绘制灯笼3.动态效果四、添加脚本到网页1.下载万能的油猴2.安装使用3.附录一、前言除夕夜,在门前挂上灯笼有鸿(红)运当头的吉祥寓意,... 查看详情

爬虫速度太慢?来试试用异步协程提速吧!(代码片段)

...任务的时候,程序常常会因为等待IO而阻塞。比如在网络爬虫中,如果我们使用requests库来进行请求的话,如果网站响应速度过慢,程序一直在等待网站响应,最后导致其爬取效率是非常非常低的。为了解决这类问题,本文就来... 查看详情

小白向教程从零开始为你的手机安装win11系统(代码片段)

本教程基于项目RenegadeProject,为本人原创,有部分借鉴和引用,已于文中注明。本人能力有限,从小白到写出这篇文章不过一周的时间,如有谬误请各位指正。注意:1.本教学使用一加6(8G+128G)... 查看详情