GTFS Realtime Python Bindings
The gtfs-realtime-bindings library provides Python classes generated from the GTFS-realtime Protocol Buffer specification. These classes enable developers to parse binary Protocol Buffer GTFS-realtime data feeds into Python objects, facilitating the consumption of real-time transit information. The project is currently at version 2.0.0 and has been maintained by MobilityData since early 2019, with updates typically released to stay in sync with the evolving GTFS-realtime specification and Protobuf library.
Warnings
- breaking The `gtfs-realtime-bindings` library relies on the underlying `protobuf` library. Future major versions of `protobuf` (e.g., beyond 5.0) may introduce breaking changes or require specific versions for optimal compatibility, potentially leading to parsing errors if `protobuf` is not correctly managed.
- gotcha Protocol Buffers distinguish between a field explicitly set to its default value (e.g., 0 for an integer) and a field that is entirely unset. Directly accessing fields without checking for their presence using the `HasField()` method can lead to misinterpretation, as an unset field will return its default value in Python, which might not be the intended semantic zero or empty string.
- gotcha The `gtfs-realtime-bindings` library is generated from the `gtfs-realtime.proto` specification. The GTFS Realtime specification itself evolves, introducing new fields, deprecating old ones, or clarifying semantics (e.g., GTFS-realtime v2.0 spec). Using older bindings with newer feeds (or vice-versa) may result in parsing issues or incorrect interpretation of data, particularly with experimental features or required field changes.
- gotcha The GTFS Realtime specification provides guidelines on data freshness. Specifically, Trip Updates and Vehicle Positions should generally not be older than 90 seconds, and Service Alerts not older than 10 minutes. Consuming stale data, even if successfully parsed, can lead to inaccurate real-time information for end-users.
Install
-
pip install gtfs-realtime-bindings
Imports
- gtfs_realtime_pb2
from google.transit import gtfs_realtime_pb2
Quickstart
import requests
from google.transit import gtfs_realtime_pb2
import os
# Replace with the actual URL of your GTFS-realtime data feed
GTFS_REALTIME_FEED_URL = os.environ.get('GTFS_REALTIME_FEED_URL', 'https://gtfs.example.com/realtime-feed.pb')
# Optional: If your API requires an API key in headers
API_KEY = os.environ.get('GTFS_REALTIME_API_KEY', '')
headers = {'x-api-key': API_KEY} if API_KEY else {}
try:
response = requests.get(GTFS_REALTIME_FEED_URL, headers=headers, timeout=10)
response.raise_for_status() # Raise an exception for HTTP errors
feed = gtfs_realtime_pb2.FeedMessage()
feed.ParseFromString(response.content)
print(f"Successfully parsed feed from {GTFS_REALTIME_FEED_URL}")
print(f"Feed header timestamp: {feed.header.timestamp}")
print(f"Number of entities: {len(feed.entity)}")
for entity in feed.entity:
if entity.HasField('trip_update'):
print(f" Trip Update: {entity.trip_update.trip.trip_id}")
# Example of accessing a field, always check HasField() first
if entity.trip_update.trip.HasField('route_id'):
print(f" Route ID: {entity.trip_update.trip.route_id}")
elif entity.HasField('vehicle'):
print(f" Vehicle Position: {entity.vehicle.trip.trip_id}")
if entity.vehicle.HasField('position'):
print(f" Lat: {entity.vehicle.position.latitude}, Lon: {entity.vehicle.position.longitude}")
elif entity.HasField('alert'):
print(f" Service Alert: {entity.alert.header_text.translation[0].text if entity.alert.header_text.translation else 'N/A'}")
except requests.exceptions.RequestException as e:
print(f"Error fetching GTFS-realtime feed: {e}")
except Exception as e:
print(f"Error parsing GTFS-realtime feed: {e}")