Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to click on signs on a map

I've written a script in Python in association with selenium to click on each of the signs available in a map. However, when I execute my script, it throws timeout exception error upon reaching this line wait.until(EC.staleness_of(item)).

Before hitting that line, the script should have clicked once but It could not? How can I click on all the signs in that map cyclically?

This is the site link.

This is my code so far (perhaps, I'm trying with the wrong selectors):

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

link = "https://www.findapetwash.com/"

driver = webdriver.Chrome()
driver.get(link)
wait = WebDriverWait(driver, 15)
for item in wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "#map .gm-style"))):
    item.click()
    wait.until(EC.staleness_of(item))
driver.quit()

Signs visible on that map like:

enter image description here

Post script: I know that this is their API https://www.findapetwash.com/api/locations/getAll/ using which I can get the JSON content but I would like to stick to the Selenium way. Thanks.

like image 931
SIM Avatar asked Sep 02 '18 05:09

SIM


2 Answers

You can click one by one using Selenium if, for some reasons, you cannot use API. Also it is possible to extract information for each sign without clicking on them with Selenium.

Here code to click one by one:

signs = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "li.marker.marker--list")))
for sign in signs:
     driver.execute_script("arguments[0].click();", sign)
     #do something

Try also without wait, probably will work.

like image 141
Sers Avatar answered Oct 19 '22 20:10

Sers


I know you wrote you don't want to use the API but using Selenium to get the locations from the map markers seems a bit overkill for this, instead, why not making a call to their Web service using requests and parse the returned json?

Here is a working script:

import requests
import json

api_url='https://www.findapetwash.com/api/locations/getAll/'

class Location:
    def __init__(self, json):
        self.id=json['id']
        self.user_id=json['user_id']
        self.name=json['name']
        self.address=json['address']
        self.zipcode=json['zipcode']
        self.lat=json['lat']
        self.lng=json['lng']
        self.price_range=json['price_range']
        self.photo='https://www.findapetwash.com' + json['photo']

def get_locations():
    locations = []
    response = requests.get(api_url)
    if response.ok:
        result_json = json.loads(response.text)
        for location_json in result_json['locations']:
            locations.append(Location(location_json))

        return locations
    else:
        print('Error loading locations')
        return False

if __name__ == '__main__':
    locations = get_locations()
    for l in locations:
        print(l.name)

Selenium

If you still want to go the Selenium way, instead of waiting until all the elements are loaded, you could just halt the script for some seconds or even a minute to make sure everything is loaded, this should fix the timeout exception:

import time 

driver.get(link)
# Wait 20 seconds
time.sleep(20)

For other possible workarounds, see the accepted answer here: Make Selenium wait 10 seconds

like image 21
Isma Avatar answered Oct 19 '22 19:10

Isma