优化 Python 爬虫性能:异步爬取新浪财经大数据

小白学大数据
• 阅读 5

一、同步爬虫的瓶颈 传统的同步爬虫(如requests+BeautifulSoup)在请求网页时,必须等待服务器返回响应后才能继续下一个请求。这种阻塞式I/O操作在面对大量数据时存在以下问题: 速度慢:每个请求必须串行执行,无法充分利用网络带宽。 易被封禁:高频请求可能触发IP限制或验证码。 资源浪费:CPU在等待I/O时处于空闲状态。 解决方案:异步爬虫(Asynchronous Crawling) Python的asyncio+aiohttp库可以实现非阻塞I/O,允许同时发起多个请求,大幅提升爬取效率。 二、异步爬虫技术选型 技术方案 适用场景 优势 aiohttp HTTP请求 异步HTTP客户端,支持高并发 asyncio 事件循环 Python原生异步I/O框架 aiofiles 异步文件存储 避免文件写入阻塞主线程 uvloop 加速事件循环 替换asyncio 默认循环,性能提升2-4倍 三、实战:异步爬取新浪财经股票数据 目标 爬取新浪财经A股股票实时行情(代码、名称、价格、涨跌幅等)。 使用aiohttp实现高并发请求。 存储至CSV文件,避免数据丢失。 步骤1:分析数据接口 新浪财经的股票数据通常通过API返回,我们可以通过浏览器开发者工具(F12)抓包分析: 示例接口:https://finance.sina.com.cn/realstock/company/sh600000/nc.shtml 数据格式:部分数据直接渲染在HTML中,部分通过Ajax加载(如分时数据)。 步骤2:安装依赖库 步骤3:编写异步爬虫代码

import aiohttp
import aiofiles
from bs4 import BeautifulSoup
import csv
import time

# 替换为新浪财经股票列表API(示例)
STOCK_LIST_API = "https://finance.sina.com.cn/stock/sl/stock_list.html"
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}

async def fetch(session, url):
    """异步获取网页内容"""
    async with session.get(url, headers=HEADERS) as response:
        return await response.text()

async def parse_stock_data(html):
    """解析股票数据(示例:仅提取名称和价格)"""
    soup = BeautifulSoup(html, "html.parser")
    stock_name = soup.select_one(".stock-name").text.strip() if soup.select_one(".stock-name") else "N/A"
    stock_price = soup.select_one(".price").text.strip() if soup.select_one(".price") else "N/A"
    return {"name": stock_name, "price": stock_price}

async def save_to_csv(data, filename="stocks.csv"):
    """异步写入CSV"""
    async with aiofiles.open(filename, mode="a", encoding="utf-8", newline="") as f:
        writer = csv.writer(f)
        await writer.writerow([data["name"], data["price"]])

async def crawl_stock(stock_code, session):
    """爬取单只股票数据"""
    url = f"https://finance.sina.com.cn/realstock/company/{stock_code}/nc.shtml"
    try:
        html = await fetch(session, url)
        data = await parse_stock_data(html)
        await save_to_csv(data)
        print(f"爬取成功:{stock_code} - {data['name']}")
    except Exception as e:
        print(f"爬取失败:{stock_code} - {str(e)}")

async def main():
    """主协程:并发爬取多个股票"""
    stock_codes = ["sh600000", "sh601318", "sz000001"]  # 示例股票代码(可扩展)

    # 使用uvloop加速(仅限Unix系统)
    try:
        import uvloop
        asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    except ImportError:
        pass

    # 创建aiohttp会话
    async with aiohttp.ClientSession() as session:
        tasks = [crawl_stock(code, session) for code in stock_codes]
        await asyncio.gather(*tasks)

if __name__ == "__main__":
    start_time = time.time()
    asyncio.run(main())
    print(f"爬取完成,耗时:{time.time() - start_time:.2f}秒")

四、性能优化策略

  1. 控制并发量 新浪财经可能限制高频请求
  2. 使用代理IP 避免IP被封:
  3. 随机User-Agent 减少被识别为爬虫的概率:
  4. 数据存储优化 异步数据库写入:如aiomysql、asyncpg。 批量写入:减少I/O次数。
    import aiohttp
    from bs4 import BeautifulSoup
    import pandas as pd
    from fake_useragent import UserAgent
    import aiomysql
    

使用 Semaphore 限制并发数

semaphore = asyncio.Semaphore(10) # 最大并发 10

代理信息

proxyHost = "www.16yun.cn" proxyPort = "5445" proxyUser = "16QMSOML" proxyPass = "280651"

构造代理 URL

PROXY = f"http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}"

随机 User-Agent

ua = UserAgent()

数据库配置

DB_CONFIG = { 'host': 'localhost', 'port': 3306, ' user': 'your_username', 'password': 'your_password', 'db': 'your_database', 'charset': 'utf8mb4' }

数据存储优化:异步数据库写入

async def save_to_db(data): conn = await aiomysql.connect(**DB_CONFIG) async with conn.cursor() as cur: await cur.executemany("INSERT INTO finance_data (column1, column2, column3) VALUES (%s, %s, %s)", data) await conn.commit() conn.close()

爬取单个股票数据

async def crawl_stock(stock_code, session): async with semaphore: url = f"https://finance.sina.com.cn/stock/{stock_code}.html" HEADERS = {"User-Agent": ua.random} async with session.get(url, headers=HEADERS, proxy=PROXY) as response: html = await response.text() data = parse(html) return data

解析网页内容

def parse(html): soup = BeautifulSoup(html, 'html.parser') # 假设数据在特定的表格中 table = soup.find('table', {'class': 'example'}) data = [] for row in table.find_all('tr'): cols = row.find_all('td') cols = [ele.text.strip() for ele in cols] data.append([ele for ele in cols if ele]) return data

主函数

async def main(stock_codes): async with aiohttp.ClientSession() as session: tasks = [crawl_stock(stock_code, session) for stock_code in stock_codes] all_data = await asyncio.gather(*tasks) # 扁平化数据 flat_data = [item for sublist in all_data for item in sublist] # 异步批量写入数据库 await save_to_db(flat_data)

示例股票代码列表

stock_codes = [ '000001', '000002', # 更多股票代码 ]

运行爬虫

asyncio.run(main(stock_codes))


五、对比同步与异步爬虫性能
指标
同步爬虫(requests)
异步爬虫(aiohttp)
100次请求耗时
~20秒
~3秒
CPU占用
低(大量时间在等待)
高(并发处理)
反爬风险
高(易触发封禁)
较低(可控并发)
点赞
收藏
评论区
推荐文章
菜鸟阿都 菜鸟阿都
4年前
创建免费ip代理池
     反爬技术越来越成熟,为了爬取目标数据,必须对爬虫的请求进行伪装,骗过目标系统,目标系统通过判断请求的访问频次或请求参数将疑似爬虫的ip进行封禁,要求进行安全验证,通过python的第三方库faker可以随机生成header伪装请求头,并且减缓爬虫的爬取速度,能很好的避过多数目标系统的反扒机制,但对一些安全等级
Wesley13 Wesley13
3年前
IO模型(BIO,NIO,AIO)及其区别
BIO:同步阻塞IONIO:同步非阻塞IOAIO:异步非阻塞IO先弄清楚同步、异步,阻塞、非阻塞概念。io操作分为两部分,发起io请求,和io数据读写。阻塞、非阻塞主要是针对线程发起io请求后,是否立即返回来定义的,立即返回称为非阻塞io,否则称为阻塞io。同步、异步主要针对io数据读写来定义的,读写数据过程中不阻塞线程称为异步io
Wesley13 Wesley13
3年前
Java BIO
同步与异步,阻塞与非阻塞同步:当前线程发起了一个调用或请求,然后当前线程需要等待该调用结束返回结果才能继续往下进行其他操作。异步:当前线程发起了一个调用或请求,然后当前线程不需等待调用的执行结果就可以继续往下执行(请求交由另一个线程去执行),之后可以通过被调用者的状态改变或者被调用者主动发出通知来获得执行结果
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Easter79 Easter79
3年前
SwiftUI 跨组件数据传递
作者:Cyandev,iOS和MacOS开发者,目前就职于字节跳动0x00前言众所周知,SwiftUI的开发模式与React、Flutter非常相似,即都是声明式UI,由数据驱动(产生)视图,视图也会与数据自动保持同步,框架层会帮你处理“绑定”的问题。在声明式UI中不存在命令式地让一个视图变成xxx
异步爬虫实战:实际应用asyncio和aiohttp库构建异步爬虫
在网络爬虫的开发中,异步爬虫已经成为一种非常流行的技术。它能够充分利用计算机的资源,提高爬虫效率,并且能够处理大量的运算请求。Python中的asyncio和aiohttp库提供了强大的异步爬虫支持,使得开发者能够轻松构建高效的异步爬虫。什么是异动爬虫?为
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
小白学大数据 小白学大数据
2个月前
Python爬虫多次请求后被要求验证码的应对策略
在互联网数据采集领域,Python爬虫是一种强大的工具,能够帮助我们高效地获取网页数据。然而,在实际应用中,许多网站为了防止恶意爬取,会在检测到频繁请求时要求用户输入验证码。这无疑给爬虫的正常运行带来了挑战。本文将详细介绍Python爬虫在多次请求后被要求
小白学大数据 小白学大数据
3星期前
如何通过requests和time模块限制爬虫请求速率?
一、为什么需要限制爬虫请求速率?在爬取网站数据时,网站服务器需要处理我们的请求并返回数据。如果爬虫的请求过于频繁,服务器可能会因为负载过高而崩溃,或者将我们的爬虫IP地址封禁。此外,许多网站都有反爬虫机制,例如检测单位时间内来自同一IP的请求频率。如果请求
小白学大数据
小白学大数据
Lv1
男 · 亿牛云 · python技术
宁为代码类弯腰,不为bug点提交!
文章
111
粉丝
5
获赞
18