#python #selenium #web-scraping #hover
Вопрос:
Я пытаюсь соскрести данные с https://www.similarweb.com/website/zalando.de/#overview используя Python и Селен. Сложность заключается в том, что данные отображаются только при наведении курсора на точку на графике.
Вот мой код.
websites = ['https://www.similarweb.com/website/zalando.de/#overview']
options = webdriver.ChromeOptions()
options.add_argument('start-maximized')
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
browser = webdriver.Chrome(ChromeDriverManager().install(), options=options)
delays = [7, 4, 6, 2, 10, 19]
delay = np.random.choice(delays)
for crawler in websites:
browser.get(crawler)
time.sleep(2)
time.sleep(delay)
tooltip = browser.find_element(By.XPATH, "//*[local-name() = 'svg']/*[local-name()='g'][8]/*[local-name()='text']")
ActionChains(browser).move_to_element(tooltip).perform()
month_value = browser.find_element(By.XPATH, "//*[local-name() = 'svg']/*[local-name()='g' and @class='highcharts-tooltip']/*[local-name()='text']")
print('Are they here?', month_value.text)
months = browser.find_elements(By.XPATH, "//*[local-name() = 'svg']/*[local-name()='g'][6]/*/*")
for date in months:
print(date.text)
Я могу распечатать данные за месяцы в виде:
Nov '20
Dec '20
Jan '21
Feb '21
Mar '21
Apr '21
Но не удается распечатать значения каждого месяца — это дает пустой отпечаток-Они здесь?
Как мне убедиться, что он сначала завис, а затем очищен? Пожалуйста, помогите
ИЗМЕНИТЬ : Вот обновленный код
def website_monitoring():
websites = ['https://www.similarweb.com/website/zalando.de/#overview']
options = webdriver.ChromeOptions()
options.add_argument('start-maximized')
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
browser = webdriver.Chrome(ChromeDriverManager().install(), options=options)
for crawler in websites:
browser.get(crawler)
wait = WebDriverWait(browser, 10)
months = []
monthly_values = []
charts = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="highcharts-0"]')))
highchart = browser.find_elements_by_xpath('//*[@id="highcharts-0"]/svg/g[4]/g[1]')
for elements in highchart:
hover = ActionChains(browser).move_to_element(elements)
hover.perform()
month = browser.find_elements_by_css_selector('#highcharts-0 > svg > g.highcharts-tooltip > text > tspan:nth-child(1)')
month_values = browser.find_elements_by_css_selector('#highcharts-0 > svg > g.highcharts-tooltip > text > tspan:nth-child(3)')
months.append(month[0].text)
monthly_values.append(month_values[0].text)
print('Months', months)
print('Monthly Values', monthly_values)
if __name__ == "__main__":
website_monitoring()
Результат, который я получаю, таков:
Months []
Monthly Values []
Ответ №1:
Когда сайт отображает динамические диаграммы, он извлекает базовые данные из своих баз данных или из внешних API. Затем сервер отправляет эти данные или делает эти данные доступными (Json, xml, plain, csv) для графических фреймворков (d3js, highcharts…). Иногда эти данные интегрируются в HTML с помощью движков шаблонов или жестко записываются в файлы javascript.
После некоторого исследования мы видим, что здесь данные хранятся в теге сценария в конце html (см. F12 -> Инспектор). Переменная, содержащая данные, является предварительно загруженными данными. Похоже, он содержит все данные, используемые в анимации страницы, включая ту, которая вас интересует.
from selenium import webdriver
from bs4 import BeautifulSoup as bs
import time
import json
import re
driver = webdriver.Firefox()
driver.get("https://www.similarweb.com/website/zalando.de")
html = driver.page_source
soup = bs(html, "html.parser")
# get all scripts tags and select the one of interest
balises_script = soup.find_all("script")
target_balise = [str(el) for el in balises_script if "Sw.preloadedData" in str(el)][0]
# use regex to extract dict like string
m = re.findall(r"Sw.preloadedData = (. );", target_balise)[0]
# dict like string to dict
data = json.loads(m)
# explore data to see where data of interest is
sub_data_of_interest = data['overview']['EngagementsSimilarweb']['WeeklyTrafficNumbers']
for items in sub_data_of_interest.items():
print(items)
driver.close()
что приводит к :
('2020-11-01', 29914593)
('2020-12-01', 27141507)
('2021-01-01', 26863605)
('2021-02-01', 22589520)
('2021-03-01', 24745220)
('2021-04-01', 26249414)
Примечание 1: Селеном часто злоупотребляют, он предназначен для тестирования веб-страниц, а не для извлечения данных. Однако иногда использовать этот инструмент бывает проще.
Примечание 2: Я попробовал классический метод requests bs, он сложнее: тег скрипта, содержащий данные, генерируется другим javascript, использующим набор файлов cookie.
Примечание 3: Будьте осторожны, сайт обнаруживает запросы, которые, скорее всего, будут нечеловеческими (слишком быстро). Подумайте о том, чтобы включить time.sleep в свои циклы for (если вы зацикливаетесь на нескольких URL-адресах).
Ответ №2:
Это немного сложно. Но я заметил кое-что, что, я думаю, поможет: информация присутствует в DOM независимо от того, находится ли она на странице, и для нее есть уникальный css-селектор ('tspan:nth-child(3)')
. Дело в том, что это всего лишь один элемент, который динамически отображает значение при перемещении мыши. Поэтому, если вы определите, из каких точек вы хотите удалить значения, но вот быстрый способ распечатать только то значение, которое, по моему мнению, вам нужно:
for point in points_to_hover:
driver.find_element_by_css_selector('tspan:nth-child(3)').get_attribute("innerText")
Комментарии:
1. что именно такое «points_to_hover» в цикле «для»?
2. Массив определенных вами веб-элементов, состоящий из каждой точки, на которую вы хотите навести курсор.
3. о! подсказка.!! понял
4. в нем говорится, что элемент не found…it не работает
5. @technophile_3 можете ли вы опубликовать код с вашей последней попытки и полученное сообщение об ошибке?