使用RProtoBuf读取GTFS实时公交数据时遇S3method错误求助
R中解码GTFS实时Protocol Buffer数据的问题解决
在开发Shiny应用处理WMATA和Arlington Regional Transit的GTFS数据时,静态文件用tidytransit处理正常,但实时GTFS的Protocol Buffer(pb)数据解码遇到问题:
- 用httr2拉取WMATA实时行程更新数据保存为
update.pb - 通过
readProtoFiles加载GTFS实时proto文件后描述符正常,但执行mb_trip <- read-methods("transit_realtime.TripUpdate", "update.pb")[["timestamp"]]时触发错误:Error in .S3methods(generic.function, class, envir, dropPath = dropPath) : no function 'transit_realtime.TripUpdate' is visible
以下是针对性的解决方法和疑问解答:
1. 纠正RProtoBuf的调用方式
你使用的read-methods是错误的函数,RProtoBuf中需用read()配合proto生成的类来解析数据,正确流程如下:
- 先加载官方GTFS实时proto定义文件(本地保存为
gtfs-realtime.proto),生成对应的R类:library(RProtoBuf) # 加载proto文件,生成transit_realtime命名空间下的结构类 readProtoFiles("gtfs-realtime.proto") - 读取pb二进制文件并解析为根结构
FeedMessage(包含header和entity数组):# 读取pb文件内容 feed <- read(transit_realtime.FeedMessage, "update.pb") - 提取header的timestamp:
header_timestamp <- feed$header$timestamp - 筛选对应Metrobus T18的TripUpdate数据:
# 遍历所有entity,筛选目标线路的更新 t18_updates <- lapply(feed$entity, function(e) { if (!is.null(e$trip_update) && e$trip_update$trip$route_id == "T18") { e$trip_update } }) # 过滤空条目 t18_updates <- Filter(Negate(is.null), t18_updates)
2. 关于pb数据头的疑问
GTFS实时API返回的pb数据本身完全符合官方proto定义的结构,不需要额外添加自定义头。proto定义中的FeedMessage已经内置了header字段(包含timestamp、版本号等元数据),API返回的二进制流直接对应这个根结构,你拉取的update.pb无需修改头信息。
3. API数据的预处理要求
不需要额外预处理,只需确保拉取的是原始二进制数据,避免转成文本格式。用httr2拉取时注意设置正确的响应处理:
library(httr2) # 拉取实时数据,指定接收二进制格式 resp <- request("WMATA_REAL_TIME_API_URL") %>% req_headers(Accept = "application/x-protobuf") %>% req_perform() # 保存为二进制pb文件 writeBin(resp_body_raw(resp), "update.pb")
核心是用resp_body_raw()获取原始二进制,而非resp_body_string(),防止编码错误导致解析失败。
额外注意事项
- 确保使用的GTFS实时proto文件为官方最新版本,与API返回的数据结构匹配
- WMATA的GTFS实时数据可能有细微扩展,但核心兼容官方proto定义,用官方文件即可解析
- 若筛选不到T18的更新,可通过
str(feed)查看完整返回结构,确认API是否返回了对应线路的数据
内容的提问来源于stack exchange,提问作者Nadia Bey
相关产品推荐
相关产品推荐

