从使用 Power BI 的网站抓取数据 - 从网站上的 Power BI 检索数据

Posted

技术标签:

【中文标题】从使用 Power BI 的网站抓取数据 - 从网站上的 Power BI 检索数据【英文标题】:Scraping Data from a website which uses Power BI - retrieving data from Power BI on a website 【发布时间】:2019-07-30 11:44:19 【问题描述】:

我想抓取此页面(以及类似页面)的数据:https://cereals.ahdb.org.uk/market-data-centre/historical-data/feed-ingredients.aspx

此页面使用Power BI。不幸的是,找到一种刮取 Power BI 的方法很难,因为每个人都想刮取 使用/进入 Power BI,而不是从中。最接近的答案是this question。然而无关。

首先,我使用Apache tika,加载页面后很快我意识到表格数据正在加载。我需要页面的渲染版本。

因此,我使用了Selenium。一开始我想Select All(发送Ctrl+A组合键),但它不起作用。可能是受页面事件限制(我也尝试使用开发者工具删除所有事件,但Ctrl+A 仍然不起作用。

我也尝试阅读 html 内容,但 Power BI 使用 position:absolutediv 元素放在屏幕上,并且区分 div 在表格中的位置(行和列)是一项费力的活动。

由于 Power BI 使用 JSON,我尝试从那里读取数据。但是它太复杂了,我找不到规则。似乎它将关键字放在某处并在表中使用它们的索引。

注意:我意识到所有数据都没有加载,甚至没有同时显示。 divscroll-bar-part-bar 负责充当滚动条,并移动它来加载/显示数据的其他部分。

我用来读取数据的代码如下。如前所述,生成数据的顺序与在浏览器上呈现的顺序不同:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

options = webdriver.ChromeOptions()
options.binary_location = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"
driver = webdriver.Chrome(options=options, executable_path="C:/Drivers/chromedriver.exe")

driver.get("https://app.powerbi.com/view?r=eyJrIjoiYjVjM2MyNjItZDE1Mi00OWI1LWE5YWYtODY4M2FhYjU4ZDU1IiwidCI6ImExMmNlNTRiLTNkM2QtNDM0Ni05NWVmLWZmMTNjYTVkZDQ3ZCJ9")
parent = driver.find_element_by_xpath('//*[@id="pvExplorationHost"]/div/div/div/div[2]/div/div[2]/div[2]/visual-container[4]/div/div[3]/visual/div')
children = parent.find_elements_by_xpath('.//*')
values = [child.get_attribute('title') for child in children]

我很欣赏上述任何问题的解决方案。不过,对我来说最有趣的是以 JSON 格式存储 Power BI 数据的约定。

【问题讨论】:

@user308827 老实说,您可能应该为赏金创建自己的问题,从地图上抓取似乎是一个不同的过程。或者,您可以通过网络请求手动获取地图数据 仅供参考,它是 scrape 不是废品 【参考方案1】:

更多关于您尝试抓取哪些数据的详细信息将有助于构建规范答案。但是,要使用 Selenium 在 CommodityBasis 中抓取数据,因为所需的元素在 <iframe> 内,因此您必须:

为所需的frame_to_be_available_and_switch_to_it() 引入 WebDriverWait

为表的所需 visibility_of_element_located() 引入 WebDriverWait

为所需的数据诱导 WebDriverWait 为所需的visibility_of_all_elements_located()

您可以使用以下Locator Strategies:

代码块:

     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

     options = webdriver.ChromeOptions() 
     options.add_argument("start-maximized")
     options.add_experimental_option("excludeSwitches", ["enable-automation"])
     options.add_experimental_option('useAutomationExtension', False)
     driver = webdriver.Chrome(options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
     driver.get("https://ahdb.org.uk/cereals-oilseeds/feed-ingredient-prices")
     WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.TAG_NAME,"iframe")))
     WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.innerContainer")))
     print("Commodity:")
     print([my_elem.text for my_elem in WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//div[@class='pivotTableCellWrap cell-interactive tablixAlignLeft ' and starts-with(@title, 'Ex-')]//parent::div//preceding::div[1]")))])
     print("-=-=-=-=-=-")
     print("Basis:")
     print([my_elem.text for my_elem in WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "div.pivotTableCellWrap.cell-interactive.tablixAlignLeft[title^='Ex-']")))])

控制台输出:

     Commodity:
     ['Argentine Sunflowermeal 32/33%', 'Maize Gluten Feed', 'Pelleted Wheat Feed', 'Rapemeal (34%)', 'Soyameal (Hi Pro)', 'Soyameal, Brazilian (48%)']
     -=-=-=-=-=-
     Basis:
     ['Ex-Store Liverpool', 'Ex-Store Liverpool', 'Ex-Mill Midlands and Southern Mills', 'Ex-Mill Erith', 'Ex-Store East Coast', 'Ex-Store Liverpool']

更新(根据赏金解释)

根据您的评论以及赏金说明中的给定链接,使用@987654323 从标题Scouting Location 下的表格中的第2 页 中抓取数据@,您可以使用以下解决方案。为了演示,我创建了前 20 个国家/地区的列表,您可以随意扩展:

代码块:

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

  options = webdriver.ChromeOptions() 
  options.add_argument("start-maximized")
  options.add_experimental_option("excludeSwitches", ["enable-automation"])
  options.add_experimental_option('useAutomationExtension', False)
  driver = webdriver.Chrome(options=options, executable_path=r'C:\WebDrivers\chromedriver.exe')
  driver.get("https://app.powerbi.com/view?r=eyJrIjoiMzE1ODNmYzQtMWZhYS00NTNjLTg1MDUtOTQ2MGMyNDVkZTY3IiwidCI6IjE2M2FjNDY4LWFiYjgtNDRkMC04MWZkLWQ5ZGIxNWUzYWY5NiIsImMiOjh9")
  WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[@class='navigation-wrapper navigation-wrapper-big']//i[@title='Next Page']"))).click()
  print("Country:")
  print([my_elem.text for my_elem in WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//div[@class='bodyCells']//div[@class='pivotTableCellWrap cell-interactive ']")))[:20]])
  driver.quit()

控制台输出:

  DevTools listening on ws://127.0.0.1:49438/devtools/browser/1b5a2590-5a90-47fd-93c7-cfcf58a6c241
  Country:
  ['Myanmar', 'Myanmar', 'Mozambique', 'Malawi', 'Malawi', 'Mozambique', 'Malawi', 'Malawi', 'Malawi', 'Malawi', 'Malawi', 'Malawi', 'Malawi', 'Malawi', 'Malawi', 'Malawi', 'Malawi', 'Myanmar', 'Myanmar', 'Myanmar']

控制台输出快照:

【讨论】:

感谢@DebanjanB,我要抓取的数据在这里:app.powerbi.com/… 它是该链接上第 2 节和第 3 节的表格形式 我在赏金说明中也提供了该链接 @user308827 查看更新的答案并告诉我状态。 这太棒了,谢谢!您将如何处理需要滚动浏览的大表格? @Datanovice 您能否用相关的 HTML 提出一个新问题。我很乐意继续前进。【参考方案2】:

将滚动部分和 JSON 放在一边,我设法读取了数据。关键是读取父级内部的所有元素(在问题中完成):

parent = driver.find_element_by_xpath('//*[@id="pvExplorationHost"]/div/div/div/div[2]/div/div[2]/div[2]/visual-container[4]/div/div[3]/visual/div')
children = parent.find_elements_by_xpath('.//*')

然后使用它们的位置对它们进行排序:

x = [child.location['x'] for child in children]
y = [child.location['y'] for child in children]
index = np.lexsort((x,y))

要对我们在不同行中阅读的内容进行排序,这段代码可能会有所帮助:

rows = []
row = []
last_line = y[index[0]]
for i in index:
    if last_line != y[i]:
        row.append[children[i].get_attribute('title')]
    else:
        rows.append(row)
        row = list([children[i].get_attribute('title')]
rows.append(row)

【讨论】:

以上是关于从使用 Power BI 的网站抓取数据 - 从网站上的 Power BI 检索数据的主要内容,如果未能解决你的问题,请参考以下文章

power bi如何抓取连续的分秒

从已发布的 Power BI 视觉对象中抓取数据

来自 Power Query 的 Power BI Desktop 增量表更新

如何在 Power BI 中为查询建模以每天追加新数据而不是覆盖

power bi怎么导入到excel

power bi 中 如何 排序 列?