从位于网站的图表中解析表格项目时遇到问题

Posted

技术标签:

【中文标题】从位于网站的图表中解析表格项目时遇到问题【英文标题】:Trouble parsing tabular items from a graph located in a website 【发布时间】:2019-12-30 10:51:07 【问题描述】:

我正在尝试提取网页图形上可用的表格内容。只有当有人将光标悬停在该区域内时,这些表格的内容才可见。 this one 就是这样一张表。

Webpage address

表格所在的图表标题为EPS consensus revisions : last 18 months

到目前为止,我已经尝试过:

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

link = "https://www.marketscreener.com/SUNCORP-GROUP-LTD-6491453/revisions/"

driver = webdriver.Chrome()
driver.get(link)
wait = WebDriverWait(driver, 10)
for items in wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "#graphRevisionBNAeec span > table tr"))):
    data = [item.text for item in items.find_elements_by_css_selector("td")]
    print(data)
driver.quit()

当我运行上述脚本时,它会抛出错误 raise TimeoutException(message, screen, stacktrace):selenium.common.exceptions.TimeoutException: Message: 指向此 for items in wait.until() 行。

多个表中的单个表的输出应如下所示:

Period: Thursday, Aug 22, 2019
Number of upgrading estimates: 0
Number of unchanged estimates: 7
Number of Downgrading estimates: 0
High Value: 0.90 AUD
Mean Value: 0.85 AUD
Low Value: 0.77 AUD

如何从该图中获取这些表格的内容?

编辑:我仍然期待任何纯粹基于任何浏览器模拟器的解决方案。

【问题讨论】:

【参考方案1】:

直接查询网站的后端比使用 selenium 抓取前端要好得多,原因有以下三个:

    速度:直接使用 API 更快、更高效,因为它只获取您需要的数据,而无需等待 javascript 运行或像素呈现,并且没有运行 webdriver 的开销。

    稳定性:通常前端的更改比后端的更改更频繁且难以跟踪。如果您的代码依赖于网站的前端,那么当他们进行一些 UI 更改时,它可能会很快停止工作。

    准确性:有时 UI 中显示的数据不准确或不完整。例如,在这个网站中,所有数字都四舍五入到小数点后两位,而后端有时会提供两倍以上的数据。

以下是您可以轻松使用后端 API 的方法:

import requests
# API url found using chrome devtools
url = 'https://www.marketscreener.com/charting/afDataFeed.php?codeZB=6491453&t=eec&sub_t=bna&iLang=2'
# We are mocking a chrome browser because the API is blocking python requests apparently
headers = 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/76.0.3809.100 Safari/537.36'
# Make a request to the API and parse the JSON response
data = requests.get(url, headers=headers).json()[0]
# A function to find data for a specific date
def get_vals(date):
    vals = []
    for items in data:
        for item in items:
            if item['t'] == date:
                vals.append(item['y'])
                break
    return vals
# Use the function above with the example table given in the question
print(get_vals('Thursday, Aug 22, 2019'))

运行此操作会输出列表[0.9, 0.84678, 0.76628, 0, 7, 0],如您所见,这是您要从作为示例提供的表中提取的数据。

【讨论】:

点赞,学到了新东西。我有一个疑问,你是如何使用 chrome devtools 获得url 的?你的意思是Inspect Elements 并查看源代码。我在这里找不到给定的网址。 我不能代表 kmaork,但我会从开发工具捕获网络流量,然后过滤 XHR 请求。 我完全按照@FiddleStix 所说的做了。 chrome devtools 中的网络选项卡是我在每个网络抓取项目中的首选工具。【参考方案2】:

尝试更改此定位器:

By.CSS_SELECTOR, "#graphRevisionBNAeec span > table tr"

有了这个:

By.XPATH, "//*[@class='tabElemNoBor overfH']"

我得到一个这样打印的控制台:

[u'EPS consensus revisions : last 18 months', u'EPS consensus revisions : last 18 months', u'Number of Estimates\nEPS 2020(AUD)\nNumber of upgrading estimates\nHigh Value\nNumber of unchanged estimates\nMean Value\nNumber of downgrading estimates\nLow Value\nMar 18\nApr 18\nMay 18\nJun 18\nJul 18\nAug 18\nSep 18\nOct 18\nNov 18\nDec 18\nJan 19\nFeb 19\nMar 19\nApr 19\nMay 19\nJun 19\nJul 19\nAug 19\nSep 19\nOct 19\n0\n2\n4\n6\n8\n10\n12\n0.2\n0.4\n0.6\n0.8\n1\n1.2\n1.4\n\xa9marketscreener.com - S&P Global Market Intelligence']

【讨论】:

【参考方案3】:

这是使用 selenium 的解决方案(我用 Firefox 测试了我的代码,但它在 Chrome 上运行良好):

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
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Firefox()
actions = ActionChains(driver)

driver.get("https://www.marketscreener.com/SUNCORP-GROUP-LTD-6491453/revisions/")

table = driver.find_element_by_xpath("//table[@class = 'tabElemNoBor overfH']") #if you want other table, change the XPath
actions.move_to_element(table).perform()

date= WebDriverWait(driver,60).until(EC.presence_of_element_located((By.XPATH, "//table[@class = 'tabElemNoBor overfH']//div[@class = 'highcharts-label highcharts-tooltip highcharts-color-undefined']/span/span//b"))).text
data = WebDriverWait(driver,60).until(EC.presence_of_all_elements_located((By.XPATH, "//table[@class = 'tabElemNoBor overfH']//div[@class = 'highcharts-label highcharts-tooltip highcharts-color-undefined']//td")))
data = [item.get_attribute("innerHTML") for item in data]
data_1 = [data[i] for i in range(len(data)) if i%2==0]
data_2 = [data[i][3:data[i].find("&")] for i in range(len(data)) if i%2==1]
data = list(zip(data_1, data_2))
print(date)
for i in data:
     print(i[0], i[1])

我只是触发表来生成信息表的html代码。如果要更改日期,只需使用鼠标移动方法即可。

【讨论】:

【参考方案4】:

我检查了页面,但您的定位器不起作用,因为您要查找的元素是在您将鼠标悬停在图表上至少一次之后生成的。所以你从测试一开始就没有那个元素。

要悬停在元素上,您需要ActionChains。我会建议 move_to_element (位于 css 选择器:“.highcharts-plot-background”)移动到图表的中间。不要忘记使用 perform() 来执行动作链。

【讨论】:

以上是关于从位于网站的图表中解析表格项目时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

关于SQL Server 2017中使用json传参时解析遇到的多层解析问题

.NET 图表图例标记大小

关于vue项目中表格所遇到的问题

iview表格导出Excel时遇到的问题:导出.xls文件&导出的表格部分列错位

疫情图表化查询

从字符串解析 DateTime 时遇到问题