需求背景

近期从来账中发现 订单来账分区(Zone)与系统分区不一致,追溯后判断为承运商官网的邮编分区/ZIP 列表或相关文件发生更新,但内部未能及时同步,导致对账与计费风险。

目前主要靠人工不定期查看官网,存在遗漏与滞后。

需要建立自动化“官网更新雷达”:每天巡检官网公告/文件,发现变更自动提醒,留存证据,触发内部评估与系统分区更新流程。

需求描述

目标
及时性:官网内容/附件文件发生更新后,系统在下一次巡检周期内发现并通知(默认每日巡检)。
可追溯:保存变更前后快照、变更摘要。
可执行:邮件提醒中包含“变更点 + 影响范围提示”,便于渠道同事快速评估并推进系统邮编分区配置更新。

业务流程
定时巡检:每天定时访问配置的官网页面
变更识别:
页面:对“正文内容 + 关键字段+ 附件链接集合”做标准化后计算
生成变更事件:记录变更类型(文案变更/链接变更/文件内容变更)、变更摘要、影响提示
邮件通知:发送到配置的收件人组(渠道邮箱:channelsupprt@wpglb.com
人工评估与落地:渠道同事确认影响范围 → 在系统更新邮编分区/计费配置 → 关闭变更事件

FedEx官网公告更新地址:https://www.fedex.com/en-us/shipping/rate-changes.html
FedEx服务预警更新地址:https://www.fedex.com/en-us/service-alerts.html

UPS官网公告更新地址:https://www.fedex.com/en-us/shipping/rate-changes.html
UPS官网公告更新地址:https://www.ups.com/us/en/service-alerts

开发预研

当前系统已有单独轨迹抓取项目:
wpglb-crawler-task,开源项目:https://www.xuxueli.com/xxl-crawler/
但是数据库连接不可控,新库+新表。
抓取网页数据一行代码:

    private void startCrawlTask(RadarConfig config) {
        new XxlCrawler.Builder()
                .setUrls(config.getTargetUrl())
                .setThreadCount(1)
                .setAllowSpread(false) // 不允许扩散抓取
                .setHeaderMap(config.getCustomHeaders())
                .setUserAgent(config.getUserAgent())
                .setPageLoader(new JsoupPageLoader())
                .setPageParser(new RadarPageParser(config, radarService))
                .build()
                .start(true); // 同步执行以便于管控
    }

经验证,使用框架抓取网页数据,容易触发防爬。而且需求抓取到数据量不多。没必要是用框架抓取,直接采用http请求获取html数据更简单。

public static String doHtmlJsoup(String url) {
        int retry = 0;
        int maxRetry = 3;
        while (retry < maxRetry) {
            try {
                Connection connection = Jsoup.connect(url)
                        .timeout(5000)
                        .ignoreContentType(true)
                        .followRedirects(true)
                        .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36");

                // 设置默认Header(防止被拦)
                connection.header("Accept", "text/html,application/xhtml+xml");
                connection.header("Accept-Language", "en-US,en;q=0.9");
                connection.header("Connection", "keep-alive");
                return connection.get().outerHtml();
            } catch (IOException e) {
                retry++;
                try {
                    Thread.sleep(1500L * retry); // 递增退避
                } catch (InterruptedException ignored) {
                }
            }
        }
        return null;
    }

开发设计

1.1 官网公告自动抓取

每日定时抓取以下官网内容:

FedEx

  • 燃油费率公告
  • 服务预警公告

UPS

  • 燃油费率公告
  • 服务预警公告

1.2 内容变化感知

基于“标题 + 正文标准化 hash”识别公告内容变化。

1.3 防重复通知

相同内容历史已通知业务后,不重复邮件通知。

1.4 历史快照留存

每日抓取结果全部落库,用于:

  • 历史回溯
  • 审计追踪
  • 数据分析
  • 趋势报表

2. 技术方案总览

XXL-Job定时任务
    ↓
官网HTML抓取(Jsoup)
    ↓
按承运商DOM解析
    ↓
生成 WebsiteMonitorDTO
    ↓
标准化Hash
    ↓
查询历史是否已通知
    ↓
首次变化 → 邮件通知
    ↓
抓取快照落库

3. 核心流程设计

3.1 定时任务

当前采用 XXL-JOB 实现定时调度:

@XxlJob("WebsiteMonitorTask")

推荐执行频率:每天 08:00 / 14:00 / 20:00。

3.2 抓取层设计

当前方案采用:

Jsoup.connect(url)

核心能力:

  • User-Agent 伪装
  • Header 模拟
  • 自动重试
  • 指数退避
  • Redirect 跟随

3.3 解析层设计

采用按承运商类型策略化解析,通过:

Map<WebsiteMonitorCodeEnum, Function<String, WebsiteMonitorDTO>>

路由解析器。
当前已支持:FedEx、UPS。
后续可扩展:DHL、USPS、DPD、Royal Mail。


4. 内容变更识别方案

核心算法:

md5(normalize(title) + "\n" + normalize(content))

标准化规则:

  • 去除 ®
  • 去除 &nbsp;
  • 去除 Unicode 空格
  • 合并连续空格
  • trim

5. 历史去重通知设计

判重维度:

monitor_type + website_hash + is_email_notice = 1

判重逻辑:

  • 已存在:仅保存快照,不重复发邮件
  • 不存在:首次变化,发送邮件并标记 is_email_notice = 1

6. 数据库设计

核心表:carrier_website_monitor

CREATE TABLE `carrier_website_monitor` (
  `monitor_id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `carrier_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '承运商代码:FEDEX / UPS',
  `monitor_type` int NOT NULL COMMENT '监控类型:1.FEDEX燃油费率 2.FEDEX服务预警 3.UPS燃油费率  4.UPS服务预警',
  `website_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '网站-地址',
  `website_title` varchar(500) NOT NULL DEFAULT '' COMMENT '网站-标题',
  `website_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '网站-内容',
  `website_hash` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'hash唯一值',
  `is_email_notice` int NOT NULL DEFAULT '0' COMMENT '是否邮件通知',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`monitor_id`) USING BTREE,
  KEY `idx_monitor_type_website_hash` (`monitor_type`,`website_hash`),
  KEY `idx_carrier_code` (`carrier_code`) USING BTREE,
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='承运商网站监控';

7. 邮件通知设计

通过 EmailQueueService 异步发送,邮件内容包括:

  • 监控类型
  • 公告标题
  • 公告正文
  • 官网跳转链接

优势:

  • 不阻塞抓取任务
  • 支持失败重试
  • 支持优先级
  • 支持统一邮件网关

8. 风险点分析

8.1 动态渲染页面

部分官网存在“浏览器DOM ≠ 实际抓取HTML”。
当前策略:以程序实际抓取 HTML 作为唯一解析依据。
后续增强:可引入 Selenium / Playwright。

8.2 DOM结构变更风险

解决方案:

  • selector 多级兜底
  • 异常日志告警
  • parser 周期巡检
  • DOM调试样本留存

8.3 反爬风险

当前已实现:

  • User-Agent
  • Accept-Language
  • Retry
  • Backoff

后续可增强:Referer、Proxy、Cookie、IP池。


9. 预研结论

当前技术方案已验证可行,已具备以下能力:

  • 静态 HTML 抓取
  • 多承运商 DOM 解析
  • 标题正文标准化 Hash
  • 历史去重通知
  • 每日快照落库
  • 邮件异步通知
作者:黄天文  创建时间:2026-04-02 15:35
最后编辑:黄天文  更新时间:2026-04-17 09:34