【问题标题】:Scraping coronavirus-related data from a page which is dynamically loaded from a Tableau canvas (I think...)从从 Tableau 画布动态加载的页面中抓取与冠状病毒相关的数据(我认为......)
【发布时间】:2023-03-31 19:36:01
【问题描述】:

如果发现这个问题是重复的,我会非常高兴,但如果是这样 - 我找不到那个问答。

New York State Department of Health 中有一个神秘页面,其中包含“按县和年龄组划分的死亡人数”。正如标题所暗示的,它包含两个表(“按县”/“按年龄组”)。

出于某种奇怪的原因,此页面上的数据是超级安全的。不能选择,不能保存,不能打印。数据不在页面源上。我还尝试(但失败了)检查数据的 xhr 调用。

显然,requests 和 beautifulsoup 无法处理它。我尝试了通常的 Selenium 咒语(因此,除非另有说明,否则我不会用“我尝试过的”sn-ps 来混淆这个问题)。

期望输出:来自这两个表的数据,以任何可以想象的格式。

我唯一能想到的就是截屏并尝试对图像进行 ocr...

我不知道是 Selenium、Tableau、纽约州卫生部还是只有我,但现在是时候召集重型火炮了...

【问题讨论】:

  • 尝试this发送一个post http请求以获取json内容。
  • @asmitu 该评论完全没有知识。杰克对刮痧领域并不陌生。 !如果你能打电话给它。比重定向到其他资源做得更好

标签: python selenium web-scraping screen-scraping


【解决方案1】:

让我为你解释一下场景:

  1. 网站在参数X-Session-Id 后面生成一个session id,它是在您访问main page 页面索引时动态生成的。所以我通过GET 请求调用它,并从headers 响应中获取它。
  2. 我发现了一个POST 请求,它会在您点击所需的url 之前自动生成,它实际上使用的是我们之前收集的session id。这是https://covid19tracker.health.ny.gov/vizql/w/NYS-COVID19-Tracker/v/NYSDOHCOVID-19Tracker-Fatalities/clear/sessions/{session id}

  3. 现在我们可以调用您的目标 https://covid19tracker.health.ny.gov/views/NYS-COVID19-Tracker/NYSDOHCOVID-19Tracker-Fatalities?%3Aembed=yes&%3Atoolbar=no&%3Atabs=n

  4. 现在我注意到另一个XHR 请求back-end API。但在我们调用之前,我们将解析HTML 内容以获取负责从API 生成数据freshlytime 对象,因此我们将获得即时数据(将其视为实际上是实时聊天)。在我们的例子中,它位于HTML 内的lastUpdatedAt 后面

  5. 我还注意到,我们需要获取从我们之前的 POST 请求生成的最近的 X-Session-Id

  6. 现在我们将使用我们接听的session 拨打电话至https://covid19tracker.health.ny.gov/vizql/w/NYS-COVID19-Tracker/v/NYSDOHCOVID-19Tracker-Fatalities/bootstrapSession/sessions/{session}

现在我们已经收到了完整的回复。你可以解析它或做任何你想做的事情。

import requests
import re


data = {
    'worksheetPortSize': '{"w":1536,"h":1250}',
    'dashboardPortSize': '{"w":1536,"h":1250}',
    'clientDimension': '{"w":1536,"h":349}',
    'renderMapsClientSide': 'true',
    'isBrowserRendering': 'true',
    'browserRenderingThreshold': '100',
    'formatDataValueLocally': 'false',
    'clientNum': '',
    'navType': 'Reload',
    'navSrc': 'Top',
    'devicePixelRatio': '2.5',
    'clientRenderPixelLimit': '25000000',
    'allowAutogenWorksheetPhoneLayouts': 'true',
    'sheet_id': 'NYSDOH%20COVID-19%20Tracker%20-%20Fatalities',
    'showParams': '{"checkpoint":false,"refresh":false,"refreshUnmodified":false}',
    'filterTileSize': '200',
    'locale': 'en_US',
    'language': 'en',
    'verboseMode': 'false',
    ':session_feature_flags': '{}',
    'keychain_version': '1'
}


def main(url):
    with requests.Session() as req:
        r = req.post(url)
        sid = r.headers.get("X-Session-Id")

        r = req.post(
            f"https://covid19tracker.health.ny.gov/vizql/w/NYS-COVID19-Tracker/v/NYSDOHCOVID-19Tracker-Fatalities/clear/sessions/{sid}")

        r = req.get(
            "https://covid19tracker.health.ny.gov/views/NYS-COVID19-Tracker/NYSDOHCOVID-19Tracker-Fatalities?%3Aembed=yes&%3Atoolbar=no&%3Atabs=n")

        match = re.search(r"lastUpdatedAt.+?(\d+),", r.text).group(1)

        time = '{"featureFlags":"{\"MetricsAuthoringBeta\":false}","isAuthoring":false,"isOfflineMode":false,"lastUpdatedAt":xxx,"workbookId":9}'.replace(
            'xxx', f"{match}")

        data['stickySessionKey'] = time
        nid = r.headers.get("X-Session-Id")

        r = req.post(
            f"https://covid19tracker.health.ny.gov/vizql/w/NYS-COVID19-Tracker/v/NYSDOHCOVID-19Tracker-Fatalities/bootstrapSession/sessions/{nid}", data=data)

        print(r.text)


main("https://covid19tracker.health.ny.gov")

【讨论】:

  • 我不知道你是怎么想出这一切的——我向你致敬!谢谢 - 我也学到了一些新东西。
  • @JackFleeting 欢迎您:P 只需每天致电网络即可。我也曾与许多.gov 网站合作过:)。
  • @JackFleeting check
  • 哇,这太棒了,谢谢你,艾哈迈德! @JackFleeting 你知道如何解析结果吗?我正在尝试获取类似的数据,但无法完全弄清楚数据是如何存储的。
【解决方案2】:

我创建了一个tableau scraper library 来从 Tableau 工作表中提取数据

您可以使用以下代码获取每个工作表的 pandas 数据框中的所有数据:

from tableauscraper import TableauScraper as TS

url = "https://covid19tracker.health.ny.gov/views/NYS-COVID19-Tracker/NYSDOHCOVID-19Tracker-Fatalities"

ts = TS()
ts.loads(url)
dashboard = ts.getWorkbook()

for t in dashboard.worksheets:
    # show worksheet name
    print(f"WORKSHEET NAME : {t.name}")
    # show dataframe for this worksheet
    print(t.data)

Try this on repl.it

【讨论】:

    猜你喜欢
    • 2020-07-02
    • 2020-06-18
    • 2020-06-21
    • 2021-10-25
    • 2021-10-15
    • 1970-01-01
    • 2020-07-09
    • 2011-01-11
    • 1970-01-01
    相关资源
    最近更新 更多