tyriaa
first commit
5445916
from flask import Flask, jsonify, render_template
from bs4 import BeautifulSoup
import requests
from datetime import datetime
import os
from dotenv import load_dotenv
from rtm_scraper import RTMTraffic # Importer notre nouveau scraper
# Charger les variables d'environnement
load_dotenv()
app = Flask(__name__)
TOMTOM_API_KEY = os.getenv("TOMTOM_API_KEY")
# Coordonnées du centre de Marseille
MARSEILLE_CENTER = {"lat": 43.2965, "lon": 5.3698}
def scrape_marseille_ferries():
"""
Scrape les données des ferries depuis le site du Port de Marseille
Returns:
list: Liste des ferries avec leurs horaires
"""
try:
# Headers pour simuler un navigateur web
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'Accept-Language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7'
}
# Faire la requête
response = requests.get("https://pcs.marseille-port.fr/webix/public/escales/ferries", headers=headers)
response.raise_for_status()
# Parser le HTML
soup = BeautifulSoup(response.text, 'html.parser')
# Initialiser la liste pour les navires
ships_data = []
# Trouver la table des ferries
table = soup.find('table', class_='table')
if not table:
return []
# Trouver toutes les lignes de la table (sauf l'en-tête)
rows = table.find_all('tr')[1:] # Skip header
for row in rows:
# Trouver toutes les cellules de la ligne
cells = row.find_all('td')
if len(cells) >= 6: # Vérifier qu'il y a assez de cellules
try:
# Extraire les informations
navire = cells[1].get_text(strip=True)
quai = cells[3].get_text(strip=True)
eta = cells[2].get_text(strip=True) # Heure d'arrivée prévue
etd = cells[4].get_text(strip=True) # Heure de départ prévue
destination = cells[5].get_text(strip=True) # Destination
# Créer l'objet navire seulement si au moins une des dates est spécifiée
if eta != "-" and etd != "-":
ship_data = {
'name': navire,
'location': quai,
'arrival': eta,
'departure': etd,
'destination': destination
}
ships_data.append(ship_data)
except Exception:
continue
# Trier par date d'arrivée
ships_data.sort(key=lambda x: x['arrival'])
return ships_data
except Exception:
return []
def get_rtm_traffic():
"""
Récupère les informations de trafic RTM
Returns:
dict: Informations de trafic RTM
"""
rtm = RTMTraffic()
traffic_info = rtm.get_alerts()
# Organiser les perturbations par type et période
organized_traffic = {
'current': {
'metro': [],
'bus': [],
'tram': [],
'other': []
},
'upcoming': {
'metro': [],
'bus': [],
'tram': [],
'other': []
}
}
def process_alerts(alerts, is_upcoming=False):
for alert in alerts:
for line in alert['affected_lines']:
# Déterminer le type de transport basé sur le numéro de ligne
transport_type = 'other'
if line.startswith('M'):
transport_type = 'metro'
elif line.startswith('T'):
transport_type = 'tram'
elif line.isdigit() or any(c.isdigit() for c in line):
transport_type = 'bus'
period = 'upcoming' if is_upcoming else 'current'
organized_traffic[period][transport_type].append({
'line': line,
'title': alert['title'],
'description': alert['description'],
'validity': alert['validity'],
'type': alert['type']
})
# Traiter les alertes du jour
if 'AlertesToday' in traffic_info:
process_alerts(traffic_info['AlertesToday'])
# Traiter les alertes à venir
if 'AlertesComing' in traffic_info:
process_alerts(traffic_info['AlertesComing'], True)
return organized_traffic
@app.route('/')
def index():
return render_template('marseille_traffic.html', api_key=TOMTOM_API_KEY)
@app.route('/get_ship_schedules')
def get_ship_schedules():
try:
# Récupérer les données des ferries
ferry_data = scrape_marseille_ferries()
return jsonify({
'ferries': ferry_data,
'last_update': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
})
except Exception as e:
return jsonify({
'error': str(e),
'ferries': [],
'last_update': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
})
@app.route('/api/rtm-traffic')
def get_rtm_traffic_api():
"""
Endpoint API pour obtenir les informations de trafic RTM
"""
traffic_info = get_rtm_traffic()
return jsonify(traffic_info)
@app.route('/api/here-incidents')
def here_incidents():
incidents = get_traffic_incidents()
if incidents is None:
return jsonify([])
# Transformer les incidents en format GeoJSON pour la carte
features = []
for incident in incidents.get('results', []):
# Les coordonnées sont dans le format OLR, nous devons les extraire
location = incident['location']
incident_details = incident['incidentDetails']
# Créer une feature GeoJSON pour chaque incident
feature = {
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [5.3698, 43.2965] # Pour l'instant, on utilise le centre de Marseille
},
'properties': {
'id': incident_details['id'],
'type': incident_details['type'],
'description': incident_details.get('description', {}).get('value', ''),
'startTime': incident_details['startTime'],
'endTime': incident_details['endTime'],
'criticality': incident_details['criticality'],
'roadClosed': incident_details.get('roadClosed', False)
}
}
features.append(feature)
return jsonify({
'type': 'FeatureCollection',
'features': features
})
@app.route('/incidents')
def get_incidents():
# Définir la zone autour de Marseille (rayon approximatif)
bounding_box = f"{MARSEILLE_CENTER['lon']-0.1},{MARSEILLE_CENTER['lat']-0.1},{MARSEILLE_CENTER['lon']+0.1},{MARSEILLE_CENTER['lat']+0.1}"
# URL pour les incidents
incidents_url = f"https://api.tomtom.com/traffic/services/5/incidentDetails?bbox={bounding_box}&fields=%7Bincidents%7Btype%2Cgeometry%7Btype%2Ccoordinates%7D%2Cproperties%7BiconCategory%7D%7D%7D&language=fr-FR&categoryFilter=0%2C1%2C2%2C3%2C4%2C5%2C7%2C8%2C9%2C10%2C11%2C14&timeValidityFilter=present&key={TOMTOM_API_KEY}"
try:
print(f"Requête TomTom URL: {incidents_url}")
# Récupérer les incidents
incidents_response = requests.get(incidents_url)
incidents_response.raise_for_status()
incidents_data = incidents_response.json()
print(f"Réponse TomTom brute: {incidents_data}")
# Transformer les incidents en format GeoJSON
formatted_incidents = []
for incident in incidents_data.get("incidents", []):
try:
coordinates = incident.get("geometry", {}).get("coordinates", [])
if coordinates:
formatted_incident = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": coordinates[0] if isinstance(coordinates[0], list) else coordinates
},
"properties": {
"type": incident.get("type", ""),
"description": incident.get("description", ""),
"from": incident.get("from", ""),
"to": incident.get("to", ""),
"delay": incident.get("delay", 0),
"length": incident.get("length", 0),
"iconCategory": incident.get("properties", {}).get("iconCategory", "default")
}
}
formatted_incidents.append(formatted_incident)
print(f"Incident formaté: {formatted_incident}")
except Exception as e:
print(f"Erreur lors du formatage d'un incident : {str(e)}")
continue
print(f"Nombre total d'incidents formatés: {len(formatted_incidents)}")
return jsonify({"incidents": formatted_incidents})
except Exception as e:
print(f"Erreur lors de la récupération des incidents : {str(e)}")
return jsonify({"error": str(e), "incidents": []}), 500
if __name__ == '__main__':
app.run(debug=True)