Advertisement
Guest User

Untitled

a guest
Dec 14th, 2019
198
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.69 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2.  
  3.  
  4. import math
  5. import pandas as pd
  6. from pathlib import Path
  7. import time
  8. import numpy as np
  9.  
  10. from selenium.webdriver.firefox.options import Options
  11. from selenium import webdriver
  12. from selenium.webdriver.common.keys import Keys
  13. from selenium.webdriver.common.action_chains import ActionChains
  14.  
  15. from selenium.webdriver.common.by import By
  16. from selenium.webdriver.support.ui import WebDriverWait
  17. from selenium.webdriver.support import expected_conditions as EC
  18.  
  19. from bs4 import BeautifulSoup
  20.  
  21. # search parameters
  22. search_date = '18.12.2019'
  23. search_time = '08:00'
  24. time_dep_arr = 1 # 1 time is departue, 0 is arrival (?!)
  25.  
  26. # Hamburg HBF coords
  27. outFile =  'C:/WorkExchange/Python/Git/OPNV/HH_HBF.xlsx'
  28. coords =    [(53.82, 9.40), #NW
  29.               (53.82, 10.50), #NE
  30.               (53.20, 9.40), #SW
  31.               (53.20, 10.50)  #SE
  32.              ]
  33.  
  34. # Kernbereich Hamburg
  35. #coords =    [(53.644949, 9.732696), #NW
  36. #              (53.644949, 10.321555), #NE
  37. #              (53.418800, 9.732696), #SW
  38. #              (53.418800, 10.321555)  #SE
  39. #             ]
  40.  
  41. destination = "Hamburg Hbf"
  42. destination_city = "Hamburg"
  43. destination_type = "STATION" # oder COORDINATE
  44. destination_coord = (53.55297, 10.0069)
  45.  
  46. # grid spacing in meters
  47. spacing = 100
  48.  
  49.  
  50. def calc_deg_increments(meters, coords_list):
  51.     # returns (lat,lon) mean degree increments representing x meters in coords area
  52.    
  53.     avg_lat = sum([l[0] for l in coords_list]) / len(coords_list)
  54.    
  55.     # earth circle in meters at avg_lat
  56.     circle = 6372800 * 2 * 3.141592 * math.cos(math.radians(avg_lat))
  57.    
  58.     # meters in degrees at avg_lat
  59.     lat_dist_in_deg = 360 / (circle / meters)
  60.    
  61.     # longitude distance in degrees along great circle
  62.     lon_dist_in_deg = 360 / (6372800 * 2 * 3.141592 / meters)
  63.    
  64.     return (lat_dist_in_deg, lon_dist_in_deg)
  65.  
  66. def haversine(coord1, coord2):
  67.     R = 6372800  # Earth radius in meters
  68.     lat1, lon1 = coord1
  69.     lat2, lon2 = coord2
  70.    
  71.     phi1, phi2 = math.radians(lat1), math.radians(lat2)
  72.     dphi       = math.radians(lat2 - lat1)
  73.     dlambda    = math.radians(lon2 - lon1)
  74.    
  75.     a = math.sin(dphi/2)**2 + \
  76.         math.cos(phi1)*math.cos(phi2)*math.sin(dlambda/2)**2
  77.    
  78.     return 2*R*math.atan2(math.sqrt(a), math.sqrt(1 - a))
  79.  
  80.  
  81. def string_to_minutes(inStr):
  82.     """ Input is string in format '1:15 h' and returns minutes """
  83.  
  84. def build_url(start_x, start_y, destination, destination_city, destination_type,
  85.                    search_date, search_time, time_dep_arr):
  86.  
  87.     #start_x = "9.9771741231548"
  88.     #start_y = "53.55145216841"
  89.    
  90.     url = "https://geofox.hvv.de/jsf/home.seam?execute=true&" +\
  91.           f"date={search_date}&time={search_time}&" +\
  92.           "language=de&start=&startCity=Hamburg&startType=COORDINATE&" +\
  93.           f"startX={start_x}&startY={start_y}2&" +\
  94.           f"destination={destination}&" +\
  95.           f"destinationCity={destination_city}&destinationType={destination_type}&" +\
  96.           f"timeIsDeparture={time_dep_arr}&wayBy="
  97.    
  98.     return url
  99.  
  100.  
  101.  
  102.  
  103. if __name__ == '__main__':  
  104.        
  105.     # check if output already exists, if then continue, else create new
  106.     if Path(outFile).is_file():
  107.         outDF = pd.read_excel(outFile)
  108.     else:
  109.         outDF = pd.DataFrame(columns=['org_coord',
  110.                                       'org_lat',
  111.                                       'org_lon',
  112.                                       'opnv_time',
  113.                                       'bike_time',
  114.                                       'opnv_changes',
  115.                                       'dist_meters'])
  116.  
  117.     #create new driver
  118.     options = webdriver.firefox.options.Options()
  119.     #options.add_argument('-headless')    
  120.     driver = webdriver.Firefox(options=options)
  121.    
  122.     # calculate degree steps for lat and lon
  123.     spacing_deg = calc_deg_increments(spacing, coords)    
  124.    
  125.     cur_lat = coords[0][0]
  126.     cur_lon = coords[0][1]
  127.    
  128.     # close coords
  129.     #cur_lat = 53.521251
  130.     #cur_lon = 9.979911
  131.    
  132.     # fail coords
  133.     #cur_lat = 53.540028
  134.     #cur_lon = 19.929517
  135.        
  136.     while cur_lat > coords[3][0]:        
  137.         while cur_lon < coords[3][1]:
  138.            
  139.             cur_lat = round(cur_lat, 6)
  140.             cur_lon = round(cur_lon, 6)
  141.             coord_tuple = (cur_lat, cur_lon)            
  142.            
  143.             # skip distances already fetched
  144.             if str(coord_tuple) in outDF['org_coord'].to_list():
  145.                 cur_lon = cur_lon + spacing_deg[1]
  146.                 print(str(coord_tuple) + " skipped" )
  147.                 continue
  148.            
  149.             dist_meters = haversine((cur_lat, cur_lon), destination_coord)
  150.    
  151.             url = build_url(cur_lon, cur_lat, destination, destination_city, destination_type,
  152.                    search_date, search_time, time_dep_arr)
  153.    
  154.             # wait for schedule table to load, if fail -> wait 120s
  155.             try:
  156.                 driver.get(url)
  157.            
  158.                 if "Mit diesen Angaben können wir leider keine Verbindung für Sie finden" in driver.page_source:
  159.                     cur_lon = cur_lon + spacing_deg[1]
  160.                     continue
  161.                
  162.                 if "Es ist ein Fehler aufgetreten" in driver.page_source:
  163.                     time.sleep(30)
  164.                     cur_lon = cur_lon + spacing_deg[1]
  165.                     continue
  166.                
  167.                 element = WebDriverWait(driver, 10).until(
  168.                     EC.presence_of_element_located((By.CLASS_NAME, "c-schedule-table"))
  169.                 )
  170.  
  171.                
  172.             except:
  173.                
  174.                 if "Mit diesen Angaben können wir leider keine Verbindung für Sie finden" in driver.page_source:
  175.                     cur_lon = cur_lon + spacing_deg[1]
  176.                     continue
  177.                
  178.                 time.sleep(30)
  179.                 driver.get(url)
  180.                
  181.                 if "Mit diesen Angaben können wir leider keine Verbindung für Sie finden" in driver.page_source:
  182.                     cur_lon = cur_lon + spacing_deg[1]
  183.                     continue
  184.                
  185.                 if "Es ist ein Fehler aufgetreten" in driver.page_source:
  186.                     time.sleep(30)
  187.                     cur_lon = cur_lon + spacing_deg[1]
  188.                     continue
  189.                
  190.                 element = WebDriverWait(driver, 10).until(
  191.                     EC.presence_of_element_located((By.CLASS_NAME, "c-schedule-table"))
  192.                 )
  193.        
  194.        
  195.                
  196.             # get site html in beautifulsoup as well (should work parallel to clickEntries)
  197.             blankHTML_all = driver.page_source
  198.             soup_all = BeautifulSoup(blankHTML_all, "html5lib")        
  199.             soup_sched_table = soup_all.find('div', {'class':'c-schedule-table'})
  200.            
  201.             # OPNV time
  202.             try:
  203.                 soup_duration_tags = soup_sched_table.find_all('div', {'class': lambda x: 'duration' in x})    
  204.                 times_list = []
  205.                 for time_tag in soup_duration_tags:
  206.                     time_string = time_tag.text
  207.                     time_text_split = time_string.split(":")
  208.                    
  209.                     # remove all letters from second part
  210.                     time_text_split[1] = [ ''.join(i for i in time_text_split[1] if i.isdigit())][0]
  211.                    
  212.                     # caluclate time in minutes
  213.                     time_int = int(time_text_split[0])*60 + int(time_text_split[1])        
  214.                     times_list.append(time_int)
  215.                
  216.                 opnv_time = min(times_list)
  217.            
  218.                
  219.            
  220.                 # OPNV Umstiege
  221.                 soup_change_tags = soup_sched_table.find_all('div', {'class': lambda x: 'change' in x})    
  222.                 opnv_changes = min([int(x.text) for x in soup_change_tags])
  223.            
  224.             except:
  225.                 time.sleep(30)
  226.                 cur_lon = cur_lon + spacing_deg[1]
  227.                 continue
  228.            
  229.             # bike travel time
  230.             bike_button = driver.find_element_by_xpath('/html/body/div[3]/div/div/main/div/app-root/app-search-container/app-search/div/div[3]/div/div[2]/div/ul/li[4]/button/span[2]')
  231.             driver.execute_script("arguments[0].scrollIntoView();", bike_button)
  232.             bike_button.click()
  233.            
  234.             time.sleep(3)
  235.            
  236.             if "Es ist ein Fehler aufgetreten" in driver.page_source:
  237.                     time.sleep(30)
  238.                     cur_lon = cur_lon + spacing_deg[1]
  239.                     continue
  240.            
  241.             try:
  242.                 element = WebDriverWait(driver, 10).until(
  243.                         EC.presence_of_element_located((By.CSS_SELECTOR, ".wrapper > div:nth-child(2) > div:nth-child(1) > app-bikepath-result:nth-child(1) > div:nth-child(1) > div:nth-child(3)"))
  244.                     )
  245.            
  246.                 blankHTML_bike = driver.page_source
  247.                 soup_bike = BeautifulSoup(blankHTML_bike, "html5lib")
  248.                 bike_container = soup_bike.find_all('div', {'class': 'content ng-star-inserted'})
  249.                
  250.                 bike_time_list= []
  251.                 for bike_tags in bike_container:
  252.                     bike_str = bike_tags.text
  253.                     bike_time1 = int(bike_str[ bike_str.find('Dauer:') + 6 : bike_str.find('Min.')  ].strip())
  254.                     bike_time_list.append(bike_time1)
  255.                 bike_time= min(bike_time_list)
  256.            
  257.             except:
  258.                 bike_time = np.NaN
  259.                 cur_lon = cur_lon + spacing_deg[1]
  260.                 continue
  261.  
  262.            
  263.             outDF = outDF.append({'org_coord':coord_tuple,
  264.                                   'org_lat':cur_lat,
  265.                                   'org_lon':cur_lon,
  266.                                   'opnv_time':opnv_time,
  267.                                   'bike_time':bike_time,
  268.                                   'opnv_changes':opnv_changes,
  269.                                   'dist_meters':dist_meters},
  270.                             ignore_index=True)
  271.            
  272.             if len(outDF) % 100 == 0:
  273.                 print(str(len(outDF)) + " done")
  274.                 outDF.drop_duplicates(inplace=True)
  275.                 outDF.to_excel(outFile, index=False)
  276.             elif len(outDF) % 20 == 0:
  277.                 outDF.to_excel(outFile, index=False)
  278.                
  279.        
  280.             cur_lon = cur_lon + spacing_deg[1]
  281.        
  282.         cur_lon = coords[0][1]
  283.         cur_lat = cur_lat - spacing_deg[0]
  284.  
  285.     outDF.drop_duplicates(inplace=True)
  286.     outDF.to_excel(outFile, index=False)    
  287.     driver.close()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement