默认过滤器处于活动状态时下载所有数据

时间:2018-11-26 20:22:13

标签: r selenium web-scraping download rselenium

BCOGC保留a database of applications用于在不列颠哥伦比亚省东北部的钻井。默认情况下,即使应用程序数据库包含超过3万条记录,某些过滤器仍处于活动状态以仅突出显示上个月内已批准的应用程序:

enter image description here

停用过滤器后:

enter image description here

要下载整个数据集,请删除或停用任何过滤器,请单击“操作”>“下载”>“ CSV”。我想使用R自动下载整个数据集(包含3万多个记录)。

当我使用

library(tidyverse)

df <- read_csv(
  file = 'https://reports.bcogc.ca/ogc/f?p=200:21::CSV::::'
)

它只会下载默认查询指定的内容,因此会下载150条记录,而不是30K +。

如何使用R自动下载整个数据集?这是httrRSelenium的任务吗?

1 个答案:

答案 0 :(得分:1)

好的,我将继续使用Selenium,因为它不一定需要Docker(尽管我使用的示例是Docker:-)我很确定我也可以让Splash / splashr做到这一点,但它涉及文件下载,我认为这与Splash后端有关。作为splashr的作者,如果在本示例中也使用Selenium,则避免处理GitHub问题;-)

无论如何,您应该安装RSelenium。我真的不能为此提供支持,但是有据可查,并且rOpenSci团队非常有用。我强烈建议让Docker在您的系统上运行,或者让您的部门设置大家都可以使用的Selenium服务器。

此用例有两个陷阱:

  • 我们需要检测的某些元素名称是动态生成的,因此我们必须解决该问题
  • 这涉及下载CSV文件,因此我们需要在Docker中映射文件系统路径,以便其正确下载
  • 这是一个超级慢的站点,因此您需要计算每次交互后的等待时间(我不打算这样做,因为您可能处在速度较慢或更快的网络上,并且网络速度确实在其中起作用,那么多)

我建议先尝试一下RSelenium的小插曲,然后再尝试以下方法,以了解其工作原理。您实质上是在编码人工页面交互。

您将需要使用映射目录启动Docker。有关所有信息,请参见download file with Rselenium & docker toolbox,但这是我在macOS机器上所做的操作:

docker run -d -v /Users/hrbrmstr/Downloads://home/seluser/Downloads  -p 4445:4444 selenium/standalone-firefox:2.53.1

这使得Selenium可以在端口4445上访问,使用Firefox(b / c Chrome是邪恶的),并将本地下载目录映射到Docker容器中的硒用户的Firefox默认目录。这意味着well_authorizations_issued.csv将会(最终)去那里。

现在,我们需要启动R并将其连接到该Selenium实例。我们需要创建一个自定义的Firefox配置文件,因为我们将内容保存到磁盘上,并且我们不希望浏览器提示我们输入任何内容:

library(RSelenium)

makeFirefoxProfile(
  list(
    browser.download.dir = "home/seluser/Downloads",
    browser.download.folderList = 2L,
    browser.download.manager.showWhenStarting = FALSE, 
    browser.helperApps.neverAsk.saveToDisk =  "text/csv"
  )
) -> ffox_prof

remoteDriver(
  browserName = "firefox", port = 4445L,
  extraCapabilities = ffox_prof
) -> remDr

invisible(remDr$open())
remDr$navigate("https://reports.bcogc.ca/ogc/f?p=AMS_REPORTS:WA_ISSUED")
# Sys.sleep(###)
magick::image_read(openssl::base64_decode(remDr$screenshot()[[1]]))

您将需要取消注释Sys.sleep(),并尝试两次调用之间的各种“等待时间”值。有些会很短(1-2秒),有些会更大(20s,30s或更高)。

我没有在此处显示屏幕截图的输出,但是这些是弄清楚时序的一种方法(例如,在元素交互之后继续生成屏幕截图,直到灰色的微调框消失了,等等),并牢记有多少秒)。

现在,上面提到的一个棘手的问题是弄清楚复选框将关闭过滤器的位置,因为它具有动态id。但是,我们实际上并不会单击b / c复选框,创建该应用程序的傻瓜不知道他们在做什么,实际上是单击事件被包围在其周围的span元素所包围,因此我们必须找到包含复选框标签文本的li元素,然后转到span元素并单击它。

box <- remDr$findElement(using = "xpath", value = "//li[contains(., 'Approval Date is in the last')]/span")
box$clickElement()
# Sys.sleep(###)
magick::image_read(openssl::base64_decode(remDr$screenshot()[[1]]))

^^绝对需要延迟(您可能会看到它在单击自己时面对面旋转一段时间,因此您可以数一下并增加一些缓冲时间)。

然后,我们单击下拉菜单“ menu”(它实际上是button):

btn1 <- remDr$findElement(using = "css", "button#WA_ISSUED_actions_button")
btn1$clickElement()
# Sys.sleep(###)
magick::image_read(openssl::base64_decode(remDr$screenshot()[[1]]))

然后下载“菜单”项(它实际上是button

btn2 <- remDr$findElement(using = "css", "button#WA_ISSUED_actions_menu_14i")
btn2$clickElement()
# Sys.sleep(###)
magick::image_read(openssl::base64_decode(remDr$screenshot()[[1]]))

^^还需要延迟,因为下载“对话框”需要几秒钟的时间(至少对我有用)。

现在,找到确实是a标签的CSV框:

lnk <- remDr$findElement(using = "css", "a#WA_ISSUED_download_CSV")
lnk$clickElement()
### WAIT A WHILE
magick::image_read(openssl::base64_decode(remDr$screenshot()[[1]]))

最后一点是您必须尝试的东西。 一会儿来处理该请求,然后传输约9MB的文件。对rmDr$screenshot()的调用实际上等待下载完成,因此您可以删除显示和解码代码,并将输出分配给变量,并将其用作自动的“ waiter”。

我在2个不同的macOS系统上尝试了3倍,效果很好。 YMMV。

我猜您最终将要自动化,因此您可以对脚本的顶部进行system()调用,以启动Selenium Docker容器,然后执行其余部分,然后发出另一个system()调用以关闭Docker容器。

或者,https://github.com/richfitz/stevedore现在在CRAN上,因此它是启动/停止Docker容器的纯R接口(在许多其他事情中),因此您可以使用它代替system()调用。

如果您不能使用Docker,则需要在Windows机器上为Firefox安装“ webdriver”可执行文件,并获取Selenium Java归档文件,确保已安装Java,然后执行各种手动操作来实现此目的(超出了此答案的范围)。

以下是上述内容的简化版本:

library(RSelenium)

# start Selenium before doing this

makeFirefoxProfile(
  list(
    browser.download.dir = "home/seluser/Downloads",
    browser.download.folderList = 2L,
    browser.download.manager.showWhenStarting = FALSE, 
    browser.helperApps.neverAsk.saveToDisk =  "text/csv"
  )
) -> ffox_prof

remoteDriver(
  browserName = "firefox", port = 4445L,
  extraCapabilities = ffox_prof
) -> remDr

invisible(remDr$open())
remDr$navigate("https://reports.bcogc.ca/ogc/f?p=AMS_REPORTS:WA_ISSUED")
# Sys.sleep(###)

box <- remDr$findElement(using = "xpath", value = "//li[contains(., 'Approval Date is in the last')]/span")
box$clickElement()
# Sys.sleep(###)

btn1 <- remDr$findElement(using = "css", "button#WA_ISSUED_actions_button")
btn1$clickElement()
# Sys.sleep(###)

btn2 <- remDr$findElement(using = "css", "button#WA_ISSUED_actions_menu_14i")
btn2$clickElement()
# Sys.sleep(###)

lnk <- remDr$findElement(using = "css", "a#WA_ISSUED_download_CSV")
lnk$clickElement()
### WAIT A WHILE
done <- remDr$screenshot()

# stop Selenium