How to webscrap leaflet mapas de polígonos usando Selenium e Python
Esta postagem é bastante semelhante a esta: Usando selênio e python para extrair dados quando eles aparecem após passar o mouse
Mas não consegui encontrar a resposta que procurava.
Estou tentando fazer um webcrap com um mapa de folheto muito semelhante a este: https://leafletjs.com/examples/choropleth/, de preferência, gostaria de baixar todas as informações que aparecem depois de mover o mouse sobre os polígonos:
Post original em loop sobre cada elemento do círculo, gostaria de fazer o mesmo em cada polígono.
Testes de código:
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Chrome
driver.get("https://leafletjs.com/examples/choropleth/")
timeout = 1000
explicit_wait30 = WebDriverWait(driver, 30)
try:
# Wait for all circles to load
poli = explicit_wait30.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.leaflet-interactive')))
except TimeoutException:
driver.refresh()
data = []
i=1
for circle in poli:
i+=1
# Execute mouseover on the element
driver.execute_script("const mouseoverEvent = new Event('mouseover');arguments[0].dispatchEvent(mouseoverEvent)", poli)
# Wait for the data to appear
listing = explicit_wait30.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#listingHover')))
data.append(listing.text)
# Close the listing
driver.execute_script("arguments[0].click()", listing.find_element_by_tag_name('button'))
print(i)
if i>15 :
break
Eu recebo o erro:
JavascriptException: Message: javascript error: arguments[0].dispatchEvent is not a function
(Session info: chrome=85.0.4183.102)
Parece que os elementos "interativos com o folheto" não têm eventos do tipo mouse over. Como posso reproduzir a ação humana de mover o mouse sobre os polígonos?
Respostas
Para quebrar o mapa do folheto e extrair todas as informações que aparecem depois de mover o mouse sobre os polígonos, já que os elementos desejados estão dentro de um <iframe>, você deve:
Induza o WebDriverWait para que o quadro desejado esteja disponível e mude para ele .
Induza WebDriverWait para o desejado visibility_of_element_located .
Você pode usar as seguintes estratégias de localizador :
driver.get('https://leafletjs.com/examples/choropleth/') driver.execute_script("return arguments[0].scrollIntoView(true);", WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//h2[text()='Interactive Choropleth Map']")))) WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[src='example.html']"))) elements = driver.find_elements_by_css_selector("svg.leaflet-zoom-animated>g path") for element in elements: ActionChains(driver).move_to_element(element).perform() print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//div[@class='info leaflet-control']"))).text)Nota : Você deve adicionar as seguintes importações:
from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as ECSaída do console:
US Population Density Alabama 94.65 people / mi2 US Population Density Hover over a state US Population Density Arizona 57.05 people / mi2 US Population Density Arkansas 56.43 people / mi2 US Population Density California 241.7 people / mi2 US Population Density Colorado 49.33 people / mi2 US Population Density Connecticut 739.1 people / mi2 US Population Density Delaware 464.3 people / mi2 US Population Density Maryland 596.3 people / mi2 US Population Density Hover over a state US Population Density Georgia 169.5 people / mi2 US Population Density Hover over a state US Population Density Montana 6.858 people / mi2 US Population Density Illinois 231.5 people / mi2 US Population Density Indiana 181.7 people / mi2 US Population Density Iowa 54.81 people / mi2 US Population Density Kansas 35.09 people / mi2 US Population Density Kentucky 110 people / mi2 US Population Density Mississippi 63.5 people / mi2 US Population Density Maine 43.04 people / mi2 US Population Density Virginia 204.5 people / mi2 US Population Density Massachusetts 840.2 people / mi2 US Population Density
Referência
Você pode encontrar algumas discussões relevantes em:
- Maneiras de lidar com #document sob iframe
- Mude para um iframe por meio de Selenium e python
Em vez de torná-la uma execução lenta, demorada e demorada, basta pegar a url onde todos os dados estão disponíveis e analisá-la.
Url = 'https://leafletjs.com/examples/choropleth/us-states.js'
response = requests.get(Url)
json_data = json.loads(response.text.split("=")[1].replace(';',''))
prop = jsonpath.jsonpath(json_data,"$.features[*].properties")
print(prop)
Importações necessárias -
import requests
import json
import jsonpath
Resultado:-
[{'name': 'Alabama', 'density': 94.65}, {'name': 'Alaska', 'density': 1.264}, {'name': 'Arizona', 'density': 57.05}, {'name': 'Arkansas', 'density': 56.43}, {'name': 'California', 'density': 241.7}, {'name': 'Colorado', 'density': 49.33}, {'name': 'Connecticut', 'density': 739.1}, {'name': 'Delaware', 'density': 464.3}, {'name': 'District of Columbia', 'density': 10065}, {'name': 'Florida', 'density': 353.4}, {'name': 'Georgia', 'density': 169.5}, {'name': 'Hawaii', 'density': 214.1}, {'name': 'Idaho', 'density': 19.15}, {'name': 'Illinois', 'density': 231.5}, {'name':
'Indiana', 'density': 181.7}, {'name': 'Iowa', 'density': 54.81}, {'name': 'Kansas', 'density': 35.09}, {'name': 'Kentucky', 'density': 110}, {'name': 'Louisiana', 'density': 105}, {'name': 'Maine', 'density': 43.04}, {'name': 'Maryland', 'density': 596.3}, {'name': 'Massachusetts', 'density': 840.2}, {'name': 'Michigan', 'density': 173.9}, {'name': 'Minnesota', 'density': 67.14}, {'name': 'Mississippi', 'density': 63.5}, {'name': 'Missouri', 'density': 87.26}, {'name': 'Montana', 'density': 6.858}, {'name': 'Nebraska', 'density': 23.97}, {'name': 'Nevada', 'density': 24.8}, {'name': 'New Hampshire', 'density': 147}, {'name': 'New Jersey', 'density': 1189}, {'name': 'New Mexico', 'density': 17.16}, {'name': 'New York', 'density': 412.3}, {'name': 'North Carolina', 'density': 198.2}, {'name': 'North Dakota', 'density': 9.916}, {'name': 'Ohio', 'density': 281.9}, {'name': 'Oklahoma', 'density': 55.22}, {'name': 'Oregon', 'density': 40.33}, {'name': 'Pennsylvania', 'density': 284.3}, {'name': 'Rhode Island', 'density': 1006}, {'name': 'South Carolina', 'density': 155.4}, {'name': 'South Dakota', 'density': 98.07}, {'name': 'Tennessee', 'density': 88.08}, {'name': 'Texas', 'density': 98.07}, {'name': 'Utah', 'density': 34.3}, {'name': 'Vermont', 'density': 67.73}, {'name': 'Virginia', 'density': 204.5}, {'name': 'Washington', 'density': 102.6}, {'name': 'West Virginia', 'density': 77.06}, {'name': 'Wisconsin', 'density': 105.2}, {'name': 'Wyoming', 'density': 5.851}, {'name': 'Puerto Rico', 'density': 1082}]