Grab.com’s restaurant listings depend on search keywords (such as “chicken” or “noodles”). You need to send this search keyword as a URL parameter to get the search results. When web scraping Grab.com, you can use a headless browser to easily extract the necessary data points once you reach the search results page.
Want to know how? Read on—this article shows how to scrape Grab.com with Selenium. However, if you don’t want to code yourself, check out ScrapeHero’s Q-commerce scraping service.
Why worry about expensive infrastructure, resource allocation and complex websites when ScrapeHero can scrape for you at a fraction of the cost?Go the hassle-free route with ScrapeHero
How Do You Set Up the Environment for Web Scraping Grab.com?
To set up the environment to scrape Grab.com, install Selenium with pip:
pip install selenium
This Grab.com scraper also uses:
- time.sleep
- json
These modules come pre-installed with Python, so you don’t have to do anything extra.
What Data Does the Code Scrape from Grab.com?
The script extracts seven key details from each restaurant listing:
- Restaurant Name
- Cusine Categories
- Rating
- Distance
- Delivery Time
- URL
Dishes Served
How Do You Write the Code to Scrape Grab.com?
The code for web scraping Grab.com:
- Prompts the user to enter a search term.
- Opens Grab.com’s search page with those parameters.
- Scrolls down multiple times to load more results.
- Extracts restaurant details from the page, including URLs
- Opens each extracted URL and extracts the dishes served
- Saves the results in a JSON file.
Here are the necessary imports for web scraping Grab.com:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from time import sleep
import json
The code imports:
- webdriver from Selenium to control the browser
- By to specify the selector type, such as tag name, class, XPath, etc.
- Keys to send keyboard inputs like pressing the End key
- sleep from time to execute delays between actions, giving time for the elements to load
- json to save the extracted data in a JSON file
Now, prompt the user to enter the search term.
search_term = input("What do you want to eat?")
This search term is used as a URL parameter for Grab’s restaurant listings page.
How Do You Open Grab.com’s Restaurant Listings Page?
To open the restaurant listings page, first, launch the Selenium browser.
browser = webdriver.Chrome()
Here, the webdriver module launches a Chrome browser, but you can also use other available browsers, such as Firefox and Safari.
Next, navigate to Grab.com’s search results page.
Grab.com’s listings are accessible via a URL pattern. Figure out the pattern from the address bar of the search results page.
Then, use the get() method.
browser.get(f'https://food.Grab.com/sg/en/restaurants?lng=en&search={search_term}')
Doing this will open Grab.com’s search results page. However, since Grab.com uses lazy loading, you need to scroll to get more results.
How Do You Scroll to Load More Results?
To scroll, you can simulate END keypresses several times:
for _ in range(5):
browser.find_element(By.TAG_NAME, 'body').send_keys(Keys.END)
sleep(2)
This code uses the send_keys() method to simulate five END keypresses, scrolling the page down five times.
How Do You Scrape Grab’s Website for Restaurant Details?
Each restaurant on the search results page resides within a div that has the class “RestaurantListCol”.
Extract these div elements using find_elements().
dishes = browser.find_elements(By.XPATH,'//div[contains(@class,"RestaurantListCol")]')
The function find_elements() returns a list. Iterate through this list to extract the details of each restaurant.
extracted_data = []
for dish in dishes:
anchor_tag = dish.find_element(By.TAG_NAME, ‘a’)
url = anchor_tag.get_attribute(‘href’)
details = dish.text.split('\n')
n = 0 if ‘Promo’ in details else -1
data = {
'name': details[1],
'categories': details[2],
'rating': details[3],
'distance': details[4].split('•')[1],
'delivery_time': details[4].split('•')[0],
‘url’:url
}
extracted_data.append(data)
browser.quit()
This code uses a loop to perform these actions in each iteration:
- Retrieves the URL from the anchor tag
- Extracts the text and splits it at each newline character, returning it in an array
- Checks if the text has the string “Promo” to adjust the indices when retrieving details from the array
- Stores the details in a dictionary
- Appends the dictionary to a list called extracted_data
How Do You Extract the Dishes Served from Each Restaurant Page?
The extracted data variable contains details about restaurants, including the URLs. You can now use these URLs to navigate to each restaurant’s page and extract the dishes served that correspond to your search term.
To achieve this, first, create a function called “get_dish_details().” This function should:
1. Accept a URL and the search term as parameters
2. Navigate to the specified URL
3. Extract the div elements that have “menuItemInfo” in their class name
4. Loop through the elements to:
-
- Retrieve their text content
- Split the text content at every newline character, returning an array
- Extract the relevant details using the appropriate indices
- Store the details in a dictionary
- Append the dictionary to a list
Finally, the function should return the list of dish details.
def get_dish_details(url,search_term):
restaurant_browser =webdriver.Chrome()
restaurant_browser.get(url)
offers = restaurant_browser.find_elements(By.XPATH,"//div[contains(@class,'menuItemInfo')]")
dish_details =[]
for offer in offers:
if search_term.lower() in offer.text.lower():
details = offer.text.split('\n')
if len(details) == 5:
dish_details.append(
{
"Name": details[0] ,
"Description": details[1] ,
"Original Price": '$'+details[3] ,
"Current Price": '$'+details[4],
"Discount": '$'+details[2].split('$')[1]
}
)
if len(details) == 3:
dish_details.append(
{
"Name": details[0],
"Description": details[1],
"Price": "$" + details[2],
}
)
if len(details) == 2:
dish_details.append(
{
"Name": details[0],
"Price": "$" + details[1],
}
)
restaurant_browser.quit()
print(dish_details)
return dish_details
Note: The code checks the length of the array returned by split() since not every dish item includes an offer and a description.
Next, loop through the extracted_data variable, which contains the restaurant details as dictionaries. And in each iteration, call get_dish_details() and store the returned value as another item within the dictionary.
for data in extracted_data:
print(data['url'])
data['dishes'] = get_dish_details(data['url'],search_term)
sleep(3)
How Do You Save the Results?
Finally, dump the extracted details into a JSON file:
with open(f'Grab.com_{search_term}.json', 'w', encoding='utf-8') as f:
json.dump(extracted_data, f, ensure_ascii=False, indent=4)
This creates a file named after your search term, for example, Grab.com_noodles.json, with structured results like:
{
"name": "LiXin Teochew Fishball Noodles - Lau Pa Sat",
"categories": "Noodles, Chinese, Local & Malaysian",
"rating": "4.1",
"distance": " 2.5 km",
"delivery_time": "50 mins ",
"url": "https://food.Grab.com/sg/en/restaurant/lixin-teochew-fishball-noodles-lau-pa-sat-delivery/4-C4LKWEUHDBJHAA?",
"dishes": [
{
"Name": "Fishball Noodles (Dry) 鱼圆面 (干)",
"Description": "Our fishballs are made using pure yellowtail fish, containing no preservatives fillers or surimi, giving it that unmistakable firmness and bounce that is synonymous with Li Xin",
"Price": "$8.20"
},
{
"Name": "Fishball Minced Meat Noodles (Dry) 鱼圆肉脞面(干)",
"Price": "$9.80"
},
{
"Name": "Fishball Noodles + Fish Sticks 鱼圆面+炸鱼条",
"Price": "$13.20"
},
{
"Name": "Signature Noodles (Dry) 招牌面(干)",
"Description": "A combination of all the favourites - fishballs, fish dumplings and fish cake with your choice of noodles",
"Price": "$10.70"
},
{
"Name": "Fishball Noodles (Soup) 鱼圆面 (汤)",
"Description": "Our fishballs are made using pure yellowtail fish, containing no preservatives fillers or surimi, giving it that unmistakable firmness and bounce that is synonymous with Li Xin",
"Price": "$8.20"
}
]
}
Here’s the complete code for Grab.com data scraping.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from time import sleep
import json
def get_dish_details(url,search_term):
restaurant_browser =webdriver.Chrome()
restaurant_browser.get(url)
offers = restaurant_browser.find_elements(By.XPATH,"//div[contains(@class,'menuItemInfo')]")
dish_details =[]
for offer in offers[:5]:
if search_term.lower() in offer.text.lower():
details = offer.text.split('\n')
if len(details) == 5:
dish_details.append(
{
"Name": details[0] ,
"Description": details[1] ,
"Original Price": '$'+details[3] ,
"Current Price": '$'+details[4],
"Discount": '$'+details[2].split('$')[1]
}
)
if len(details) == 3:
dish_details.append(
{
"Name": details[0],
"Description": details[1],
"Price": "$" + details[2],
}
)
if len(details) == 2:
dish_details.append(
{
"Name": details[0],
"Price": "$" + details[1],
}
)
restaurant_browser.quit()
print(dish_details)
return dish_details
search_term = input("What do you want to eat?")
browser = webdriver.Chrome()
browser.get(f'https://food.grab.com/sg/en/restaurants?lng=en&search={search_term}')
sleep(3)
for _ in range(5):
browser.find_element(By.TAG_NAME, 'body').send_keys(Keys.END)
sleep(2)
dishes = browser.find_elements(By.XPATH,'//div[contains(@class,"RestaurantListCol")]')
extracted_data = []
for dish in dishes[:3]:
details = dish.text.split('\n')
anchor_tag = dish.find_element(By.TAG_NAME,'a')
url = anchor_tag.get_attribute('href')
n = 0 if 'Promo' in details else -1
data = {
'name': details[n+1],
'categories': details[n+2],
'rating': details[n+3],
'distance': details[n+4].split('•')[1],
'delivery_time': details[n+4].split('•')[0],
'url':url
}
extracted_data.append(data)
browser.quit()
for data in extracted_data:
print(data['url'])
data['dishes'] = get_dish_details(data['url'],search_term)
sleep(3)
with open(f'Grab.com_{search_term}.json', 'w', encoding='utf-8') as f:
json.dump(extracted_data, f, ensure_ascii=False, indent=4)
What Are the Limitations of This Grab.com Scraper?
Although you perform Grab web scraping using the code shown in this tutorial, beware of the limitations:
- The scraper depends on fixed XPaths and text structures. Any change to Grab.com’s HTML layout will require adjustments to keep it working.
- Slow connections or incomplete scrolling may prevent all results from appearing before extraction.
- Grab can deploy CAPTCHA or block requests if it detects heavy scraping, and this script has no safeguards for bypassing anti-scraping measures.
- The code searches for the exact search term in the dish names, meaning it will ignore the variations in spellings by restaurants.
When Should You Use a Web Scraping Service?
This Selenium script works effectively to Grab data extraction on a small scale. If you just want to experiment, the script offers a straightforward way to interact with Grab.com’s interface.
However, for large-scale projects—such as collecting thousands of records, updating them frequently, or covering multiple regions—issues with speed, dynamic loading, and anti-bot measures can become a recurring burden. In such cases, a web scraping service can be the smart choice.
A web scraping service like ScrapeHero can manage scaling, IP rotation, and evolving site structures so you don’t have to spend time fixing or rebuilding scripts.
ScrapeHero is an enterprise-grade web scraping service designed to handle these larger challenges. By using ScrapeHero’s services, your team can save significant time and effort, focusing instead on analyzing high-quality data and turning it into actionable insights.