从使用Power BI的网站中收集数据-从网站上的Power BI中检索数据

时间:2019-03-08 12:28:57

标签: python selenium web-scraping powerbi

我要从此页面(以及与之相似的页面)中抓取数据: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使用div在屏幕上放置position:absolute元素,并区分表中div的位置(行和列) )是一项艰苦的活动。

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

注意:我意识到所有数据都不会加载,甚至不会同时显示。类div的{​​{1}}负责充当滚动条,并进行移动以加载/显示数据的其他部分。

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

scroll-bar-part-bar

我感谢您解决上述任何问题。对于我来说,最有趣的是约定以JSON格式存储Power BI数据。

2 个答案:

答案 0 :(得分:3)

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

  • 为所需的frame_to_be_available_and_switch_to_it()引入 WebDriverWait
  • 为表所需的visibility_of_element_located()诱导 WebDriverWait
  • 为所需的数据visibility_of_all_elements_located()生成 WebDriverWait
  • 您可以使用以下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']
      

更新(根据赏金解释)

根据您的评论以及赏金解释中的给定链接,请使用{{从标题下的表格中的 Page 2 中抓取数据3}},您可以使用以下解决方案。为了演示,我创建了一个 20 个国家/地区的 List ,您可以根据需要扩展任意数量:

  • 代码块:

    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']
    
  • 控制台输出快照:

Selenium

答案 1 :(得分:0)

除了滚动部分和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)