告别手动复制粘贴:用TagUI实现美食数据自动化采集与营养分析全流程

告别手动复制粘贴:用TagUI实现美食数据自动化采集与营养分析全流程

【免费下载链接】TagUI aisingapore/TagUI: 是一个用于自动化测试的 RPA(Robotic Process Automation)工具,支持多种浏览器和操作系统,可以用于自动化测试,数据抓取和网页操作等任务。 【免费下载链接】TagUI 项目地址: https://gitcode.com/gh_mirrors/ta/TagUI

你是否还在为整理菜谱数据而重复复制粘贴?是否因手工录入营养成分表格而焦头烂额?本文将带你用RPA(Robotic Process Automation,机器人流程自动化)工具TagUI,构建一个从美食网站自动采集菜谱信息、提取营养数据并生成分析报告的完整解决方案。读完本文你将掌握

  • 使用TagUI实现网页元素精确定位与数据抓取
  • 批量处理多页菜谱的自动化流程设计
  • 数据清洗与营养成分提取的实用技巧
  • 生成可视化分析报告的完整代码实现

为什么选择TagUI做美食数据自动化?

TagUI作为一款开源RPA工具,特别适合处理菜谱数据采集这类规则性强但重复度高的任务。其核心优势在于:

mermaid

相比Python爬虫需要处理复杂的反爬机制,TagUI通过模拟真实用户操作(如点击、输入、滚动)来获取数据,大幅降低被网站屏蔽的风险。同时支持Chrome/Edge浏览器的无头模式运行,可在后台静默完成整个采集过程,不影响正常电脑使用。

环境准备与基础配置

快速安装TagUI

在Linux系统中,通过以下命令即可完成安装:

# 克隆官方仓库
git clone https://gitcode.com/gh_mirrors/ta/TagUI /data/web/disk1/git_repo/gh_mirrors/ta/TagUI

# 进入目录并赋予执行权限
cd /data/web/disk1/git_repo/gh_mirrors/ta/TagUI/src
chmod +x tagui

# 验证安装成功
./tagui --version

Windows用户可直接下载安装包,Mac用户则可通过Homebrew安装。安装完成后,建议启动一次tagui live进入实时模式,熟悉基础操作语法。

项目结构设计

为美食数据采集项目创建以下目录结构,保持代码组织清晰:

food_analysis/
├── flows/                # 主流程文件
│   ├── recipe_crawler.tag  # 菜谱采集主程序
│   └── nutrient_analyzer.tag # 营养分析模块
├── data/                 # 数据存储
│   ├── raw_recipes.csv    # 原始采集数据
│   └── cleaned_data.csv   # 清洗后数据
├── images/               # 定位用图片资源
│   ├── recipe_card.png    # 菜谱卡片识别图
│   └── nutrient_table.png # 营养表格识别图
└── reports/              # 生成的报告
    └── analysis_report.html # 营养分析报告

核心技术:TagUI选择器与数据抓取技巧

精确定位网页元素

TagUI提供多种元素定位方式,针对美食网站常见的菜谱卡片,推荐使用XPath定位:

mermaid

以某美食网站为例,要提取菜谱名称和制作时间,可使用如下代码:

// 访问目标页面
https://www.example-food-site.com/recipes/chinese

// 等待页面加载完成
wait 3 seconds

// 读取菜谱标题(XPath定位)
read //div[@class="recipe-card"]/h2 to recipe_title

// 读取烹饪时间(CSS选择器)
read .recipe-meta time to cook_time

// 输出获取结果
echo 菜谱名称: `recipe_title`
echo 烹饪时间: `cook_time`

处理分页与动态加载内容

许多美食网站采用瀑布流或分页加载方式展示菜谱列表,可通过循环结合滚动操作实现全量采集:

// 初始化页码计数器
page = 1

// 定义最大页数
max_pages = 5

// 循环采集多页数据
for page from 1 to max_pages
    echo 正在采集第`page`页数据...
    
    // 抓取当前页所有菜谱链接
    read //div[@class="recipe-list"]//a@href to recipe_links
    
    // 处理当前页每个菜谱
    for link in recipe_links
        // 在新标签页打开菜谱
        popup `link`
            // 采集菜谱详情...
            read //h1[@itemprop="name"] to dish_name
            read //span[@itemprop="totalTime"] to total_time
            // 其他数据采集步骤...
            
            // 保存到CSV文件
            write `csv_row([dish_name, total_time, ingredients])` to data/raw_recipes.csv
        
        // 关闭当前标签页
        close popup
    end
    
    // 点击下一页
    click //a[contains(text(),"下一页")]
    wait 2 seconds
end

实战案例:构建完整的菜谱数据采集流程

设计采集流程

我们以"下厨房"网站为例,构建一个包含以下步骤的自动化流程:

mermaid

完整代码实现

创建flows/recipe_crawler.tag文件,实现上述完整流程:

// 菜谱数据采集主流程
// 作者:美食自动化爱好者
// 版本:1.0
// 日期:2025-09-20

// 配置参数
base_url = "https://www.xiachufang.com/category/40076/"
output_file = "data/raw_recipes.csv"
max_pages = 3

// 初始化CSV文件(写入表头)
dump 菜名,烹饪时间,难度,食材,热量(千卡),蛋白质(克),脂肪(克),碳水化合物(克) to `output_file`

// 主循环 - 多页采集
for page from 1 to max_pages
    echo === 开始采集第`page`页 ===
    
    // 访问目标页面
    `base_url`?page=`page`
    
    // 等待页面加载
    wait 3 seconds
    
    // 获取当前页所有菜谱卡片
    recipe_count = count('//div[@class="recipe"]')
    echo 发现`recipe_count`个菜谱
    
    // 循环处理每个菜谱
    for i from 1 to recipe_count
        echo 正在处理第`i`个菜谱...
        
        // 点击菜谱卡片(XPath索引从1开始)
        click (//div[@class="recipe"])[`i`]
        
        // 等待详情页加载
        wait 2 seconds
        
        // 提取基本信息
        read //h1[@class="page-title"] to dish_name
        read //div[@class="info"]/span[1] to cook_time
        read //div[@class="info"]/span[2] to difficulty
        
        // 提取食材列表
        ingredients = ""
        ingredient_count = count('//div[@class="ings"]//li')
        for j from 1 to ingredient_count
            read (//div[@class="ings"]//li)[`j`] to ingredient
            ingredients = ingredients + "|" + ingredient
        end
        
        // 提取营养成分(处理可能不存在的情况)
        if exist('//table[@class="nutritions"]')
            read (//table[@class="nutritions"]//td)[2] to calories
            read (//table[@class="nutritions"]//td)[4] to protein
            read (//table[@class="nutritions"]//td)[6] to fat
            read (//table[@class="nutritions"]//td)[8] to carbs
        else
            calories = "N/A"
            protein = "N/A"
            fat = "N/A"
            carbs = "N/A"
        end
        
        // 保存数据到CSV
        write `csv_row([dish_name, cook_time, difficulty, ingredients, calories, protein, fat, carbs])` to `output_file`
        
        // 返回列表页
        click //a[@class="back"]
        wait 2 seconds
    end
end

echo 数据采集完成!共采集`page*recipe_count`条菜谱数据
echo 数据已保存至:`output_file`

数据清洗与营养分析

数据预处理

原始采集的数据往往包含多余空格、特殊字符等噪音,需要进行清洗。创建flows/data_cleaner.tag

// 数据清洗流程
// 输入:raw_recipes.csv
// 输出:cleaned_data.csv

// 加载原始数据
load data/raw_recipes.csv to raw_data

// 初始化清洗后的数据文件
dump 菜名,烹饪时间(分钟),难度,主要食材,热量(千卡),蛋白质(克),脂肪(克),碳水化合物(克) to data/cleaned_data.csv

// 跳过表头行,从第二行开始处理
for row from 1 to raw_data.length-1
    // 解析CSV行数据(split函数将字符串转为数组)
    js data_row = raw_data[`row`].split(',')
    
    // 提取字段(处理CSV中的逗号问题)
    dish_name = data_row[0]
    cook_time = data_row[1]
    difficulty = data_row[2]
    ingredients = data_row[3]
    calories = data_row[4]
    protein = data_row[5]
    fat = data_row[6]
    carbs = data_row[7]
    
    // 清洗烹饪时间(提取数字部分)
    js cook_time_minutes = cook_time.replace(/[^0-9]/g, '')
    
    // 提取主要食材(取前三个)
    js main_ingredients = ingredients.split('|').slice(1,4).join(';')
    
    // 清洗营养数据(去除非数字字符)
    js calories_clean = calories.replace(/[^0-9.]/g, '')
    js protein_clean = protein.replace(/[^0-9.]/g, '')
    js fat_clean = fat.replace(/[^0-9.]/g, '')
    js carbs_clean = carbs.replace(/[^0-9.]/g, '')
    
    // 写入清洗后的数据
    write `csv_row([dish_name, cook_time_minutes, difficulty, main_ingredients, calories_clean, protein_clean, fat_clean, carbs_clean])` to data/cleaned_data.csv
end

echo 数据清洗完成!共处理`row`条记录

生成营养分析报告

使用TagUI的模板功能结合HTML/CSS,生成可视化的营养分析报告:

// 生成营养分析报告
// 读取清洗后的数据
load data/cleaned_data.csv to nutrition_data

// 创建HTML报告文件
dump <!DOCTYPE html>
<html>
<head>
    <title>美食营养分析报告</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        h1 { color: #d35400; border-bottom: 2px solid #d35400; }
        .summary { background-color: #f8f9fa; padding: 15px; border-radius: 5px; }
        .table-container { overflow-x: auto; margin-top: 20px; }
        table { width: 100%; border-collapse: collapse; }
        th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
        th { background-color: #f1c40f; color: #333; }
        tr:hover { background-color: #f5f5f5; }
        .high-protein { background-color: #d5f5e3; }
        .low-calorie { background-color: #eaf2f8; }
    </style>
</head>
<body>
    <h1>美食营养分析报告</h1>
    <p>生成日期: `date()`</p>
    <p>分析样本: `nutrition_data.length-1`道菜谱</p>
    
    <div class="summary">
        <h2>营养概览</h2>
        <p>平均热量: `avg_calories` 千卡</p>
        <p>平均蛋白质: `avg_protein` 克</p>
        <p>最高蛋白质菜谱: `high_protein_dish`</p>
        <p>低卡健康选择: `low_calorie_dish`</p>
    </div>
    
    <div class="table-container">
        <h2>详细营养数据</h2>
        <table>
            <tr>
                <th>菜名</th>
                <th>烹饪时间(分钟)</th>
                <th>难度</th>
                <th>主要食材</th>
                <th>热量(千卡)</th>
                <th>蛋白质(克)</th>
                <th>脂肪(克)</th>
                <th>碳水化合物(克)</th>
            </tr>
    to reports/analysis_report.html

// 计算统计数据
total_calories = 0
total_protein = 0
high_protein = 0
high_protein_dish = ""
low_calorie = 9999
low_calorie_dish = ""
valid_count = 0

// 遍历数据计算统计值
for row from 1 to nutrition_data.length-1
    js data_row = nutrition_data[`row`].split(',')
    calories = data_row[4]
    protein = data_row[5]
    
    // 累加有效数据
    if calories != "N/A" and protein != "N/A"
        total_calories = total_calories + parseFloat(calories)
        total_protein = total_protein + parseFloat(protein)
        valid_count = valid_count + 1
        
        // 跟踪高蛋白菜谱
        if parseFloat(protein) > high_protein
            high_protein = parseFloat(protein)
            high_protein_dish = data_row[0]
        end
        
        // 跟踪低卡菜谱
        if parseFloat(calories) < low_calorie
            low_calorie = parseFloat(calories)
            low_calorie_dish = data_row[0]
        end
    end
    
    // 添加表格行数据
    // 判断是否为高蛋白或低卡菜品,添加样式标记
    if data_row[5] == high_protein
        write <tr class="high-protein"> to reports/analysis_report.html
    else if data_row[4] == low_calorie
        write <tr class="low-calorie"> to reports/analysis_report.html
    else
        write <tr> to reports/analysis_report.html
    end
    
    // 写入表格内容
    for col from 0 to data_row.length-1
        write <td>`data_row[col]`</td> to reports/analysis_report.html
    end
    write </tr> to reports/analysis_report.html
end

// 计算平均值
avg_calories = total_calories / valid_count
avg_protein = total_protein / valid_count

// 更新报告中的统计数据
// 使用JavaScript替换占位符
js const fs = require('fs');
js let report = fs.readFileSync('reports/analysis_report.html', 'utf8');
js report = report.replace('`avg_calories`', `avg_calories`.toFixed(1));
js report = report.replace('`avg_protein`', `avg_protein`.toFixed(1));
js report = report.replace('`high_protein_dish`', '`high_protein_dish` ('`high_protein`'克)');
js report = report.replace('`low_calorie_dish`', '`low_calorie_dish` ('`low_calorie`'千卡)');
js fs.writeFileSync('reports/analysis_report.html', report);

// 完成报告HTML
write        </table>
    </div>
</body>
</html> to reports/analysis_report.html

echo 营养分析报告生成完成!
echo 报告路径:reports/analysis_report.html

自动化任务调度与扩展

设置定时运行

在Linux系统中,可通过crontab设置每周自动更新菜谱数据:

# 编辑crontab配置
crontab -e

# 添加以下行(每周日凌晨2点运行)
0 2 * * 0 /data/web/disk1/git_repo/gh_mirrors/ta/TagUI/src/tagui /data/web/disk1/git_repo/gh_mirrors/ta/TagUI/flows/recipe_crawler.tag -headless

功能扩展建议

  1. 多网站支持:通过参数化URL和选择器,扩展支持多个美食网站
  2. 图片采集:添加snap命令保存菜谱图片,丰富数据集
  3. AI分类:集成营养分析API,自动识别食材类别和烹饪方式
  4. 异常处理:增加try-catch机制和错误日志,提高稳定性

常见问题与解决方案

页面加载缓慢导致数据抓取失败

解决方案:使用动态等待代替固定等待时间

// 不推荐:固定等待
wait 3 seconds

// 推荐:等待元素出现后再操作
timeout 10  // 设置最长等待10秒
wait for exist('//h1[@class="page-title"]')

网站结构变化导致选择器失效

解决方案:采用多属性组合定位,提高鲁棒性

// 脆弱的定位方式(容易因样式变化失效)
click //div[@class="recipe-card-2023"]

// 更健壮的定位方式(组合文本和属性)
click //div[contains(@class,"recipe-card") and contains(text(),"家常菜")]

反爬机制限制采集速度

解决方案:模拟人类操作节奏,添加随机等待

// 引入随机等待时间
js random_wait = Math.floor(Math.random() * 3) + 1;  // 1-3秒随机等待
wait `random_wait` seconds

总结与下一步

通过本文介绍的方法,我们构建了一个完整的美食数据自动化采集与分析系统。这个方案不仅适用于菜谱数据,还可推广到其他需要重复操作的场景,如电商产品信息采集、新闻文章汇总、金融数据整理等。

下一步建议:

  1. 尝试使用TagUI的live模式进行交互式开发,实时调试选择器
  2. 探索Excel集成功能,直接将数据导入电子表格进行分析
  3. 研究TagUI的OCR功能,处理图片中的菜谱信息

最后,分享一个完整的运行命令,一键启动从采集到报告的全流程:

# 全流程运行命令
tagui flows/recipe_crawler.tag && tagui flows/data_cleaner.tag && tagui flows/report_generator.tag -h

【免费下载链接】TagUI aisingapore/TagUI: 是一个用于自动化测试的 RPA(Robotic Process Automation)工具,支持多种浏览器和操作系统,可以用于自动化测试,数据抓取和网页操作等任务。 【免费下载链接】TagUI 项目地址: https://gitcode.com/gh_mirrors/ta/TagUI

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值