基于Burp的网站数据收集及可视化

作业记录

本流程覆盖 “环境搭建→本地网站部署→数据采集→数据存储→数据清洗→可视化→成果验证” 全环节

前置准备:工具 / 软件清单

提前安装以下工具,版本匹配建议:

  1. Python 3.7+(推荐 3.9):https://www.python.org/downloads/
  2. MySQL 5.7/8.0 + Navicat(可视化管理):MySQL 官网下载社区版,Navicat 选免费版 / 试用版
  3. Burp Suite Community(抓包工具):https://portswigger.net/burp/communitydownload
  4. Kettle 9.4(数据清洗):https://community.hitachivantara.com/s/article/data-integration-pentaho-data-integration
  5. Anaconda(可选,创建独立虚拟环境):https://www.anaconda.com/download
  6. PyCharm(可选,代码编辑):https://www.jetbrains.com/pycharm/download/

搭建独立 Python 虚拟环境(避免依赖冲突)

打开 Anaconda Prompt(无 Anaconda 则打开 CMD/PowerShell):

  • (Anaconda)创建环境:conda create -n burp_data python=3.9,按提示输入y确认
  • 激活环境:conda activate burp_data(终端前缀出现(burp_data)即成功)

安装 Python 依赖库:

1
pip install flask pandas matplotlib pymysql  # 核心依赖,一键安装

验证:执行pip list,能看到 flask、pandas、matplotlib、pymysql 均在列表中,版本无报错即可。

部署本地测试网站(数据源)

新建项目文件夹(如burp_test_site),结构如下:

1
2
3
4
5
burp_test_site/
├─ app.py (后端脚本)
├─ static/ (可选,放样式,无则忽略)
└─ templates/
└─ index.html (首页模板)

用 PyCharm 打开该文件夹,选择解释器为burp_data虚拟环境(File→Settings→Python Interpreter)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!-- index.html代码 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>模拟电商商品页</title>
<!-- 引入Bootstrap CDN(无需本地安装) -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.goods-card { margin: 20px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.header { background-color: #0d6efd; color: white; padding: 20px; text-align: center; margin-bottom: 30px; }
</style>
</head>
<body>
<div class="header">
<h1>模拟电商商品展示平台</h1>
<p>基于Flask+Bootstrap搭建的测试网站</p>
</div>
<div class="container">
<div class="row">
{% for good in goods %}
<div class="col-md-4">
<div class="card goods-card">
<div class="card-body">
<h5 class="card-title">{{ good.name or '未命名商品' }}</h5>
<p class="card-text">价格:¥{{ good.price }}</p>
<p class="card-text">库存:{{ good.stock }}</p>
<p class="card-text">分类:{{ good.category or '未分类' }}</p>
<p class="card-text">销量:{{ good.sales }}</p>
<a href="" class="btn btn-primary">查看详情</a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

运行app.py:

  • 终端执行:python app.py
  • 看到终端输出Running on http://127.0.0.1:5000/即启动成功。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from flask import Flask, render_template
app = Flask(__name__)
# 模拟商品数据(包含空值、0值、无效值,用于后续清洗)
goods_data = [
{"id": 1, "name": "华为Mate70", "price": 6999, "stock": 100, "category": "手机", "sales": 500},
{"id": 2, "name": "苹果iPhone16", "price": 0, "stock": 80, "category": "", "sales": 300}, # price=0,category空值
{"id": 3, "name": "", "price": 2999, "stock": -5, "category": "平板", "sales": 0}, # name空,stock无效,sales=0
{"id": 4, "name": "小米Pad6", "price": 2499, "stock": 200, "category": "平板", "sales": 150},
{"id": 5, "name": "vivo X200", "price": 4599, "stock": 0, "category": "手机", "sales": 200} # stock=0]
# 首页(商品列表,美化后)@app.route('/')def index():
return render_template('index.html', goods=goods_data)
# 商品详情页@app.route('/detail/<int:goods_id>')def detail(goods_id):
good = next((g for g in goods_data if g['id'] == goods_id), None)
return render_template('detail.html', good=good)
if __name__ == '__main__':
app.run(debug=True, port=5000) # 本地启动,访问http://127.0.0.1:5000

验证:打开浏览器访问http://127.0.0.1:5000,能看到带商品列表的美化页面,包含异常值(如 “未命名商品”、库存 - 5 等)效果图如下:

Burp 抓包采集网站数据

  1. Burp 代理配置:

    • 启动 Burp Suite,选 “Temporary project”→“Next”→“Start Burp”。
    • 点击Proxy→Options→Add,端口填 8080,勾选Loopback only(仅抓本地请求),点击OK,确保代理状态为 “Running”。
  2. 浏览器代理配置:

  • Chrome/Edge:设置→高级→系统→打开计算机代理设置→手动设置代理,地址填127.0.0.1,端口8080,勾选 “对所有协议使用相同代理”,保存。
  1. 抓包并导出数据:
  • 浏览器刷新http://127.0.0.1:5000,回到 Burp→Proxy→HTTP history,筛选 URL 含/的 GET 请求(目标请求)。

  • 选中该请求,右键→Save items,保存类型选XML,文件名burp_requests.xml,保存到burp_test_site文件夹。

  1. 解析 XML 为 CSV:
  • xml_to_json.py复制到burp_test_site文件夹。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    # -*- coding: utf-8 -*-
    """
    Burp XML商品数据提取脚本
    功能:解析Burp导出的XML文件,提取商品信息并转为CSV格式
    适配场景:从本地Burp XML文件中提取商品数据,无需预处理和自动导入数据库
    """
    import xml.etree.ElementTree as ET
    import csv
    import re
    import logging
    import time
    import base64

    # -------------------------- 1. 本地日志初始化 --------------------------
    def init_logger():
    """初始化本地日志,仅保存到本地文件"""
    logger = logging.getLogger("burp_goods_extract")
    logger.setLevel(logging.INFO)
    if not logger.handlers:
    # 同时输出到控制台和文件
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)

    file_handler = logging.FileHandler("goods_extract.log", encoding="utf-8")
    file_handler.setLevel(logging.INFO)

    formatter = logging.Formatter(
    "%(asctime)s - %(levelname)s - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
    )
    console_handler.setFormatter(formatter)
    file_handler.setFormatter(formatter)

    logger.addHandler(console_handler)
    logger.addHandler(file_handler)
    return logger


    logger = init_logger()


    # -------------------------- 2. 解析Burp XML文件(核心:提取商品信息) --------------------------
    def parse_burp_xml_goods(xml_path):
    """
    解析Burp导出的XML文件,提取商品信息
    :param xml_path: 本地XML文件路径
    :return: 商品数据列表(字典)
    """
    goods_data = []
    try:
    tree = ET.parse(xml_path)
    root = tree.getroot()

    # 遍历Burp XML的item节点
    for item in root.findall(".//item"):
    response = item.find("response")
    if response is not None and response.text:
    try:
    # 解码base64响应内容为完整页面HTML
    response_html = base64.b64decode(response.text).decode("utf-8")
    logger.info("HTML解码成功,开始提取商品信息")
    except Exception as e:
    logger.warning(f"响应解码失败:{str(e)}")
    continue

    # 更健壮的提取方式:直接在整个HTML中搜索商品信息
    # 首先,提取所有商品名称
    names = re.findall(r'<h5 class="card-title">([^<]+)</h5>', response_html)

    # 提取所有价格
    prices = re.findall(r'价格:¥(\d+)', response_html)

    # 提取所有库存
    stocks = re.findall(r'库存:([^<]+)</p>', response_html)
    # 清理库存数据,只保留数字部分
    stocks_clean = []
    for stock in stocks:
    # 提取数字部分,包括可能的负号
    stock_match = re.search(r'(-?\d+)', stock)
    stocks_clean.append(stock_match.group(1) if stock_match else "0")

    # 提取所有分类
    categories = re.findall(r'分类:([^<]+)</p>', response_html)

    # 提取所有销量
    sales = re.findall(r'销量:(\d+)', response_html)

    logger.info(
    f"提取到字段数量:名称{len(names)}个,价格{len(prices)}个,库存{len(stocks_clean)}个,分类{len(categories)}个,销量{len(sales)}个")

    # 取最小长度,避免索引越界
    min_len = min(len(names), len(prices), len(stocks_clean), len(categories), len(sales))

    for i in range(min_len):
    # 构建商品数据字典
    goods_data.append({
    "id": str(i + 1),
    "name": names[i].strip(),
    "price": prices[i] if i < len(prices) else "0",
    "stock": stocks_clean[i] if i < len(stocks_clean) else "0",
    "category": categories[i].strip() if i < len(categories) else "未分类",
    "sales": sales[i] if i < len(sales) else "0"
    })
    logger.debug(
    f"提取商品:名称={names[i].strip()}, 价格={prices[i]}, 库存={stocks_clean[i]}, 分类={categories[i]}, 销量={sales[i]}")

    logger.info(f"解析完成:从XML提取{len(goods_data)}条商品记录(文件:{xml_path})")

    except FileNotFoundError:
    logger.error(f"Burp XML文件不存在:{xml_path}")
    except Exception as e:
    logger.error(f"XML解析失败:{str(e)}")

    return goods_data


    # -------------------------- 3. 商品数据转CSV --------------------------
    def goods2csv(data, csv_path):
    """
    将提取的商品数据转换为CSV文件
    :param data: 商品数据列表
    :param csv_path: CSV文件路径
    :return: 是否成功
    """
    if not data:
    logger.warning("无商品数据,CSV转换终止")
    return False

    try:
    # 定义CSV字段名
    fieldnames = ["id", "name", "price", "stock", "category", "sales"]

    with open(csv_path, "w", encoding="utf-8", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()

    # 写入所有商品数据
    for goods in data:
    writer.writerow(goods)

    logger.info(f"商品数据转CSV完成,输出文件:{csv_path}")
    return True

    except Exception as e:
    logger.error(f"CSV转换失败:{str(e)}")
    return False


    # -------------------------- 4. 显示表格格式的结果 --------------------------
    def display_table(goods_data, max_display=5):
    """以表格形式显示商品信息"""
    if not goods_data:
    print("未提取到商品数据")
    return

    print("\n" + "=" * 65)
    print("提取的商品信息(表格格式)")
    print("=" * 65)

    # 表头
    print(f"{'序号':<4} {'商品名称':<20} {'价格':<8} {'库存':<6} {'销量':<6} {'分类':<10}")
    print("-" * 65)

    # 显示数据
    for i, goods in enumerate(goods_data[:max_display], 1):
    name = goods['name'][:18] if len(goods['name']) > 18 else goods['name']
    price_display = f"¥{goods['price']}" if goods['price'] != "0" else "¥0"
    stock_display = goods['stock']
    sales_display = goods['sales']
    category_display = goods['category'][:8] if len(goods['category']) > 8 else goods['category']

    print(f"{i:<4} {name:<20} {price_display:<8} {stock_display:<6} {sales_display:<6} {category_display:<10}")

    print("=" * 65)


    # -------------------------- 5. 主函数 --------------------------
    def main():
    """主函数:执行商品数据提取和转换流程"""
    start_time = time.time()
    logger.info("=" * 50 + "开始商品数据提取" + "=" * 50)

    # 配置文件路径
    burp_xml_path = "burp_requests.xml" # Burp导出的XML文件
    output_csv_path = "goods_data.csv" # 输出的CSV文件

    # 执行流程
    goods_data = parse_burp_xml_goods(burp_xml_path)

    if not goods_data:
    logger.error("XML解析无有效商品数据,流程终止")
    print("\n错误:未提取到商品数据,请检查XML文件格式")
    return

    csv_ok = goods2csv(goods_data, output_csv_path)

    if csv_ok:
    # 打印提取结果摘要
    total_price = sum(int(goods["price"]) for goods in goods_data)
    total_stock = sum(int(goods["stock"]) for goods in goods_data)
    total_sales = sum(int(goods["sales"]) for goods in goods_data)

    logger.info(f"提取完成!")
    logger.info(f"商品总数:{len(goods_data)}")
    logger.info(f"总价格:¥{total_price}")
    logger.info(f"总库存:{total_stock}")
    logger.info(f"总销量:{total_sales}")
    logger.info(f"耗时:{round(time.time() - start_time, 2)}秒")
    logger.info(f"输出文件:{output_csv_path}")

    # 在控制台以表格形式显示商品信息
    display_table(goods_data)

    # 显示统计信息
    print(f"\n统计信息:")
    print(f" 商品总数: {len(goods_data)}")
    print(f" 总价格: ¥{total_price}")
    print(f" 总库存: {total_stock}")
    print(f" 总销量: {total_sales}")
    print(f"\n完整数据已保存到: {output_csv_path}")

    else:
    logger.error("商品数据转CSV失败,流程终止")
    print("\n错误:CSV转换失败")

    logger.info("=" * 50 + "商品数据提取结束" + "=" * 50)


    # -------------------------- 6. 直接运行 --------------------------
    if __name__ == "__main__":
    main()
  • 终端执行:python xml_to_json.py,生成goods_data.csv(含提取的商品数据)。

    验证:打开goods_data.csv,能看到 id、name、price、stock 等字段,包含测试网站的所有商品数据(含异常值)同时还有生成转换日志。

    转换日志

MySQL 数据存储(原始 + 清洗表)

  1. 启动 MySQL 服务:

    • 右键 “此电脑”→管理→服务,找到MySQL,确保状态为 “正在运行”。
  2. Navicat 创建数据库 / 表:

    • 打开 Navicat,连接 MySQL(主机 127.0.0.1,端口 3306,用户名 root,密码自己设置的)。

    • 新建数据库:名称burp_good,字符集utf8mb4,排序规则utf8mb4_general_ci

    • 新建原始数据表goods_data:

      执行 SQL(Navicat→查询→新建查询):

      1
      2
      3
      4
      5
      6
      7
      8
      9
      USE burp_good;
      CREATE TABLE goods_data (
      id INT NOT NULL PRIMARY KEY,
      name VARCHAR(100),
      price INT,
      stock INT,
      category VARCHAR(50),
      sales INT
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
      • 导入 CSV 数据:右键goods_data→导入向导→选goods_data.csv→字段一一匹配→完成导入。
      • 新建清洗后数据表cleaned_goods_data:结构和goods_data完全一致(复制表结构即可)。

验证:打开goods_data表,能看到从 CSV 导入的所有商品数据(含异常值),无中文乱码。

Kettle 数据清洗(过滤无效数据)

  1. Kettle 驱动适配(关键!避免编码报错):

  2. 配置 Kettle 清洗转换:

  • 启动 Kettle,点击“文件→新建→转换”,在画布中添加以下组件:
  • 表输入组件从“输入”分类中拖拽“表输入”到画布,双击配置:
    • 选择MySQL连接(已配置的burp_good连接);
    • 输入 SQL 语句:SELECT * FROM goods_data;
    • 点击“确定”保存。
  • 过滤记录组件从“转换”分类中拖拽“过滤记录”到画布,按住 Shift 从“表输入”拖拽到“过滤记录”,建立连线。
  • 表输出组件从“输出”分类中拖拽“表输出”到画布,按住 Shift 从“过滤记录”的“真”出口拖拽到“表输出”,建立连线,双击配置:
    • 选择MySQL连接;
    • 选择目标表cleaned_goods_data;
    • 勾选“Truncate table before loading”(导入前清空表);
    • 点击“确定”保存。
  1. 清洗条件配置

    双击“过滤记录”组件,点击“+”按钮逐个添加以下条件(逻辑关系均为“AND”):

    name IS NOT NULL;

    name ≠ “”;

    category IS NOT NULL;

    category ≠ “”;

    price IS NOT NULL;

    stock IS NOT NULL;

    sales IS NOT NULL;

    name ≠ “未知”;

    category ≠ “未分类”;

    stock > 0。添加完成后,设置“发送 true 数据的步骤”为“表输出”,点击“确定”保存

表输入:读取原始数据表goods_data的所有记录;

过滤记录:配置多条件过滤规则,仅保留符合要求的记录;

表输出:将符合条件的记录写入清洗后数据表cleaned_goods_data.

注意输出的时候会有肯报错就是输出要设置文字编码,表输出的“数据库连接”的“编辑”,然后选择“选项”,在右侧的命名参数添加。

清洗结果验证:打开 Navicat 查看cleaned_goods_data表,可看到仅保留了2条有效记录:id=1:华为Mate70(stock=100>0,category = 手机≠未分类);id=4:小米 Pad6(stock=200>0,category = 平板≠未分类)。验证清洗规则生效,无效数据已被过滤。

数据可视化(生成图表)

  1. 准备可视化脚本:

    • visualize.py复制到burp_test_site文件夹。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      import pandas as pd
      import matplotlib.pyplot as plt
      import pymysql
      from matplotlib import rcParams

      # 配置中文显示
      rcParams['font.sans-serif'] = ['SimHei'] # Windows
      # rcParams['font.sans-serif'] = ['PingFang SC'] # macOS
      rcParams['axes.unicode_minus'] = False

      # 连接MySQL读取清洗后的数据
      def get_clean_data():
      conn = pymysql.connect(
      host="127.0.0.1",
      port=3306,
      user="root",
      password="123456",
      database="burp_good",
      charset="utf8mb4", # 匹配数据库的字符集
      use_unicode=True # 强制使用Unicode编码处理字符串
      )
      df = pd.read_sql("SELECT * FROM cleaned_goods_data", conn)
      conn.close()
      return df

      # 可视化示例:商品价格分布
      def plot_goods_price(df):
      # 筛选商品数据
      goods_df = df[df["id"].notna()]
      # 柱状图
      plt.figure(figsize=(10, 6))
      plt.bar(goods_df["name"], goods_df["price"], color="#007bff")
      plt.title("商品价格分布", fontsize=16)
      plt.xlabel("商品名称", fontsize=12)
      plt.ylabel("价格(元)", fontsize=12)
      plt.grid(axis="y", linestyle="--", alpha=0.7)
      plt.savefig("goods_price.png", dpi=300, bbox_inches="tight")
      plt.show()

      if __name__ == "__main__":
      df = get_clean_data()
      plot_goods_price(df)
    • 修改脚本中的 MySQL 连接参数:password改为自己的 MySQL 密码,其他(host/port/user/database)默认即可。

  2. 运行脚本:

    • burp_data虚拟环境下,终端执行:python visualize.py

验证:

  • 自动弹出 “商品价格分布” 柱状图,中文标签正常显示,数据为清洗后的有效商品;

  • 文件夹中生成goods_price.png高清图表文件。

收尾与验证(全流程确认)

文档:整理课题报告(含引言、需求分析、方案设计、实施、评估、总结、参考文献、附录)为 PDF;

代码:app.py/visualize.py/xml_to_json.py/index.html

数据:burp_requests.xml(抓包)、goods_data.csv(解析)、MySQL 两张表的备份(Navicat→右键表→转储 SQL 文件);

成果:goods_price.png(可视化图表)、各环节关键截图(网站页面、Burp 抓包、Kettle 清洗、可视化图表)。

打包:按 “文档 / 代码 / 环境配置 / 测试数据 / 成果展示” 分类整理文件夹,压缩为课题名称-姓名-学号.zip

核心注意事项

  1. 编码问题:MySQL 字符集必须设为utf8mb4,Kettle 驱动升级到 8.0.x,可视化脚本配置中文字体;
  2. 字段匹配:可视化脚本的字段名(id/name/price)必须和 MySQL 表字段一致;
  3. 环境激活:所有脚本运行前,确保激活burp_data虚拟环境,避免依赖找不到;
  4. 代理配置:Burp 仅勾选 “Loopback only”,避免抓取非本地请求。
  5. 清洗的表输出要设置文字编码。
  6. 保证kettle全流程的数据库连接完成。

流程总结

本流程核心是 “搭建数据源→采集数据→存储数据→清洗数据→可视化展示” 的闭环,关键在于:

  1. 环境隔离(虚拟环境)避免依赖冲突;

  2. 驱动 / 编码适配解决工具兼容问题;

  3. 规则化清洗确保数据有效性;

  4. 字段 / 表名统一避免可视化报错。

    按步骤执行可完整复现从 “本地网站→数据→图表” 的全流程

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2025 唐小唐
  • 访问人数: | 浏览次数: