WebArena 部署踩坑
Map 网站
后端服务部署 (Tile, Nominatim, OSRM)
在 WebArena 中,地图功能并不依赖外部公网 API(如 Google Maps),而是完全本地化部署。这涉及三个核心服务:
- Tile Server: 提供地图瓦片图片渲染(视觉层)。
- Nominatim: 提供地理编码服务(搜索地址转坐标,或坐标转地址)。
- OSRM: 提供路径规划服务(驾车、骑行、步行导航)。
直接下载 AWS S3 上预构建好的数据卷的方式进行部署。
前置要求:
- 确保服务器有足够的磁盘空间(建议预留 200GB+)。
- 确保已安装 Docker。
- 设置环境变量 DATA_ROOT 指向你的数据存储目录,例如:export DATA_ROOT=/data/map_backend。
为了应对 S3 下载可能出现的网络波动和 SSL 问题,我们定义了一个健壮的下载函数,支持断点续传和自动重试。(文件链接来自于 WbArena 官方的部署文件)
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
#!/bin/bash
# 确保 DATA_ROOT 已定义
if [ -z "$DATA_ROOT" ]; then
echo "Error: DATA_ROOT environment variable is not set."
exit 1
fi
mkdir -p "$DATA_ROOT/docker_volumes"
mkdir -p "$DATA_ROOT/opt/osm_dump"
mkdir -p "$DATA_ROOT/opt/osrm"
# 定义下载函数:自动把 https 换成 http 绕过 SSL 报错,且支持断点续传
download_safe() {
local url=$1
local dest=$2
local name=$3
# 强制 http,避免 wget 的 SSL 握手问题
local http_url="${url/https:/http:}"
echo ">>> 正在下载: $name"
while true; do
wget -c -t 50 -T 60 --no-check-certificate "$http_url" -O "$dest"
if [ $? -eq 0 ]; then
echo ">>> $name 下载完成"
break
else
echo ">>> 下载中断,3秒后重试..."
sleep 3
fi
done
}
# --- 1. 下载 Tile Server 数据 (地图瓦片数据库) ---
if [ ! -d "$DATA_ROOT/docker_volumes/osm-data" ]; then
download_safe \
"http://s3.amazonaws.com/webarena-map-server-data/osm_tile_server.tar" \
"$DATA_ROOT/osm_tile_server.tar" \
"Tile Server Data"
echo ">>> 解压 Tile Server 数据..."
# 注意:这里剥离了 5 层目录,适配原压缩包结构
tar -C "$DATA_ROOT/docker_volumes" --strip-components=5 -xf "$DATA_ROOT/osm_tile_server.tar"
# 可选:解压后删除压缩包释放空间
# rm -f "$DATA_ROOT/osm_tile_server.tar"
fi
# --- 2. 下载 Nominatim 数据 (地理编码数据库) ---
if [ ! -d "$DATA_ROOT/docker_volumes/nominatim-data" ]; then
download_safe \
"http://s3.amazonaws.com/webarena-map-server-data/nominatim_volumes.tar" \
"$DATA_ROOT/nominatim_volumes.tar" \
"Nominatim Data"
echo ">>> 解压 Nominatim 数据..."
tar -C "$DATA_ROOT/docker_volumes" --strip-components=5 -xf "$DATA_ROOT/nominatim_volumes.tar"
fi
# --- 3. 下载 OSM Dump (原始 PBF 数据,用于辅助) ---
if [ -z "$(ls -A "$DATA_ROOT/opt/osm_dump")" ]; then
download_safe \
"http://s3.amazonaws.com/webarena-map-server-data/osm_dump.tar" \
"$DATA_ROOT/osm_dump.tar" \
"OSM Dump"
echo ">>> 解压 OSM Dump..."
tar -C "$DATA_ROOT/opt/osm_dump" -xf "$DATA_ROOT/osm_dump.tar"
fi
# --- 4. 下载 OSRM Routing 数据 (预处理好的路由图) ---
if [ -z "$(ls -A "$DATA_ROOT/opt/osrm")" ]; then
download_safe \
"http://s3.amazonaws.com/webarena-map-server-data/osrm_routing.tar" \
"$DATA_ROOT/osrm_routing.tar" \
"OSRM Data"
echo ">>> 解压 OSRM 数据..."
tar -C "$DATA_ROOT/opt/osrm" -xf "$DATA_ROOT/osrm_routing.tar"
fi
数据准备好后,我们需要启动对应的容器。为了保证服务稳定性,我们在启动脚本中加入了镜像拉取重试机制和内存限制。
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
# 定义镜像拉取函数,失败自动重试
pull_retry() {
for i in {1..5}; do
docker pull "$1" && return 0
echo "镜像拉取失败,2秒后重试..."
sleep 2
done
return 1
}
echo ">>> 拉取 Docker 镜像..."
pull_retry "overv/openstreetmap-tile-server" || true
pull_retry "mediagis/nominatim:4.2" || true
pull_retry "ghcr.io/project-osrm/osrm-backend:v5.27.1" || true
# --- 1. 启动 Tile Server (端口 8080) ---
# 挂载说明:
# /data/database/: 存放 PostgreSQL 数据
# /data/tiles/: 存放渲染好的瓦片缓存
echo ">>> 启动 Tile Server..."
docker rm -f tile 2>/dev/null || true
docker run --name tile --restart unless-stopped \
--memory=4g --memory-swap=8g \
-v "$DATA_ROOT/docker_volumes/osm-data":/data/database/ \
-v "$DATA_ROOT/docker_volumes/osm-tiles":/data/tiles/ \
-p 8080:80 -d overv/openstreetmap-tile-server run
# --- 2. 启动 Nominatim (端口 8085) ---
# 这是一个 PostgreSQL 数据库容器,用于地址解析。
# IMPORT_STYLE=extratags: 导入额外的标签数据,提高搜索准确度
echo ">>> 启动 Nominatim..."
docker rm -f nominatim 2>/dev/null || true
docker run --name nominatim --restart unless-stopped \
--memory=8g --memory-swap=16g \
--env=IMPORT_STYLE=extratags \
--env=PBF_PATH=/nominatim/data/us-northeast-latest.osm.pbf \
--env=IMPORT_WIKIPEDIA=/nominatim/data/wikimedia-importance.sql.gz \
-v "$DATA_ROOT/opt/osm_dump":/nominatim/data \
-v "$DATA_ROOT/docker_volumes/nominatim-data/_data":/var/lib/postgresql/14/main \
-v "$DATA_ROOT/docker_volumes/nominatim-flatnode/_data":/nominatim/flatnode \
-p 8085:8080 -d mediagis/nominatim:4.2 /app/start.sh
# --- 3. 启动 OSRM Routing (端口 5001-5003) ---
# 我们需要启动三个实例,分别对应三种出行方式:
# osrm-car (5003): 驾车
# osrm-bike (5001): 骑行
# osrm-foot (5002): 步行
# 它们共享同一个 osm.pbf,但使用预处理好的不同 profile 数据。
echo ">>> 启动 OSRM 后端..."
docker rm -f osrm-car osrm-bike osrm-foot 2>/dev/null || true
# 驾车服务
docker run --name osrm-car --restart unless-stopped \
--memory=8g --memory-swap=8g \
-v "$DATA_ROOT/opt/osrm/car":/data -p 5003:5000 -d \
ghcr.io/project-osrm/osrm-backend:v5.27.1 osrm-routed --algorithm mld /data/us-northeast-latest.osrm
# 骑行服务
docker run --name osrm-bike --restart unless-stopped \
--memory=8g --memory-swap=8g \
-v "$DATA_ROOT/opt/osrm/bike":/data -p 5001:5000 -d \
ghcr.io/project-osrm/osrm-backend:v5.27.1 osrm-routed --algorithm mld /data/us-northeast-latest.osrm
# 步行服务
docker run --name osrm-foot --restart unless-stopped \
--memory=8g --memory-swap=8g \
-v "$DATA_ROOT/opt/osrm/foot":/data -p 5002:5000 -d \
ghcr.io/project-osrm/osrm-backend:v5.27.1 osrm-routed --algorithm mld /data/us-northeast-latest.osrm
等待几分钟(数据库初始化需要时间),可以通过以下方式验证服务是否正常:
- Tile Server: 访问
http://<服务器IP>:8080,应能看到地图瓦片服务页面。 - Nominatim: 测试 API,例如
http://<服务器IP>:8085/search?q=New+York&format=json。 - OSRM: 测试驾车路由,例如
http://<服务器IP>:5003/route/v1/driving/-74.006,40.7128;-73.935,40.7306?steps=true。
前端服务部署 (OpenStreetMap Website)
前端服务的部署主要包含三个步骤:获取镜像与源码、配置服务连接、初始化数据库结构。
注意:本章节部署的数据库容器 openstreetmap-website-db 初始状态下仅包含数据库软件本身(PostgreSQL)和表结构,不包含具体的地图节点数据。因此,部署完成后,虽然地图可见、搜索可用,但点击具体地点的详情页会显示 “Not Found”。数据的注入将在下一章节(数据恢复)中完成。
我们将使用 WebAgent-R1 归档的 Docker 镜像和源码包。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 定义归档文件存放路径,建议与之前保持一致
export ARCHIVES_LOCATION="$DATA_ROOT/archives"
mkdir -p $ARCHIVES_LOCATION
# 1. 下载 DB 镜像包 (仅包含环境,无数据)
wget -nc -P $ARCHIVES_LOCATION https://zenodo.org/records/12636845/files/openstreetmap-website-db.tar.gz
# 2. 下载 Web 镜像包 (Rails 应用)
wget -nc -P $ARCHIVES_LOCATION https://zenodo.org/records/12636845/files/openstreetmap-website-web.tar.gz
# 3. 下载网站源码包 (用于挂载配置)
wget -nc -P $ARCHIVES_LOCATION https://zenodo.org/records/12636845/files/openstreetmap-website.tar.gz
# 简单校验文件是否存在
if [ -f "${ARCHIVES_LOCATION}/openstreetmap-website-db.tar.gz" ] && \
[ -f "${ARCHIVES_LOCATION}/openstreetmap-website-web.tar.gz" ] && \
[ -f "${ARCHIVES_LOCATION}/openstreetmap-website.tar.gz" ]; then
echo ">>> 所有前端依赖包下载完成。"
else
echo ">>> 错误:下载失败,请检查网络。"
exit 1
fi
不同于后端服务直接 docker pull,为了保证版本严格锁定,我们通过 docker load 加载本地镜像。
1
2
3
4
5
6
7
8
9
10
11
# 加载数据库和Web服务镜像
docker load --input "${ARCHIVES_LOCATION}/openstreetmap-website-db.tar.gz"
docker load --input "${ARCHIVES_LOCATION}/openstreetmap-website-web.tar.gz"
# 解压网站源码到当前目录
if [ ! -d ./openstreetmap-website ]; then
echo ">>> 解压网站源码..."
tar -xzf ${ARCHIVES_LOCATION}/openstreetmap-website.tar.gz
else
echo ">>> 源码目录已存在,跳过解压。"
fi
随后,需要替换掉默认的配置文件,并修复 docker-compose.yml 中的构建逻辑。先下载并应用 WebAgent-R1 提供的配置模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
# 下载模板(这里假设你已经克隆了 WebAgent-R1 仓库,或者直接下载相关文件)
# 假设模板位于 ../openstreetmap-templates
cd openstreetmap-website/
echo ">>> 应用配置文件模板..."
# 1. 替换 docker-compose.yml: 定义了 web 和 db 服务的运行方式
cp ../openstreetmap-templates/docker-compose.yml ./docker-compose.yml
# 2. 替换 leaflet.osm.js: 用于前端加载瓦片地图的逻辑
cp ../openstreetmap-templates/leaflet.osm.js ./vendor/assets/leaflet/leaflet.osm.js
# 3. 替换 fossgis_osrm.js: 用于前端调用 OSRM 路由服务的逻辑
cp ../openstreetmap-templates/fossgis_osrm.js ./app/assets/javascripts/index/directions/fossgis_osrm.js
模板文件中的 docker-compose.yml 默认配置是尝试从当前目录构建镜像 (build: context: .)。但我们刚才已经通过 docker load 加载了预编译好的镜像 openstreetmap-website-db。为了避免构建失败并使用正确的镜像,我们需要修改它:
1
2
3
4
5
6
7
8
9
db:
build:
context: .
dockerfile: docker/postgres/Dockerfile
# 替换为
db:
image: openstreetmap-website-db
现在,我们需要告诉前端(Web)去哪里找后端(Tile/Nominatim/OSRM)。通过 sed 命令批量替换配置文件中的占位符。
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
# --- 配置区 ---
# 如果后端服务都在本机,使用本机公网 IP 或内网 IP
# 注意:不要使用 127.0.0.1,因为这是 Docker 容器内部的 loopback
OSM_SERVICES_IP="" # 请替换为你的实际服务器 IP
MAP_PORT="3000" # Web 服务对外端口
# 组装后端服务 URL
OSM_TILE_SERVER_URL="http://${OSM_SERVICES_IP}:8080/tile/{z}/{x}/{y}.png"
OSM_GEOCODING_SERVER_URL="http://${OSM_SERVICES_IP}:8085/"
OSM_ROUTING_SERVER_URL="http://${OSM_SERVICES_IP}"
# OSRM 不同模式的端口后缀
OSM_CAR_SUFFIX=":5003"
OSM_BIKE_SUFFIX=":5001"
OSM_FOOT_SUFFIX=":5002"
echo ">>> 正在配置服务地址,后端IP: $OSM_SERVICES_IP ..."
# 1. 设置 Web 服务对外端口
sed -i "s|MAP_PORT|${MAP_PORT}|g" docker-compose.yml
# 2. 设置瓦片服务器地址 (JS文件)
# 替换默认的 openstreetmap.org 源为我们自建的源
sed -i "s|url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'|url: '${OSM_TILE_SERVER_URL}'|g" ./vendor/assets/leaflet/leaflet.osm.js
# 3. 设置地理编码/搜索服务器地址 (YAML配置文件)
sed -i "s|nominatim_url:.*|nominatim_url: \"$OSM_GEOCODING_SERVER_URL\"|g" ./config/settings.yml
# 4. 设置路由服务器基础地址 (YAML配置文件)
sed -i "s|fossgis_osrm_url:.*|fossgis_osrm_url: \"$OSM_ROUTING_SERVER_URL\"|g" ./config/settings.yml
# 5. 设置路由具体端口 (JS文件)
# 替换 JS 代码中的占位符
sed -i "s|__OSMCarSuffix__|${OSM_CAR_SUFFIX}|g" ./app/assets/javascripts/index/directions/fossgis_osrm.js
sed -i "s|__OSMBikeSuffix__|${OSM_BIKE_SUFFIX}|g" ./app/assets/javascripts/index/directions/fossgis_osrm.js
sed -i "s|__OSMFootSuffix__|${OSM_FOOT_SUFFIX}|g" ./app/assets/javascripts/index/directions/fossgis_osrm.js
配置完成后,就可以启动容器了。启动后,我们需要手动执行 Rails 的数据库迁移命令,以初始化必要的表结构。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
echo ">>> 创建并启动容器..."
docker compose create
docker compose start
echo ">>> 等待服务启动 (60秒)..."
sleep 60
echo ">>> 执行 Rails 数据库迁移 (db:migrate)..."
# 说明:
# RAILS_ENV=development: 使用开发环境配置
# bin/rails db:migrate: 创建数据库表结构
# grep -v ...: 过滤掉大量无关的资源处理日志,保持输出清爽
docker exec openstreetmap-website-web-1 bash -c "
export RAILS_ENV=development
export RAILS_LOG_LEVEL=WARN
mkdir -p /app/log 2>/dev/null || true
bin/rails db:migrate --trace 2>&1 | grep -v 'pngcrush\|advpng\|optipng\|pngquant\|jhead\|jpegoptim\|jpegtran\|gifsicle\|svgo'
echo '>>> 数据库结构初始化完成。'
"
至此,前端服务部署完毕。你可以访问 http://<服务器IP>:3000。服务器IP>
预期表现:
- ✅ 首页加载:网站骨架正常显示。
- ✅ 地图显示:由于 Tile Server 已配置,你应该能看到地图背景。
- ✅ 搜索/导航:搜索框和路径规划功能可用(依赖 Nominatim/OSRM)。
- ⚠️ 地点详情:当你尝试点击地图上的某个具体地点(如某个餐厅或建筑)查看详情时,会显示 Not Found。
- 原因:因为 openstreetmap-website-db 容器里现在只有表结构,没有数据。
- 解决方案:请继续阅读下一章节,我们将把 142GB 的完整数据库注入其中。
数据库数据迁移
首先,根据 WebArena 官方给出的 AMI ,启动 EC2实例
1
2
3
4
5
AMI Information (EC2 console > AMIs). IMPORTANT: AMIs are region-scoped.
Region: us-east-2 (Ohio)
Visibility: Public (available to all accounts in us-east-2)
Name: webarena-with-configurable-map-backend
ID: ami-08a862bf98e3bd7aa
我们会看到一个 osm_website_volumes.tar 包,大概在 142 GB 大小。如果你的服务器离这个 AMI (美国俄亥俄)比较近,可以尝试直接传输。但对于部署在中国内陆或网络条件复杂的服务器,跨半球传输 142GB 数据是一个巨大的挑战。直接传输经常面临速度慢(几百 KB/s)、连接重置等问题。因此我们利用 AWS S3 作为中转站。
- 上行:利用 AWS 内部骨干网,瞬间将数据从美国 EC2 传送到香港 S3 存储桶(速度极快)。
- 下行:生成预签名链接,使用多线程下载工具(aria2)将数据拉取到本地服务器。
登录 EC2 后,安装并配置 AWS CLI。需要先在 AWS 控制台(IAM -> 安全凭证)创建一个 Access Key。
1
2
3
4
5
# 安装 CLI
sudo apt-get install awscli
# 配置凭证
aws configure
配置示例
1
2
3
4
AWS Access Key ID [None]: AKIAxxxxxxxxxxxx <-- 填入你的 Access Key
AWS Secret Access Key [None]: xxxxxxxxxxxxxxx <-- 填入你的 Secret Key
Default region name [None]: us-east-2 <-- 关键:源服务器在俄亥俄,填 us-east-2
Default output format [None]: json
为了缩短下载时的物理距离,我们将中转桶建立在 亚太地区(香港) (ap-east-1)。这里的数据流是 EC2 (US) -> AWS Backbone -> S3 (HK)。不仅避开了公网拥堵,还能跑满 EC2 的上行带宽。
1
2
3
4
5
6
7
# 1. 创建存储桶 (Bucket)
# 桶名必须全球唯一,建议加上日期或随机后缀
aws s3 mb s3://osm-migration-2026 --region ap-east-1
# 2. 执行上传
# 注意:虽然源在俄亥俄,目标在香港,但数据走的是 AWS 全球光纤骨干网,速度极快且稳定。
aws s3 cp osm_website_volumes.tar s3://osm-migration-2026/ --region ap-east-1
数据到达香港后,我们需要将其下载到目标服务器。虽然我们可以在新服务器上配置 AWS CLI 直接下载,但 aws s3 cp 命令默认不支持断点续传。对于 142GB 的超大文件,如果下载到 99% 网络波动中断,通过 CLI 只能从头重来,这在跨公网传输中是灾难性的。可以让 AWS 生成一个临时的 HTTP 下载链接,然后使用专业的下载工具(如 aria2)进行下载,我们先登录新服务器
1
2
3
4
5
# 安装 CLI
sudo apt-get install awscli
# 配置凭证
aws configure
配置示例
1
2
3
4
AWS Access Key ID [None]: AKIAxxxxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxxxxxxx
Default region name [None]: ap-east-1 <-- 新服务器填这个
Default output format [None]: json
然后生成一个有效期为 48 小时 (172800秒) 的下载链接
1
2
3
4
5
6
7
8
9
# --region ap-east-1 必须加上,确保指向正确的区域端点
aws s3 presign s3://osm-migration-2026/osm_website_volumes.tar --expires-in 172800 --region ap-east-1
# 执行下载,可能仍然需要代理加速
# -c: 开启断点续传 (Continue)
# -x 16: 开启 16 线程并发 (加速下载)
# -o: 指定保存的文件名
# 最后的引号内填入上一步生成的长链接
aria2c -c -x 16 -o osm_website_volumes.tar "https://osm-migration-2026.s3.ap-east-1.amazonaws.com/osm_website_volumes.tar?..."
此时,我们的环境状态如下:
- 状态:前端 Web 和后端 DB 容器已经启动。
- 问题:DB 容器是 Docker 自动初始化的空壳,里面没有数据。导致网页虽然能打开,但点击具体地点显示 “Not Found”。
- 目标:142GB 的压缩包 (osm_website_volumes.tar) 已经在新服务器上了。需要用压缩包里的数据“覆盖”掉当前空的数据库卷。
在对数据库底层文件进行操作前,必须停止数据库进程。如果在数据库读写时强行替换文件,会导致不可逆的数据损坏。
1
2
3
cd ~/openstreetmap-website/
echo ">>> 停止服务..."
docker compose stop
执行后,确保 docker ps 中看不到 openstreetmap-website-db 容器。
对于数据注入,我们不会直接在宿主机操作 /var/lib/docker/volumes(因为权限复杂且路径不统一),而是采用 Docker 官方推荐的 “临时容器挂载法”。我们将启动一个微型的 Alpine Linux 容器,同时挂载“宿主机的备份文件”和“目标数据库卷”,在容器内部完成解压。
请确认备份路径:以下命令假设你的压缩包位于 /home/ubuntu/osm_website_volumes.tar。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 启动临时容器执行数据替换
# -v openstreetmap-website_db-data:/target_volume: 挂载数据库卷到容器内
# -v /home/ubuntu:/backup: 挂载备份文件所在的宿主机目录
echo ">>> 开始恢复数据 (预计耗时 10-30 分钟)..."
docker run --rm \
-v openstreetmap-website_db-data:/target_volume \
-v /home/ubuntu:/backup \
alpine \
sh -c "
echo '1. 清理现有的空数据...' && \
rm -rf /target_volume/* && \
echo '2. 解压备份数据...' && \
tar -xvf /backup/osm_website_volumes.tar -C /target_volume --strip-components=2 openstreetmap-website_db-data/_data
"
核心命令详解:
rm -rf /target_volume/*:。Docker 在初次启动时已经生成了一个空的 PostgreSQL 数据库(包含默认的配置文件等)。我们必须先彻底清空它,防止新旧配置文件冲突或版本不兼容。--strip-components=2:- 我们的压缩包目录结构是:openstreetmap-website-db-data/_data/PG_VERSION…
- 但 Docker 卷的根目录直接对应 _data 下的内容。
- 此参数告诉 tar 命令在解压时剥离掉前两层目录,直接将数据甩到卷的根目录下。如果忽略此参数,数据库将无法启动。
解压出来的文件通常保留了旧服务器的用户 ID(UID)。PostgreSQL 容器默认使用 UID 999 运行。如果文件权限归属错误(例如变成了 root),数据库将因无权读写文件而启动失败
1
2
3
4
5
6
echo ">>> 修正文件权限..."
# 999:999 是官方 Postgres 镜像默认的用户:组 ID
docker run --rm \
-v openstreetmap-website_db-data:/target_volume \
alpine \
chown -R 999:999 /target_volume
一切就绪,在openstreetmap-website重新启动服务。
1
2
echo ">>> 启动服务..."
docker compose up -d
启动后,我们需要验证数据是否真的回来了。使用 psql 命令进入容器内部查询路网数据量。
1
2
# 查询当前路网(Ways)的数量
docker exec -it openstreetmap-website-db-1 psql -U openstreetmap -c "SELECT count(*) FROM current_ways;"
- 失败标志:结果为 0(说明还是空库,或者解压路径错了)。
- 成功标志:结果为一个巨大的数字(百万/千万级)。
此时,再次访问你的 Map 网站,点击任意地点详情页,之前的 “Not Found” 应该已经变成了详细的地理信息。
在完成这次迁移后,你可能会关心之前的 AWS 资源如何处理。
1. EC2 实例 (旧服务器/中转服务器)
- 如果不释放:会持续扣费。EC2 是按秒/小时计费的,即使你关机(Stop),挂载的 EBS 硬盘依然在收费。
- 建议:确认数据迁移成功且验证无误后,立即 Terminate(终止/删除) 该实例。
- 操作:EC2 Console -> 选中实例 -> Instance State -> Terminate Instance。
2. S3 存储桶 (osm-migration-2026)
- 如果不释放:会持续扣费,但较少。S3 是按“存储量”和“请求次数”收费的。
- 存储费:香港区域标准存储约 $0.023 / GB / 月。
- 建议:
- 如果你觉得以后可能还需要重新部署,可以留着它当异地冷备份(一个月 20 多块人民币买个数据保险,其实很划算)。
- 如果你确定再也不用了,或者已经把数据下载到了本地服务器并做好了本地备份,那么建议清空并删除桶以节省费用。
- 操作:S3 Console -> 选中桶 -> Empty(清空) -> Delete(删除)。
其余网站(以Shopping为例)
官方提供的镜像托管在 Google Drive 上。
- 下载链接: https://drive.google.com/file/d/1gxXalk9O0p9eu1YkIJcmZta1nvvyAJpA/view?usp=sharing
- 文件 ID: 1gxXalk9O0p9eu1YkIJcmZta1nvvyAJpA
对于这种超大文件,直接使用浏览器下载容易中断,而普通的 wget 往往无法处理 Google Drive 的大文件确认页(Virus scan warning)。
最佳实践:使用 Google OAuth 2.0 API 配合 curl 进行断点续传下载。我们需要一个 Google 的临时授权令牌来通过 API 下载。
- 打开 Google OAuth 2.0 Playground。
- 在左侧 “Select & authorize APIs” 框中,找到 “Input your own scopes”,粘贴以下链接并点击 Authorize APIs: https://www.googleapis.com/auth/drive.readonly
- 点击 “Exchange authorization code for tokens” 按钮。
- 复制生成的 Access Token(通常以 ya29. 开头的一长串字符)。
我们在服务器上使用 curl 命令。为了应对网络波动,我们增加了 -C -(断点续传)和进度条显示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 请替换以下变量
FILE_ID="1gxXalk9O0p9eu1YkIJcmZta1nvvyAJpA"
ACCESS_TOKEN="在此处粘贴你的Access_Token"
OUTPUT_FILE="shopping_final_0712.tar"
# curl 参数解释:
# -H: 添加授权头
# -L: 跟随重定向 (Google Drive API 会重定向到实际下载地址)
# -C -: 开启断点续传 (自动检测已下载大小)
# --progress-bar: 显示进度条 (或者去掉此参数显示详细速度信息)
# -o: 指定输出文件名
curl -L -C - --progress-bar \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"https://www.googleapis.com/drive/v3/files/$FILE_ID?alt=media" \
-o "$OUTPUT_FILE"
提示:Access Token 有效期通常只有 1 小时。如果下载中途 Access Token 过期导致 401 错误,请重新去 Playground 生成一个新的 Token,替换命令中的 Token,再次运行命令。得益于 -C - 参数,它会从断开的地方继续下载。
下载完成后,使用命令来启动
1
2
3
4
5
6
docker load --input shopping_final_0712.tar
docker run --name shopping -p 7770:80 -d shopping_final_0712
wait ~1 min to wait all services to start
docker exec shopping /var/www/magento2/bin/magento setup:store-config:set --base-url="http://<url>:7770" # no trailing slash
docker exec shopping mysql -u magentouser -pMyPassword magentodb -e 'UPDATE core_config_data SET value="http://<url>:7770/" WHERE path = "web/secure/base_url";'
docker exec shopping /var/www/magento2/bin/magento cache:flush
在一次测评结束之后,由于要重置环境,可以通过 stop,rm,重新 run 和exec 这些命令来做,详见官方的文档,这个写的很清楚
其余网站的下载和部署方式类似,看文档就行,值得注意的是,根据issue120讨论,reddit 会遇到发帖速率限制,可以通过这两行额外命令来添加受信任用户和检查
1
2
docker exec -it forum psql -U postmill -c "UPDATE users SET trusted = true WHERE username = 'MarvelsGrantMan136';"
docker exec -it forum psql -U postmill -c "SELECT username, trusted FROM users WHERE username = 'MarvelsGrantMan136';"
下拉框修复
在使用 WebArena 的 Magento 环境进行评测时,会有一个的交互 Bug:Agent 无法正常操作后台的下拉菜单(Dropdown/Combobox)。即当 Agent 试图点击任何下拉菜单选项时(例如选择统计周期),页面没有任何反应,这个问题严重影响了涉及后台配置的任务成功率。
原因分析:
原生
<select>标签下的<option>元素,在浏览器中是由原生控件渲染的,不参与正常的页面布局流。因此,对<option>元素调用getBoundingClientRect(),返回值通常是{x: 0, y: 0, width: 0, height: 0}。这不是 Bug,而是 HTML 规范。在
browser_env/processors.py的fetch_page_accessibility_tree()函数中,为了精简 observation,开启了current_viewport_only=True。代码逻辑会移除所有宽或高为 0 的节点。后果:由于<option>的包围盒是 0,即使下拉框已经展开(expanded: True),里面的选项在 Accessibility Tree 中也是“隐身”的,Agent 根本看不到。部分 UI 框架或浏览器会将
<option>映射为 Accessibility Tree 中的menuitem角色,但底层 DOM 仍然是<option>。如果 Agent 试图基于错误的坐标(0,0)去点击,或者在 Magento 的 JS 事件监听器未完全绑定时点击,就会触发 Magento 的错误处理机制,导致页面重定向。
修复方案:
browser_env/processors.py中的fetch_page_accessibility_tree函数。- 遍历树,找到所有状态为
expanded: True的combobox节点。 - 递归收集这些节点下的所有子节点(即选项)。
- 在执行视口过滤(Viewport Filtering)时,强制保留这些子节点,即使它们的尺寸为 0。
- 遍历树,找到所有状态为
browser_env/actions.py中的execute_action函数(针对CLICK操作)。由于<option>元素没有真实的物理坐标,传统的mouse.click(x, y)必定失败。我们需要回退到 JavaScript DOM 操作。- 当 Agent 发出 CLICK 指令时,检查目标节点。
- 如果目标节点的包围盒无效(宽/高为0)或者是
option/menuitem类型:- 针对 Option: 不移动鼠标,直接通过 Playwright 执行 JS,修改父级
<select>的 value,并手动触发change事件。 - 针对 Menuitem: 先检查其底层 DOM 节点是否其实是
<option>,如果是,按上述逻辑处理。
- 针对 Option: 不移动鼠标,直接通过 Playwright 执行 JS,修改父级
修复效果:现在,当下拉框展开时,Agent 可以清晰地看到内部结构,并且可以准确选中目标:
1
2
3
4
[2321] combobox 'Period' focused: True hasPopup: menu expanded: True
[2362] menuitem 'Day' selected: False
[2363] menuitem 'Month' selected: True
[2364] menuitem 'Year' selected: False