├── .gitignore
├── .idea
├── .gitignore
├── 3- Scrapper.iml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
└── modules.xml
├── .vscode
└── settings.json
├── Procfile
├── README.md
├── Variables Heroku.png
├── app.py
├── instructions.txt
├── requirements.txt
├── runtime.txt
└── templates
└── index.html
/.gitignore:
--------------------------------------------------------------------------------
1 | venv/*
2 | parsing_analysis/*
3 | .vscode/*
4 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/3- Scrapper.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.pythonPath": "venv\\Scripts\\python.exe"
3 | }
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn -t 120 -b :$PORT app:app
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Build Your Free GPS Routing API with Python Flask 🗺️
2 | *Build your free Distance Matrix API deployed on the cloud*
3 |
4 | ### Article
5 | In this [Article](https://s-saci95.medium.com/build-your-free-gps-routing-api-to-calculate-road-distances-143632cc4917), we will create a free, easy-to-implement and customizable (and a bit slow :D) Distance Matrix API using Flask with a Selenium Bot deployed on Heroku
6 |
7 | ### How does it work?
8 | Before starting to read this part, please forget everything you know about how to put in production a fast, efficient and stable code ensuring quick response with limited resources.
9 | This will be simple, quick and dirty, with no intention to be a scalable solution. The performance will be way lower than if you directly query the official Google API — but here it’s free :)
10 |
11 | 
12 |
13 | #### Let us do it in three steps
14 | 1. Build a Selenium Bot that will query the distance from City A to City B in Google Maps Website
15 | 2. Set up your Flask API that will receive the request and return a distance
16 | 3. Deploy your code on Heroku
17 |
18 |
19 | ## Code
20 | This repository code is ready to be deployed on Heroku:
21 | ##### 1. Copy Github repository in your local folder and create a local python environment
22 | ##### 2. Download libraries listed in requirements.txt
23 | ```
24 | pip3 install -r requirements.txt
25 | ```
26 | ##### 3. Download Buildpacks on Heroku to use Selenium + ChromeDriver
27 | Go to settings > Add Buildpack
28 | 
29 | ```
30 | Enter Two Links
31 | https://github.com/heroku/heroku-buildpack-google-chrome
32 | https://github.com/heroku/heroku-buildpack-chromedriver
33 | ```
34 | ##### 4. Set up Environment Variables on Heroku
35 | 
36 | ```
37 | CHROMEDRIVER_PATH: /app/.chromedriver/bin/chromedriver
38 | GOOGLE_CHROME_BIN: /app/.apt/usr/bin/google-chrome
39 | ```
40 | ##### 5. Deploy your app on Heroku
41 |
42 |
43 | ## Test your API
44 | #### Test your API to calculate the distance
45 | ```
46 | From: Paris, France
47 | To: Marseille, France
48 | ```
49 |
50 | #### Request link
51 | http://xxx-xxx.herokuapp.com/distance/Paris,France/Marseille,France
52 | (replace xxx-xxx by your Heroku app name)
53 |
54 | #### Response
55 | {“distance”:”775 km”}
56 |
57 | ## About me 🤓
58 | Senior Supply Chain Engineer with an international experience working on Logistics and Transportation operations. \
59 | Have a look at my portfolio: [Data Science for Supply Chain Portfolio](https://samirsaci.com) \
60 | For **consulting or advising** on analytics and sustainable supply chain transformation, feel free to contact me via [Logigreen Consulting](https://www.logi-green.com/) \
61 | Data Science for Warehousing📦, Transportation 🚚 and Demand Forecasting 📈
62 |
--------------------------------------------------------------------------------
/Variables Heroku.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samirsaci/geocoding-api/fbf9adcacba2ed403ff44fc7d46aaa9f34f7c228/Variables Heroku.png
--------------------------------------------------------------------------------
/app.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | from flask import Flask, render_template, request, redirect
4 | from selenium import webdriver
5 | from bs4 import BeautifulSoup as soup
6 |
7 | # Chromedrive setting
8 | chrome_options = webdriver.ChromeOptions()
9 | chrome_options.add_argument("--headless")
10 | chrome_options.add_argument("--disable-dev-shm-usage")
11 | chrome_options.add_argument("--no-sandbox")
12 | chrome_options.binary_location = os.environ.get("GOOGLE_CHROME_BIN")
13 | driver = webdriver.Chrome(executable_path=os.environ.get("CHROMEDRIVER_PATH"), chrome_options=chrome_options)
14 |
15 | # Link
16 | fr = 'Paris, France'
17 | to = 'Marseille, France'
18 |
19 | app = Flask(__name__)
20 |
21 | def from_to(fr, to):
22 | # url
23 | url = 'https://www.google.fr/maps/dir/{}/{}/data=!4m2!4m1!3e0'.format(fr, to)
24 | print("link: {}".format(url))
25 | # Driver get
26 | driver.get(url)
27 | time.sleep(1)
28 | # Soupify
29 | page_soup = soup(driver.page_source, "html.parser")
30 | # Extract
31 | css_dist = "div[class^='section-directions-trip-distance'] > div"
32 | css_dura = "div[class^='section-directions-trip-duration']"
33 |
34 | try:
35 | distance = page_soup.select_one(css_dist).text
36 | duration = page_soup.select_one(css_dura).text
37 | except Exception as e:
38 | print(e)
39 | distance = 'Error'
40 | duration = 'Error'
41 | print("{} to {}: {}".format(fr, to, distance))
42 | result = {
43 | "distance": distance
44 | # "distance": distance,
45 | # "duration": duration
46 | }
47 |
48 | return result
49 |
50 | # Routing do define url
51 | @app.route('/')
52 | def index():
53 | return render_template('index.html')
54 |
55 | @app.route('/distance//', methods=['GET', 'POST'])
56 | def distance(fr, to):
57 | #returns the post, the post_id should be an int
58 | result = from_to(fr, to)
59 | return result
60 |
61 |
62 | if __name__ == '__main__':
63 | # Threaded option to enable multiple instances for multiple user access support
64 | app.run(debug=True, port=5000)
--------------------------------------------------------------------------------
/instructions.txt:
--------------------------------------------------------------------------------
1 | # Step 1: Download the Buildpacks Necessary for the ChromeDriver
2 | # Buildpack 1: https://github.com/heroku/heroku-buildpack-google-chrome
3 | # Buildpack 2: https://github.com/heroku/heroku-buildpack-chromedriver
4 | # Step 2: Add the PATH variable to the Heroku configuration
5 | # heroku config:set GOOGLE_CHROME_BIN=/app/.apt/usr/bin/google_chrome
6 | # heroku config:set CHROMEDRIVER_PATH=/app/.chromedriver/bin/chromedriver
7 | # heroku ps:scale worker=0
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samirsaci/geocoding-api/fbf9adcacba2ed403ff44fc7d46aaa9f34f7c228/requirements.txt
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.7.10
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Your Google API (Free :))
9 |
10 |
11 |
--------------------------------------------------------------------------------