42Cummer commited on
Commit
9d931e7
·
verified ·
1 Parent(s): 59a93f4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -0
app.py CHANGED
@@ -5,6 +5,13 @@ import requests
5
  from bs4 import BeautifulSoup
6
  import tempfile
7
  import os
 
 
 
 
 
 
 
8
 
9
 
10
 
@@ -228,9 +235,161 @@ def serviceAlerts():
228
 
229
  return jsonify(alerts)
230
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  @app.route('/', methods=['GET'])
232
  def health_check():
233
  return 'Backend is running!', 200
234
 
235
  if __name__ == '__main__':
 
236
  app.run(debug=True, port=5000)
 
5
  from bs4 import BeautifulSoup
6
  import tempfile
7
  import os
8
+ from selenium import webdriver
9
+ from selenium.webdriver.chrome.options import Options
10
+ from selenium.webdriver.common.by import By
11
+ from selenium.webdriver.support.ui import WebDriverWait
12
+ from selenium.webdriver.support import expected_conditions as EC
13
+ from datetime import datetime
14
+ import pytz
15
 
16
 
17
 
 
235
 
236
  return jsonify(alerts)
237
 
238
+ @app.route('/seek', methods=['POST'])
239
+ def seek():
240
+ if not request.is_json:
241
+ return jsonify({'error': 'Request must be JSON'}), 400
242
+
243
+ data = request.get_json()
244
+ stop_id = data.get('stop')
245
+
246
+ if not stop_id:
247
+ return jsonify({'error': 'Stop ID is required'}), 404
248
+
249
+ url = url = f"https://www.transsee.ca/smsstop?a=ttc&id={stop_id}"
250
+ headers = {
251
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
252
+ 'Referer': 'https://www.transsee.ca/',
253
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
254
+ 'Accept-Language': 'en-US,en;q=0.9',
255
+ 'DNT': '1', # Do Not Track
256
+ 'Connection': 'keep-alive',
257
+ 'Upgrade-Insecure-Requests': '1'
258
+ }
259
+ # Use Selenium to handle redirects and wait for page to load
260
+ options = Options()
261
+ options.add_argument("--headless=new")
262
+ options.add_argument("--disable-gpu")
263
+ options.add_argument("--no-sandbox")
264
+
265
+ driver = webdriver.Chrome(options=options)
266
+ driver.get(url)
267
+
268
+ # Wait for the page to load and look for divp elements
269
+ try:
270
+ WebDriverWait(driver, 15).until(
271
+ EC.presence_of_element_located((By.CLASS_NAME, "divp"))
272
+ )
273
+ except:
274
+ pass
275
+
276
+ html = driver.page_source
277
+ driver.quit()
278
+
279
+ soup = BeautifulSoup(html, 'html.parser')
280
+
281
+ # Extract routes from the <p> tags that contain <b> tags
282
+ routes = []
283
+ for p_tag in soup.find_all('p', id=re.compile(r'^\d+_\d+$')):
284
+ b_tag = p_tag.find('b')
285
+ if b_tag:
286
+ route_link = b_tag.find('a', href=re.compile(r'stoplist\?a=ttc&r=\d+'))
287
+ if route_link:
288
+ route_text = route_link.get_text(strip=True)
289
+ # Remove dash between number and name (e.g., "133-Neilson" -> "133 Neilson")
290
+ route_text = re.sub(r'(\d+)-([A-Za-z])', r'\1 \2', route_text)
291
+
292
+ # Get the full text content of the p tag for branch and destination
293
+ full_text = p_tag.get_text()
294
+
295
+ # Extract branch (letter/number after "going" if it exists)
296
+ branch = None
297
+ branch_match = re.search(r'going\s+([A-Za-z0-9]+)', full_text)
298
+ if branch_match:
299
+ branch_text = branch_match.group(1)
300
+ # Only treat single characters/numbers as branches (A, B, 1, 2, etc.)
301
+ if len(branch_text) == 1 and branch_text.isalnum():
302
+ branch = branch_text
303
+
304
+ # Extract destination (everything after "to" until the end or next punctuation)
305
+ destination = None
306
+ destination_match = re.search(r'to\s+([^.]+)', full_text)
307
+ if destination_match:
308
+ destination = destination_match.group(1).strip()
309
+
310
+ routes.append({
311
+ 'name': route_text,
312
+ 'branch': branch,
313
+ 'destination': destination
314
+ })
315
+
316
+ pattern = re.compile(r'^\d{1,3}_\d{3,5}_[1-4]$')
317
+
318
+ vehicles = []
319
+
320
+ for div_tag in soup.find_all('div', class_='divp', id=pattern):
321
+ vehicle_id = div_tag.get('id')
322
+ id_parts = vehicle_id.split('_')
323
+ route = id_parts[0] # Extract first 1-3 digits as route
324
+
325
+ vehicle_data = {
326
+ 'route': route,
327
+ }
328
+
329
+ # Get both timedisp times
330
+ timedisp_elements = div_tag.find_all('time', class_='timedisp')
331
+ if len(timedisp_elements) >= 2:
332
+ vehicle_data['actual'] = timedisp_elements[0].get_text(strip=True)
333
+ vehicle_data['scheduled'] = timedisp_elements[1].get_text(strip=True)
334
+ elif len(timedisp_elements) == 1:
335
+ vehicle_data['actual'] = timedisp_elements[0].get_text(strip=True)
336
+ vehicle_data['scheduled'] = None
337
+ else:
338
+ vehicle_data['actual'] = None
339
+ vehicle_data['scheduled'] = None
340
+
341
+ # If actual is null, replace with current time (bus is at stop)
342
+ if vehicle_data['actual'] is None:
343
+ # Get current time in EST/EDT timezone
344
+ est_tz = pytz.timezone('America/New_York')
345
+ current_time = datetime.now(est_tz)
346
+ vehicle_data['actual'] = current_time.strftime("%I:%M:%S%p")
347
+
348
+ # Get delay/ahead status (like "1:10 ahead")
349
+ delay_span = None
350
+ for span in div_tag.find_all('span', style=True):
351
+ if 'color: light-dark' in span['style']:
352
+ span_text = span.get_text(strip=True)
353
+ if 'ahead' in span_text or 'behind' in span_text:
354
+ delay_span = span
355
+ break
356
+
357
+ if delay_span:
358
+ delay_text = delay_span.get_text(strip=True)
359
+ if 'ahead' in delay_text:
360
+ vehicle_data['delay'] = "+" + delay_text.replace(' ahead', '')
361
+ elif 'behind' in delay_text:
362
+ vehicle_data['delay'] = "-" + delay_text.replace(' behind', '')
363
+ else:
364
+ vehicle_data['delay'] = delay_text
365
+ else:
366
+ vehicle_data['delay'] = "0"
367
+
368
+ # Get vehicle number from #MapMain link or plain text
369
+ vehicle_link = div_tag.find('a', href="#MapMain")
370
+ if vehicle_link:
371
+ vehicle_data['vehicle_number'] = vehicle_link.get_text(strip=True)
372
+ else:
373
+ # Look for vehicle number in plain text like "Vehicle 1243 Load"
374
+ text = div_tag.get_text()
375
+ match = re.search(r'Vehicle\s+(\d+)', text)
376
+ if match:
377
+ vehicle_data['vehicle_number'] = match.group(1)
378
+ else:
379
+ vehicle_data['vehicle_number'] = None
380
+
381
+ vehicles.append(vehicle_data)
382
+
383
+ return jsonify({
384
+ 'stop': stop_id,
385
+ 'routes': routes,
386
+ 'vehicles': vehicles
387
+ })
388
+
389
  @app.route('/', methods=['GET'])
390
  def health_check():
391
  return 'Backend is running!', 200
392
 
393
  if __name__ == '__main__':
394
+ #app.run(debug=True, port=4999)
395
  app.run(debug=True, port=5000)