Итак, я проверил эту страницу несколько раз, и она кажется довольно устойчивой к собственным методам селена, поэтому нам придется полагаться на javascript. Вот полный код:
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver import ActionChains
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
browser = webdriver.Chrome(options=chrome_options, executable_path='chromedriver.exe')
browser.get('http://insideairbnb.com/melbourne/')
browser.maximize_window()
# Set up a 30 seconds webdriver wait
explicit_wait30 = WebDriverWait(browser, 30)
try:
# Wait for all circles to load
circles = explicit_wait30.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'svg.leaflet-zoom-animated > g:nth-child(2) > circle')))
except TimeoutException:
browser.refresh()
data = []
for circle in circles:
# Execute mouseover on the element
browser.execute_script("const mouseoverEvent = new Event('mouseover');arguments[0].dispatchEvent(mouseoverEvent)", circle)
# Wait for the data to appear
listing = explicit_wait30.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#listingHover')))
# listing now contains the full element list - you can parse this yourself and add the necessary data to `data`
.......
# Close the listing
browser.execute_script("arguments[0].click()", listing.find_element_by_tag_name('button'))
Я также использую селекторы css вместо XPATH. Вот как работает поток:
circles = explicit_wait30.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'svg.leaflet-zoom-animated > g:nth-child(2) > circle')))
Он ожидает, пока все круги будут присутствовать, и извлекает их в circles
.
Имейте в виду, что страница очень медленно загружает круги, поэтому я установил блок try/except
для автоматического обновления sh страницы, если она не загружается в течение 30 секунд. Не стесняйтесь изменять это, как хотите.
Теперь нам нужно пройти l oop по всем кругам -
for circle in circles:
Далее имитируется событие mouseover
на круге, мы ' Я буду использовать javascript для этого
Вот как будет выглядеть javascript (обратите внимание, что circle
относится к элементу, который мы передадим из селена)
const mouseoverEvent = new Event('mouseover');
circle.dispatchEvent(mouseoverEvent)
Вот как скрипт выполняется через селен -
browser.execute_script("const mouseoverEvent = new Event('mouseover');arguments[0].dispatchEvent(mouseoverEvent)", circle)
Теперь нам нужно дождаться появления списка-
listing = explicit_wait30.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#listingHover')))
Теперь у вас listing
, элемент, который также содержит много других элементов, теперь вы можете легко извлечь каждый элемент, как хотите, и сохранить их внутри data
.
Если вы не заботитесь об извлечении каждого элемента по-разному, просто выполните .text
on listing
приведет к примерно такому результату -
'Tanya\n(No other listings)\n23127829\nSerene room for a single person or a couple.\nGreater Dandenong\nPrivate room\n$37 income/month (est.)\n$46 /night\n4 night minimum\n10 nights/year (est.)\n2.7% occupancy rate (est.)\n0.1 reviews/month\n1 reviews\nlast: 20/02/2018\nLOW availability\n0 days/year (0%)\nclick listing on map to "pin" details'
Вот и все, затем вы можете добавить результат в data
, и все готово!