Google places API allows developers to access a wealth of information from Google’s database for over 100 million places including location data, contact information, user ratings and reviews and more.
In this tutorial, you will learn how to create a reusable class to read and extract location related information from Google Places API. This tutorial will help you if you want to extract business’s name, address, phone number, website, and reviews.
How to Get an API key
1- Login to your Google Cloud Console
2- From top navigation bar click “Select a project”
3- In the new window click “New project”
4- Type a name for your project and click on “Create”
5- From left side navigation go to “APIs & Services > Library”
6- From Maps section select “Places API” or search for “Places API” in the search box.
8- Go to Credentials tab
9- Click on “Create Credentials”
10- Click on “API Key”
11- Copy your generated API Key and store it somewhere.
Congratulations! You’ve got your Google Places API key successfully. Now let’s get started with coding.
Dummy Class Object
Let’s create a class which does nothing for now. You will pass your API key in the class constructor and set the apiKey attribute so you can access it later easily. We will complete our class step by step.
1 2 3 4 5 6 7 8 |
import requests import json class GooglePlaces(object): def __init__(self, apiKey): super(GooglePlaces, self).__init__() self.apiKey = apiKey |
Search for Places
To get place details, you need to search for places and get the place IDs first. Fortunately there is an API endpoint for this.
With this endpoint you will send a GPS Coordinate and a radius to the API and it will return the nearby places by your defined radius. Also there is a filter called types which can filter out only the types of the places that you are interested in. Like school or restaurant .
Note: Here is a list of all valid types:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
accounting airport amusement_park aquarium art_gallery atm bakery bank bar beauty_salon bicycle_store book_store bowling_alley bus_station cafe campground car_dealer car_rental car_repair car_wash casino cemetery church city_hall clothing_store convenience_store courthouse dentist department_store doctor electrician electronics_store embassy fire_station florist funeral_home furniture_store gas_station gym hair_care hardware_store hindu_temple home_goods_store hospital insurance_agency jewelry_store laundry lawyer library liquor_store local_government_office locksmith lodging meal_delivery meal_takeaway mosque movie_rental movie_theater moving_company museum night_club painter park parking pet_store pharmacy physiotherapist plumber police post_office real_estate_agency restaurant roofing_contractor rv_park school shoe_store shopping_mall spa stadium storage store subway_station supermarket synagogue taxi_stand train_station transit_station travel_agency veterinary_care zoo |
Lets add this search function to our class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class GooglePlaces(object): def __init__(self, apiKey): super(GooglePlaces, self).__init__() self.apiKey = apiKey def search_places_by_coordinate(self, location, radius, types): endpoint_url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json" params = { 'location': location, 'radius': radius, 'types': types, 'key': self.apiKey } res = requests.get(endpoint_url, params = params) results = json.loads(res.content) return results |
Note: Google places API can return the results in JSON or XML format. We will be using JSON format in this tutorial.
As you can see we are sending 4 parameters to the api and get back our json result. Then load it in a Python dictionary using json.loads function.
But still there is something missing in our function. Each search can return maximum 60 results and there will be 20 results per page. So you will need to paginate through the results if there is more that 20 results in your search.
If there is more pages the api will return next_page_token with the results and you have to submit this value to the api with the same search parameters to get the rest of the results.
Note: There is a delay until the next_page_token is issued and validated. So you need to put a small sleep time like 2 seconds between each request. Otherwise, you will get an INVALID_REQUEST status.
So let’s add pagination to our function. At the beginning we are creating an empty list for the found places and extending it with results from the search API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import requests import json import time class GooglePlaces(object): def __init__(self, apiKey): super(GooglePlaces, self).__init__() self.apiKey = apiKey def search_places_by_coordinate(self, location, radius, types): endpoint_url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json" places = [] params = { 'location': location, 'radius': radius, 'types': types, 'key': self.apiKey } res = requests.get(endpoint_url, params = params) results = json.loads(res.content) places.extend(results['results']) time.sleep(2) while "next_page_token" in results: params['pagetoken'] = results['next_page_token'], res = requests.get(endpoint_url, params = params) results = json.loads(res.content) places.extend(results['results']) time.sleep(2) return places |
Now our function with return a list containing the search results (Max 60 places) but still we don’t have all the details like user reviews.
Place Details
To get the complete details we have to use another API endpoint. So let’s create another function to get the place details.
Again we have to submit some parameters to the place details API to get the results. Some parameters are required some while others are optional.
Required parameters:
key : your API key.
placeid : An identifier that uniquely identifies a place, returned from the Place Search.
Optional parameters:
language : The language code, indicating in which language the results should be returned. See the list of supported languages and their codes (default is EN).
fields : One or more fields, specifying the types of place data to return, separated by a comma.
There is 3 categories for the fields parameter.
Basic: address_component, adr_address, alt_id, formatted_address, geometry, icon, id, name, permanently_closed, photo, place_id, plus_code, scope, type, url, utc_offset, vicinity
Contact: formatted_phone_number, international_phone_number, opening_hours, website
Atmosphere: price_level, rating, review
So let’s create our function to get the place details.
It’s going to be very similar to our first function. We just need to use different URL and parameters.
This is how this function looks like.
1 2 3 4 5 6 7 8 9 10 11 |
def get_place_details(self, place_id, fields): endpoint_url = "https://maps.googleapis.com/maps/api/place/details/json" params = { 'placeid': place_id, 'fields': ",".join(fields), 'key': self.apiKey } res = requests.get(endpoint_url, params = params) place_details = json.loads(res.content) return place_details |
Note: This function expects the fields parameter to be a list of strings (Valid fields string from above) then in convert the list to a comma separated string using ",".join(fields)
So here is our complete class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import requests import json import time class GooglePlaces(object): def __init__(self, apiKey): super(GooglePlaces, self).__init__() self.apiKey = apiKey def search_places_by_coordinate(self, location, radius, types): endpoint_url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json" places = [] params = { 'location': location, 'radius': radius, 'types': types, 'key': self.apiKey } res = requests.get(endpoint_url, params = params) results = json.loads(res.content) places.extend(results['results']) time.sleep(2) while "next_page_token" in results: params['pagetoken'] = results['next_page_token'], res = requests.get(endpoint_url, params = params) results = json.loads(res.content) places.extend(results['results']) time.sleep(2) return places def get_place_details(self, place_id, fields): endpoint_url = "https://maps.googleapis.com/maps/api/place/details/json" params = { 'placeid': place_id, 'fields': ",".join(fields), 'key': self.apiKey } res = requests.get(endpoint_url, params = params) place_details = json.loads(res.content) return place_details |
Now let’s use this class to retrieve some real information.
Example: Getting User Reviews for a Place Using GooglePlaces Class
In this example, you will see how to retrieve some information about places including place name, user reviews and ratings, address, phone number and website.
First you need to search for places as stated before. So go to maps.google.com and search for the area you are interested in. Then click anywhere on the map and a small box will show up in the bottom of the page.
Copy the GPS coordinates. We will use it to search the area.
We have everything we need now. Let’s write some code.
Initialize GooglePlaces class with your API key.
1 2 |
api = GooglePlaces("Your API key") |
Search the and store the results in a list.
1 2 |
places = api.search_places_by_coordinate("40.819057,-73.914048", "100", "restaurant") |
Note: This will return nearby restaurant up to 100 meters away and maximum of 60 places.
Now places variable contains our search results. Every place has a place_id and we will use the place identifier to retrieve more details about it.
Let’s define the fields which we want to retrieve.
fields = ['name', 'formatted_address', 'international_phone_number', 'website', 'rating', 'review']
And finally retrieve the details.
1 2 3 |
for place in places: details = api.get_place_details(place['place_id'], fields) |
You have all the details in details dictionary now. Here I’m just going to print the details but you can store it in CSV or Excel file or even a database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
for place in places: details = api.get_place_details(place['place_id'], fields) try: website = details['result']['website'] except KeyError: website = "" try: name = details['result']['name'] except KeyError: name = "" try: address = details['result']['formatted_address'] except KeyError: address = "" try: phone_number = details['result']['international_phone_number'] except KeyError: phone_number = "" try: reviews = details['result']['reviews'] except KeyError: reviews = [] print("===================PLACE===================") print("Name:", name) print("Website:", website) print("Address:", address) print("Phone Number", phone_number) print("==================REVIEWS==================") for review in reviews: author_name = review['author_name'] rating = review['rating'] text = review['text'] time = review['relative_time_description'] profile_photo = review['profile_photo_url'] print("Author Name:", author_name) print("Rating:", rating) print("Text:", text) print("Time:", time) print("Profile photo:", profile_photo) print("-----------------------------------------") |
If you run this code in your terminal, it will print something like the image below. I have added some separators so it’ easier to read.
As you can see in the image all the info we requested is printed on the the screen so you can process them easily.
Note: some variable ( website,name, addrees, phone_number ) are wrapped inside a try/except block just in case if the API doesn’t return those info.
Limitations
Number of Reviews
Currently, the Google Places API returns only 5 last reviews.
Being able to retrieve all the reviews for a given business is only supported if you are a verified business owner and can be done via the Google My Business API: https://developers.google.com/my-business/
Number & Type of Requests
Using Google Places API for free, you can only send up to 100,000 requests per month, and retrieve “Basic Data”.
The Basic Data SKU is triggered when any of these fields are requested: address_component
, adr_address
, formatted_address
, geometry
, icon, name
, permanently_closed
, photo, place_id
, plus_code
, type
, url
, utc_offset
, vicinity
.
On the other hand, there are request types that are paid from the first request. You can check rate limits and pricing details here: https://developers.google.com/places/web-service/usage-and-billing
Completed Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
import requests import json import time class GooglePlaces(object): def __init__(self, apiKey): super(GooglePlaces, self).__init__() self.apiKey = apiKey def search_places_by_coordinate(self, location, radius, types): endpoint_url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json" places = [] params = { 'location': location, 'radius': radius, 'types': types, 'key': self.apiKey } res = requests.get(endpoint_url, params = params) results = json.loads(res.content) places.extend(results['results']) time.sleep(2) while "next_page_token" in results: params['pagetoken'] = results['next_page_token'], res = requests.get(endpoint_url, params = params) results = json.loads(res.content) places.extend(results['results']) time.sleep(2) return places def get_place_details(self, place_id, fields): endpoint_url = "https://maps.googleapis.com/maps/api/place/details/json" params = { 'placeid': place_id, 'fields': ",".join(fields), 'key': self.apiKey } res = requests.get(endpoint_url, params = params) place_details = json.loads(res.content) return place_details if __name__ == '__main__': api = GooglePlaces("Your API key") places = api.search_places_by_coordinate("40.819057,-73.914048", "100", "restaurant") fields = ['name', 'formatted_address', 'international_phone_number', 'website', 'rating', 'review'] for place in places: details = api.get_place_details(place['place_id'], fields) try: website = details['result']['website'] except KeyError: website = "" try: name = details['result']['name'] except KeyError: name = "" try: address = details['result']['formatted_address'] except KeyError: address = "" try: phone_number = details['result']['international_phone_number'] except KeyError: phone_number = "" try: reviews = details['result']['reviews'] except KeyError: reviews = [] print("===================PLACE===================") print("Name:", name) print("Website:", website) print("Address:", address) print("Phone Number", phone_number) print("==================REWIEVS==================") for review in reviews: author_name = review['author_name'] rating = review['rating'] text = review['text'] time = review['relative_time_description'] profile_photo = review['profile_photo_url'] print("Author Name:", author_name) print("Rating:", rating) print("Text:", text) print("Time:", time) print("Profile photo:", profile_photo) print("-----------------------------------------") |
I speak Python!
Majid Alizadeh is a freelance developer specialized in web development, web scraping and automation. He provides high quality and sophisticated software for his clients. Beside Python he works with other languages like Ruby, PHP and JS as well.
Thanks. I have 300 addresses in a dataframe. How we can handle them?
Hi Abbas! What do you want to do with these addresses? Generally speaking, you can check this question (read all the answers) to know how to iterate a dataframe.
Thanks a lot for sharing the knowledge. I have used your query but getting an error “SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1056)”. Any help would really be appreciated. Thanks!!
@soumi Try adding the
verify=False
to this line, as follows:requests.get(endpoint_url, params = params, verify=False)
I have a list of addresses that I would like to know the business name that is at each location.
@Jack What about “iterating” the list of addresses using a for loop?
hello
i have got empty places 🙁 i only change GooglePlaces(“AIzaSyCy-HpjsoOoQAbwbhGdhfE8wCwrtpvqj14”)
===================PLACE===================
(‘Name:’, ”)
(‘Website:’, ”)
(‘Address:’, ”)
(‘Phone Number’, ”)
==================REWIEVS==================
===================PLACE===================
(‘Name:’, ”)
(‘Website:’, ”)
(‘Address:’, ”)
(‘Phone Number’, ”)
==================REWIEVS==================
@leena Are you sure the code written/copied correctly and that you are using the latest versions of all the libraries?
hi,
how to store it in excel file ?
@leena You can use a Python library like Pandas or CSV to store data into a CSV file.
Traceback (most recent call last):
File “C:/Users/varsayemlak/AppData/Local/Programs/Python/Python37-32/asdad.py”, line 1, in
import requests
ModuleNotFoundError: No module named ‘requests’
@evisofis You must install the Python library “requests” beforehand.
I really need to get in contact with Majid. I need some help and am not asking for you to do it for free. Please contact me.
@Chase – Regarding the malicious Telegram group you found, you can simply “report” it to Telegram on their website, or send them an email at “abuse@telegram.org” and they can take the proper action. This has nothing to do with us or what we do here. All the best! -admin
thank you it is work now, but how to receive more than 5 reviews?
and is it possible to specify the language for the 5 reviews?