“数据超人”MCP工具,到底是怎么让数据‘燃’起来的?
一个数据分析师真实使用体验和一些心得
我作为一名数据分析师,每天最多的工作就是抽取数据、过滤数据、制作BI可视化图形、分析数据,这个过程其实还挺麻烦的,首先就是先抽取数据,把业务系统已有的数据抽取出来,得到这次需求大概需要的数据之后,然后进行一些数据的清洗和转换,然后制作可视化图形。
其实我本身也是已经使用阿里云产品很久了,本身公司整体业务系统架构就都是采用的阿里云的产品,另外我个人也是使用了阿里云的E-MapReduce,云原生数据仓库AnalyticDB,尤其是前者基本上是现在使用的主要的离线数仓使用
痛点
其实每次接到需求之后,从基础数据到可视化图形,中间的开发过程还是挺让人头大的,尤其是业务方催的很紧的时候,这个时候就得拼命加班去干!
Excel
Excel是最开始采用的工具,从最开始把数据导出来在Excel中制作可视化图形,但是一开始还勉强能应对,但是公司后面的发展越来越大,业务订单量也越来越大,如果需要结合到订单商品或者一些日志型的数据进行分析的话,那Excel明显就不够用,毕竟一个Excel表格超过100万的数据量就会出现丢失数据,并且速度太慢了,卡的很,只能适合轻量的数据,数据量一大就直接拜拜了,所以这也是业务分析人员一个头疼的重要原因,老板需要的数据很难提供出来。
Python
对于使用Excel来分析数据的弊端,Python确实能够很好的解决问题,哪怕数据量大一些也是可以接受的,而且功能比较强大,需要什么样的功能直接自己手动开发就好了,还可以通过使用爬虫爬取自己需要的数据,然后进行数据处理。
在进行数据处理和可视化的时候,Python的数据分析三剑客,NumPy,Pandas,Matplotlib 那可谓是想做什么数据就做什么数据,不管是简单的场景还是复杂的场景都能够游刃有余。
天气可视化
比如说通过爬取天气网站的数据然后进行可视化展示,下面是我自己原来做的一个爬虫代码和可视化,作为参考这个Python代码会获取到北京最近一周的天气信息。
技术栈
requests作用: 我是通过request发送HTTP请求,来获取到中国天气网北京天气的网页内容
lxml作用: HTML/XML解析工具,上面获取到网页内容后需要通过使用XPath语法来解析网页中的内容,主要是吧天气的数据提取出来
pandas作用: 数据处理和分析库,这个无需多言,数据处理的神器yyds,将解析好的数据转换成DataFrame格式,然后就可以进行湖面的数据存储和处理
pyecharts作用: 这是一个Python数据可视化库,因为把数据处理好之后,需要进行可视化操作,可以制作柱形图、线形图等等,而且支持数据缩放等特性,功能还是很强大的
openpyxl作用: Excel文件读写库,最终需要把结果写入到本地的Excel表格中,进行持久化存储,方便发送给业务方进行分析,并且可以把可视化图表插入到Excel表中
整体总结一下操作过程,首先使用requests和lxml爬取到天气网站的页面的数据,得到自己需要的数据之后,就使用Pandas来进行数据的处理和清晰,然后使用pyecharts开生成可视化的图表,生成的图标使用snapshot-selenium转换成图片,最后把准备好的数据和可视化图表保存到Excel文件中
import requests
from lxml import etree
import pandas as pd
import sys
from typing import List, Dict
from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.commons.utils import JsCode
from pyecharts.globals import ThemeType
from pyecharts.render import make_snapshot
from snapshot_selenium import snapshot
from openpyxl import load_workbook
from openpyxl.drawing.image import Image as XLImage
import os
import tempfile
import re
class WeatherCrawler:
'''天气数据爬取与可视化工具类'''
def __init__(self, url: str = 'https://www.weather.com.cn/textFC/beijing.shtml'):
'''初始化参数'''
self.url = url
self.html = None # 存储原始HTML
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
}
# 更新XPath配置,区分白天和晚上
self.xpath_config = {
'date': '//ul[@class='day_tabs']/li[{}]//text()',
'city': '//div[@class='conMidtab'][{}]/div[@class='conMidtab3']/table/tr[{}]/td[{}]/a//text()',
'day_weather': '//div[@class='conMidtab'][{}]/div[@class='conMidtab3']/table/tr[{}]/td[{}]//text()',
'day_wind': '//div[@class='conMidtab'][{}]/div[@class='conMidtab3']/table/tr[{}]/td[{}]/span[{}]//text()',
'day_temp': '//div[@class='conMidtab'][{}]/div[@class='conMidtab3']/table/tr[{}]/td[{}]//text()',
'night_weather': '//div[@class='conMidtab'][{}]/div[@class='conMidtab3']/table/tr[{}]/td[{}]//text()',
'night_wind': '//div[@class='conMidtab'][{}]/div[@class='conMidtab3']/table/tr[{}]/td[{}]/span[{}]//text()',
'night_temp': '//div[@class='conMidtab'][{}]/div[@class='conMidtab3']/table/tr[{}]/td[{}]//text()',
}
def fetch_html(self) -> str:
'''获取并解析HTML内容'''
try:
response = requests.get(self.url, headers=self.headers)
response.raise_for_status()
response.encoding = response.apparent_encoding
self.html = etree.HTML(response.text)
return response.text
except requests.exceptions.RequestException as e:
raise ValueError(f'请求失败: {e}')
def parse_daily_weather(self, day_index: int) -> List[Dict]:
'''解析单日天气数据(核心解析逻辑)
:param day_index: 日期索引(1-7对应未来7天)
:return: 单日天气数据列表(字典格式)
'''
if not self.html:
raise RuntimeError('请先调用fetch_html()获取HTML内容')
daily_data = []
date = self.html.xpath(self.xpath_config['date'].format(day_index))[0].strip()
for row in range(1, 18): # 表格行(1-17对应17个区县)
# 动态计算td索引(首行和其他行结构不同)
td_offset = 2 if row == 1 else 1
try:
# 提取各字段(使用XPath配置)
city = self.html.xpath(self.xpath_config['city'].format(day_index, row, td_offset))[0].strip()
# 白天数据
day_weather = self.html.xpath(self.xpath_config['day_weather'].format(day_index, row, td_offset + 1))[0].strip()
day_wind1 = self.html.xpath(self.xpath_config['day_wind'].format(day_index, row, td_offset + 2, 1))[0].strip()
day_wind2 = self.html.xpath(self.xpath_config['day_wind'].format(day_index, row, td_offset + 2, 2))[0].strip()
# 处理白天最高气温数据
day_temp_str = self.html.xpath(self.xpath_config['day_temp'].format(day_index, row, td_offset + 3))[0].strip()
day_temp = self.extract_temperature(day_temp_str)
# 晚上数据
night_weather = self.html.xpath(self.xpath_config['night_weather'].format(day_index, row, td_offset + 4))[0].strip()
night_wind1 = self.html.xpath(self.xpath_config['night_wind'].format(day_index, row, td_offset + 5, 1))[0].strip()
night_wind2 = self.html.xpath(self.xpath_config['night_wind'].format(day_index, row, td_offset + 5, 2))[0].strip()
# 处理晚上最高气温数据
night_temp_str = self.html.xpath(self.xpath_config['night_temp'].format(day_index, row, td_offset + 6))[0].strip()
night_temp = self.extract_temperature(night_temp_str)
daily_data.append({
'日期': date,
'城市': city,
'白天天气现象': day_weather,
'白天风向风力': f'{day_wind1} {day_wind2}',
'白天最高气温': day_temp,
'晚上天气现象': night_weather,
'晚上风向风力': f'{night_wind1} {night_wind2}',
'晚上最高气温': night_temp
})
except (IndexError, ValueError) as e:
print(f'解析第{day_index}天第{row}行时出错: {e},跳过该行')
continue
return daily_data
@staticmethod
def extract_temperature(temp_str: str) -> int:
'''从字符串中提取温度值'''
# 尝试提取数字部分
match = re.search(r'(-?\d+)', temp_str)
if match:
return int(match.group(1))
# 如果无法提取数字,尝试直接转换
try:
return int(temp_str)
except ValueError:
print(f'无法转换温度值: {temp_str},使用0代替')
return 0
@staticmethod
def save_to_excel(df: pd.DataFrame, file_path: str = None) -> str:
'''保存数据到Excel文件并返回文件路径'''
if df.empty:
print('无数据可保存')
return ''
# 清理文件名中的特殊字符
date_str = df['日期'].iloc[0].replace('(', '').replace(')', '').replace(' ', '_')
file_path = file_path or f'{date_str}.xlsx'
# 保存数据到Excel
df.to_excel(file_path, index=False)
print(f'数据已保存至: {file_path}')
return file_path
def create_bar_chart(self, df: pd.DataFrame) -> str:
'''创建昼夜气温对比柱状图并返回图片路径'''
if df.empty:
print('无数据可创建图表')
return ''
# 提取数据
cities = df['城市'].tolist()
day_temps = df['白天最高气温'].tolist()
night_temps = df['晚上最高气温'].tolist()
# 创建柱状图
bar_chart = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='1200px', height='600px'))
.add_xaxis(cities)
.add_yaxis('白天最高气温', day_temps, stack='stack1', category_gap='50%',
label_opts=opts.LabelOpts(position='top', formatter='{c}℃'))
.add_yaxis('晚上最高气温', night_temps, stack='stack1', category_gap='50%',
label_opts=opts.LabelOpts(position='top', formatter='{c}℃'))
.set_global_opts(
title_opts=opts.TitleOpts(title=f'{df['日期'].iloc[0]} 昼夜气温对比'),
xaxis_opts=opts.AxisOpts(
name='城市',
axislabel_opts=opts.LabelOpts(rotate=45, interval=0)
),
yaxis_opts=opts.AxisOpts(name='气温(℃)'),
toolbox_opts=opts.ToolboxOpts(),
datazoom_opts=[opts.DataZoomOpts(type_='inside')],
)
)
# 创建临时图片文件
img_path = tempfile.mktemp(suffix='.png')
make_snapshot(snapshot, bar_chart.render(), img_path)
return img_path
@staticmethod
def insert_image_to_excel(img_path: str, excel_path: str):
'''将图片插入Excel文件'''
if not os.path.exists(img_path) or not os.path.exists(excel_path):
print('图片或Excel文件不存在')
return
try:
# 加载Excel工作簿
wb = load_workbook(excel_path)
ws = wb.active
# 计算插入位置(在数据行下方)
data_rows = len(ws['A']) # 获取数据行数(包含标题)
img_row = data_rows + 2 # 在数据下方空一行
# 创建图像对象
img = XLImage(img_path)
# 设置图像大小(保持比例)
max_width = 1400
max_height = 500
# 调整宽度
if img.width > max_width:
ratio = max_width / img.width
img.width = max_width
img.height = int(img.height * ratio)
# 调整高度
if img.height > max_height:
ratio = max_height / img.height
img.height = max_height
img.width = int(img.width * ratio)
# 将图像添加到工作表
ws.add_image(img, f'A{img_row}')
# 保存修改
wb.save(excel_path)
print(f'图表已插入到Excel文件: {excel_path}')
# 删除临时图片文件
os.remove(img_path)
except Exception as e:
print(f'插入图表到Excel时出错: {e}')
if __name__ == '__main__':
# 使用示例
crawler = WeatherCrawler()
try:
# 步骤1:获取HTML
crawler.fetch_html()
# 步骤2:解析未来7天数据
for day in range(1, 8):
print(f'正在处理第{day}天数据...')
# 解析数据
daily_weather = crawler.parse_daily_weather(day)
df = pd.DataFrame(daily_weather)
if not df.empty:
# 保存Excel文件
excel_path = crawler.save_to_excel(df)
# 创建柱状图
img_path = crawler.create_bar_chart(df)
# 将图表插入Excel
if img_path:
crawler.insert_image_to_excel(img_path, excel_path)
else:
print(f'第{day}天无有效数据,跳过处理')
except Exception as e:
print(f'程序运行出错: {e}')
简单看一下输出的结果
痛点
根据前面的看起来,Python还是很强大的,基本上所有数据都可以处理成自己想要的样子,后续还可以通过Webhook,定时把数据发送到群机器人。
说到这里,看起来Python很强大,不过还是有缺点的,缺点就是门槛有点高,对于很多业务分析师来说,还要去学习Python,包括Python的各个模块,所以门槛还是比较高的,而且开发周期也是比较长的,当一个需求下来,到开发结束还是很耗费时间的,所以Python也不是最优项。
阿里云MCP智能体
其实本来我还有很多之前做分析的手段想跟大家分享,包括使用BI工具,不过BI工具也有很多限制,以及费用还是比较高的,不过现在的主角是MCP智能体,我现在已经忍不住来介绍了!
现在真可以说是AI的时代,如果说作为程序员应该最能感受到AI带给自己的便利,在自己写代码的时候又有几个敢说一点都没有使用AI呢,我自己感觉来说,淘汰我们的不是AI,而是会用AI的人,而我在实际的工作中,对数据的处理中也可以经常使用到AI帮我写一部分代码,但是当时就一直在想,使用AI也是只能一步步有问题去问AI,那么有没有什么办法,只需要我把自己想要的数据通过语言告诉AI,AI就能自动帮我完成一系列操作,直接生成我想要的数据, 中间的过程不需要我参与,这样我就可以节省很多时间来做一些其他的事情,那么阿里云的MCP智能体来了!
特点
跟传统的数据分析工具相比,传统的数据分析工具往往要么是门槛过高,需要会Python、sql等语言,或者就是需要花费重金去购买相关的BI产品,但是整体下来可视化流程还是很复杂,而且需要花费很多时间和金钱,然而阿里云的MCP智能体可以直接基于云数据库 PolarDB Mysql版与阿里云百炼,并且结合MCP工具的SQL执行能力还有画图能力,利用AI大模型进行高效的数据分析
从以前的SQL开发或者Python开发然后到BI可视化,这一系列复杂的流程就直接一句话搞定,不需要多余的人工操作,这才是提高工作效率。然后就让我们开始先去体验一下吧
架构
本方案基于 PolarDB 构建智能数据库分析应用,集成阿里云百炼(简称“百炼”),提供开箱即用的智能化分析能力。PolarDB 作为云原生数据库,具备 Serverless 弹性伸缩、自动存储扩缩等特性,实现资源的高效利用。其高性能架构和多可用区部署保障业务稳定可靠,通过智能分层存储技术,在确保性能的同时优化成本,让企业轻松应对各类业务场景需求。
1 个云数据库 PolarDB MySQL 版集群:支持海量数据实时写入与更新。1 个 Function AI 项目:全托管的 Serverless 计算服务,用于部署模型服务与 Web 应用。百炼模型服务:调用 API 使用文本模型进行内容生成。
个人感受
说一下我自己的个人感受,在免费部署了之后,使用模拟数据测试了一下,反正是直接改变了我对传统数据分析的认知
首先是理解能力,它完全可以把我说的话来转换成我的需求,并且有的时候我表达的需求可能还不是很完美,但是它还是能够把我的需求进行优化,得到我真实想要的结果,比产品经理合格多了。
然后就是速度,依靠大模型处理速度简直绝了,Excel要处理一上午的工作丢给MCP后,去倒一杯咖啡的功夫就给你搞定了。对于一些常见的需求,比如说看近30天客户的活跃曲线,同比环比,留存率等等,我只需要在输入框中输出一句话,直接就帮我自动完成了,这不是给了我很多摸鱼的时间了吗,嘻嘻
再说一说可视化方面,太nice了!我感觉现在工作已经不需要动脑子了,直接引用我的数据源,我可以让MCP给我推荐做成那种图表比较好看,比如数值对比就使用柱状图,趋势分析就使用折线图,连配色都能自动给我配成各种风格,或者直接做成我指定的图表,而且可以让我直接导出成Excel表格或者PPT,真的是完全不用动脑了,只需要打几个字,鼠标点一点,就好像有一个人在给我打工一样,下面可以看看我给出的一些数据之后,MCP自动帮我可视化的图表
说一下最厉害的点,它甚至能自动识别出数据中的异常,我导入了用户行为的数据,有一些异常值,它可以直接帮我识别出来,然后提示我可以用什么样的值来进行填充,我只需要指挥就行了。我都不敢想如果是之前使用Python写的话最起码不得写几十行代码!
另外上面也说过,公司本身就是用阿里云的产品,那么就更贴合了,可以直接打通数据库,和分析数据库结合起来,充分发挥出云原生的优势
最重要的还是上手特别快,哪怕是没有任何基础的人都可以在很短的时间内学会如何去操作,而且可以开发一些自己的玩法,然后整体用下来给我的感觉其实就是,上手之后就离不开了,之前一大套流程,现在只需要几句话就能完成,对我来说MCP已经非常强大了,不过话说回来,工具总是在不断进步的,我真的很期待未来会发展到什么样子,最后说一下,自己总结的可能不是很好,我更推荐大家自己上手体验一下,一定会让你感受到不一样的感觉!
赞6
踩0