如何使用 selenium python 在悬停的高图上抓取值?
How to scrape values on hovering highcharts using selenium python?
我正在尝试使用 Python 和 Selenium 从 https://www.similarweb.com/website/zalando.de/#overview 抓取数据。困难的部分是数据只有在图表上的一个点悬停时才会出现。
这是我的代码。
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 []
这有点棘手。但我注意到一些我认为会有所帮助的事情:信息出现在 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")
当站点显示动态图表时,它会从其数据库或外部 API 中检索基础数据。然后,服务器发送此数据,或使此数据可用于图形框架(d3js、highcharts...)(Json、xml、plain、csv)。有时,这些数据通过模板引擎集成到 HTML 中或硬写入 javascript 文件中。
经过一些调查,我们看到这里的数据存储在 html 末尾的脚本标记中(参见 F12 -> Inspector)。包含数据的变量是 preloadedData。它似乎包含了页面动画中使用的所有数据,包括您感兴趣的数据。
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:Selenium经常被误用,它是用来测试网页的,而不是用来检索数据的。然而,有时使用此工具更容易。
注2:我试过经典的requests+bs方法,比较复杂:包含数据的script标签是由另一个javascript生成的,它使用了rimbambelle of cookies。
注意 3:请注意,该站点检测到的请求很可能是非人为的(太快了)。考虑在你的 for 循环中放置一个 time.sleep(如果你循环多个 URL)。
我正在尝试使用 Python 和 Selenium 从 https://www.similarweb.com/website/zalando.de/#overview 抓取数据。困难的部分是数据只有在图表上的一个点悬停时才会出现。
这是我的代码。
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 []
这有点棘手。但我注意到一些我认为会有所帮助的事情:信息出现在 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")
当站点显示动态图表时,它会从其数据库或外部 API 中检索基础数据。然后,服务器发送此数据,或使此数据可用于图形框架(d3js、highcharts...)(Json、xml、plain、csv)。有时,这些数据通过模板引擎集成到 HTML 中或硬写入 javascript 文件中。
经过一些调查,我们看到这里的数据存储在 html 末尾的脚本标记中(参见 F12 -> Inspector)。包含数据的变量是 preloadedData。它似乎包含了页面动画中使用的所有数据,包括您感兴趣的数据。
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:Selenium经常被误用,它是用来测试网页的,而不是用来检索数据的。然而,有时使用此工具更容易。
注2:我试过经典的requests+bs方法,比较复杂:包含数据的script标签是由另一个javascript生成的,它使用了rimbambelle of cookies。
注意 3:请注意,该站点检测到的请求很可能是非人为的(太快了)。考虑在你的 for 循环中放置一个 time.sleep(如果你循环多个 URL)。