【问题标题】:Using rvest or RSelenium to Scrape Table使用 rvest 或 RSelenium 刮表
【发布时间】:2023-10-31 01:22:01
【问题描述】:

目标:使用 R 从以下网站抓取表格。

网站:https://evanalytics.com/mlb/models/teams/advanced

我遇到了什么问题: 我使用 rvest 来自动化我的大部分数据收集过程,但是这个特定的站点似乎超出了 rvest 的工作范围(或者至少超出了我的经验水平)。不幸的是,当页面打开时,它不会立即加载表格。我试图通过 RSelenium 提出一个解决方案,但未能找到通往桌子的正确路径(RSelenium 对我来说是全新的)。导航到页面并暂停片刻以允许表格加载后,下一步是什么?

我目前所拥有的:

library("rvest")
library("RSelenium")

url <- "https://evanalytics.com/mlb/models/teams/advanced"

remDr <- remoteDriver(remoteServerAddr="192.168.99.100", port=4445L)
remDr$open()
remDr$navigate(url)
Sys.sleep(10)

任何帮助或指导将不胜感激。谢谢!

【问题讨论】:

    标签: r json web-scraping rvest rselenium


    【解决方案1】:

    你可以通过创建一个 html_session 来在没有 Selenium 的情况下执行此操作,以便获取所需的 php 会话 ID 以传递 cookie。您还需要一个用户代理标头。有了会话,您就可以发出 POST xhr 请求来获取所有数据。您需要一个 json 解析器来处理响应 html 中的 json 内容。

    您可以在其中一个脚本标签中看到参数信息:

    function executeEnteredQuery() {
        var parameterArray = {
            mode: 'runTime',
            dataTable_id: 77
        };
        $.post('/admin/model/datatableQuery.php', {
                parameter: window.btoa(jQuery.param(parameterArray))
            },
            function(res) {
                processdataTableQueryResults(res);
            }, "json");
    }

    你可以自己为参数编码字符串:

    base64_enc('mode=runTime&dataTable_id=77')
    

    R:

    require(httr)
    require(rvest)
    require(magrittr)
    require(jsonlite)
    
    headers = c('User-Agent' = 'Mozilla/5.0')
    body = list('parameter' = 'bW9kZT1ydW5UaW1lJmRhdGFUYWJsZV9pZD03Nw==') # base64 encoded params for mode=runTime&dataTable_id=77
    session <- html_session('https://evanalytics.com/mlb/models/teams/advanced', httr::add_headers(.headers=headers))
    
    p <- session %>% rvest:::request_POST('https://evanalytics.com/admin/model/datatableQuery.php', body = body)%>%
      read_html() %>%
      html_node('p') %>% 
      html_text()
    
    data <- jsonlite::fromJSON(p)
    df <- data$dataRows$columns
    print(df)
    

    派:

    import requests
    import pandas as pd
    from bs4 import BeautifulSoup as bs
    
    body = {'parameter': 'bW9kZT1ydW5UaW1lJmRhdGFUYWJsZV9pZD03Nw=='} # base64 encoded params for mode=runTime&dataTable_id=77
    
    with requests.Session() as s:
        r = s.get('https://evanalytics.com/mlb/models/teams/advanced')
        r = s.post('https://evanalytics.com/admin/model/datatableQuery.php')
        data = r.json()
        cols = [th.text for th in bs(data['headerRow'], 'lxml').select('th')]
        rows = [[td.text for td in bs(row['dataRow'], 'lxml').select('td')] for row in data['dataRows']]
        df = pd.DataFrame(rows, columns = cols)
    print(df)
    

    【讨论】:

    • 谢谢!这很好用!我在逆向工程中遇到问题的部分是 base64 字符串。这是哪里来的?
    • 该站点似乎添加了一个免费的登录名,这导致该脚本不再以相同的方式工作。有没有办法通过站点更新再次检索相同的信息?
    • 我不记得base64了。我假设我在页面上的 xhr 中找到了编码字符串并对其进行解码以查看它在做什么或使用经验,有时您需要一个 base64 编码的主体来进行 POST。
    • 对于新站点,您可能需要执行初始授权请求(可能是基本身份验证?)您应该能够通过登录免费帐户并监控网络流量来查看。否则,我想寻找替代来源,最好是 API。
    【解决方案2】:

    时间太少了,所以只是指向您的 html 源代码,您可以从中提取带有 r 背心的表格。

      remDr$navigate(url)
      html <-remDr$getPageSource()
    ## this will get you html of the page, form here 
    ## just extract the table as you would with rvest
    

    【讨论】: