使用 R 搜索 asp javascript 分页表
scraping asp javascript paginated tables behind search with R
我正在尝试使用 rvest
或 RSelenium
提取 https://www.askebsa.dol.gov/epds/default.asp 上的内容,但当 javascript 页面以搜索框开头时找不到指导?将所有这些内容放入一个简单的 CSV 文件中会很棒。
在那之后,从像 https://www.askebsa.dol.gov/mewaview/View/Index/6219 这样的个人文件中提取数据似乎是可能的..但我也很感激这样做的明确建议。谢谢
对于问题的第一部分,这种使用 rvest
的方法应该有效。我在最后一步收到错误消息,找不到所需的名称标签。
这是我的方法 -
# open a html-session
web_session <- html_session("https://www.askebsa.dol.gov/epds/default.asp")
# get the form
test_search <- html_form(read_html("https://www.askebsa.dol.gov/epds/default.asp"))[[2]]
# set the required values for fields such as company_name, ein_number etc
# pass that info and submit the form - here i am getting an error
# it cannot recognize the 'search button' name
# if that is resolved it should work
set_values(test_search, 'm1company' = "Bend", 'm1ein' = '81-6268978' ) %>%
submit_form(web_session, ., submit = "cmdSubmitM1") %>%
read_html(.) -> some_html
如果我有时间,我会尝试做更多的研究并回复您。我发现了一些关于类似主题的教程和 SO 问题 here and 。它们有点旧但仍然有用。
第二部分比较容易,因为您不涉及任何动态元素。我能够通过使用 "selector-gadget" 检索表单中的所有地址并将所有节点名称复制粘贴到 html_nodes()
函数中。
# read the file and save it into a nested list
test_file_with_address <- read_html("https://www.askebsa.dol.gov/mewaview/View/Index/6219")
# copy paste all the css node names and get the text from the html file
test_file_with_address %>%
html_nodes(".border-top:nth-child(19) code , .border-top:nth-child(18) code , .border-top:nth-child(14) code , .border-top:nth-child(13) code , .border-top:nth-child(12) code , .border-top:nth-child(11) code , .border-top:nth-child(9) code , .section-header+ .border-top code
") %>% html_text()
[1] "\r\n Bend Chamber of Commerce Benefit Plan and Trust for Wood Products Employers\r\n 777 N.W. Wall Street, Suite 200\r\n Bend, OR 97703\r\n \r\n "
[2] "(541) 382-3221"
[3] "81-6268978"
[4] "501"
[5] "\r\n Bend Chamber of Commerce\r\n 777 N.W. Wall Street, Suite 200\r\n Bend, OR 97703\r\n \r\n "
[6] "(541) 382-3221"
[7] "93-0331932"
[8] "\r\n Katy Brooks\r\n Bend Chamber of Commerce\r\n 777 N.W. Wall Street, Suite 200\r\n Bend, OR 97703\r\n \r\n "
[9] "(541) 382-3221"
[10] "katy@bendchamber.org"
[11] "\r\n Deb Oster\r\n Scott Logging/Scott Transportation\r\n 400 S.W. Bluff Drive, #101\r\n Bend, OR 97702\r\n \r\n "
[12] "(541) 536-3636"
[13] "debo@scotttransport.com"
[14] "\r\n Karen Gibbons\r\n Allen & Gibbons Logging\r\n P.O. Box 754\r\n Canyonville, OR 97417\r\n \r\n "
[15] "(541) 839-4294"
[16] "agibbonslog@frontiernet.net"
[17] "\r\n Cascade East Benefits\r\n dba Johnson Benefit Planning\r\n 777 N.W. Wall Street, Suite 100\r\n Bend, OR 97703\r\n \r\n "
[18] "(541) 382-3571"
[19] "del@johnsonbenefitplanning.com"
[20] "93-1130374"
[21] "\r\n PacificSource Health Plans\r\n P.O. Box 7068\r\n Springfield, OR 97475-0068\r\n \r\n "
[22] "(541) 686-1242"
[23] "george.sherwood@pacifcsource.com"
[24] "93-0245545"
[25] "\r\n PacificSource Health Plans\r\n P.O. Box 7068\r\n Springfield, OR 97475-0068\r\n \r\n "
[26] "(541) 686-1242"
[27] "george.sherwood@pacificsource.com"
[28] "93-0245545"
[29] "N/A"
这需要更多 regex
魔法来清理并将它们放入 data.frame
,但基本构建块在那里可以看到。
这里是使用 RSelenium
获取单个文件链接的示例。检索链接后,其余的应该很简单。您可以使用 rvest
导航到这些 URL(就像您之前所做的那样)并借助 stringr
等字符串操作工具解析内容。对于第二部分,期待所有形式的系统结构是乐观的。请尝试花一些时间构建特定的 regular expression
s 以从检索到的文本中提取您需要的内容。
下面的代码不一定是解决您问题的最有效方法,但它包含正确的 RSelenium
概念和想法。随意根据您的需要进行调整。
附加信息:RSelenium: Basics
# devtools::install_github("ropensci/RSelenium")
library(RSelenium)
# launch a remote driver
driver <- rsDriver(browser=c("chrome"))
remDr <- driver[["client"]]
# select an URL
url <- "https://www.askebsa.dol.gov/epds/default.asp"
# navigate to the URL
remDr$navigate(url)
# choose year - option[2] corresponds to 2017
year <- remDr$findElements(using = 'xpath', '//*[@id="m1year"]/option[2]')
year[[1]]$clickElement()
# choose company
company <- remDr$findElements(using = 'xpath', '//*[@id="m1company"]')
company[[1]]$sendKeysToElement(list("Bend"))
# enter ein
ein <- remDr$findElements(using = 'xpath', '//*[@id="m1ein"]')
ein[[1]]$sendKeysToElement(list("81-6268978"))
# sumbit the form to get the results
submit <- remDr$findElements(using = 'xpath', '//*[@id="cmdSubmitM1"]')
submit[[1]]$clickElement()
# get the total number of results
num_of_results <- remDr$findElements(using = 'xpath', '//*[@id="block-system-main"]/div/div/div/div/div/div[1]/form/table[1]/tbody/tr/td/div/b[1]')
n <- as.integer(num_of_results[[1]]$getElementText()[[1]])
# loop through results and print the links
for(i in 1:n) {
xpath <- paste0('//*[@id="block-system-main"]/div/div/div/div/div/div[1]/form/table[3]/tbody/tr[', i + 1, ']/td[1]/a')
link <- remDr$findElements('xpath', xpath)
print(link[[1]]$getElementAttribute('href'))
}
# [[1]]
# [1] "https://www.askebsa.dol.gov/mewaview/View/Index/5589"
#
# [[1]]
# [1] "https://www.askebsa.dol.gov/mewaview/View/Index/6219"
请注意,如果您不缩小搜索范围,您将获得超过 50 个结果,因此结果会超过一页。在这种情况下,您需要对代码进行额外的调整(for 循环内的 xpath 结构可能会发生变化,您可能需要导航到额外的页面,循环应限制为 50 次迭代等)。
我相信这涵盖了您的实际问题,即动态抓取。您可能希望 post 单独提出后续问题,因为它们包含不同的概念。那里有很多 regex
专家,他们会帮助您解析这些表单,只要您使用合适的标签在不同的问题中解决这个特定问题。
为了获得结果,您必须填写表格并提交。您可以通过检查 html 找到 url 和字段名称。
url <- "https://www.askebsa.dol.gov/epds/m1results.asp"
post_data <- list(
m1year = 'ALL', # Year
m1company = '', # Name of MEWA (starts with)
m1ein = '', # EIN
m1state = 'ALL', # State of MEWA Headquarters
m1coverage = 'ALL', # State(s) where MEWA offers coverage
m1filingtype = 'ALL', # Type of filing
cmdSubmitM1 = 'Search',
# hidden fields
auth = 'Y',
searchtype = 'Q',
sf = 'EIN',
so = 'A'
)
现在我们可以提交表单并收集链接了。我们可以用 select 或 table.table.table-condensed td a
抓取链接。
html <- read_html(POST(url, body = post_data, encode = "form"))
links <- html_nodes(html, 'table.table.table-condensed td a') %>% html_attr("href")
links <- paste0("https://www.askebsa.dol.gov", links)
这会生成第一页的所有链接。
检查 HTTP 流量时,我注意到通过提交带有一些额外字段(m1formid、allfilings、page)的相同表单来加载下一页。我们可以通过在循环中增加页面值来获取下一页。
library(httr)
library(rvest)
url <- "https://www.askebsa.dol.gov/epds/m1results.asp"
post_data <- list(
m1year='ALL', m1company='', m1ein='', m1state='all',
m1coverage='all', m1filingtype='ALL', cmdSubmitM1 = 'Search',
auth='Y', searchtype='Q', sf='EIN', so='A',
m1formid='', allfilings='', page=1
)
links = list()
while (TRUE) {
html <- read_html(POST(url, body = post_data, encode = "form"))
page_links <- html_nodes(html, 'table.table.table-condensed td a') %>% html_attr("href") %>% paste0("https://www.askebsa.dol.gov/", .)
links <- c(links, page_links)
last <- html_text(tail(html_nodes(html, 'div.textnorm > a'), n=2)[1])
if (last != 'Last') {
break
}
post_data['page'] <- post_data[['page']] + 1
}
print(links)
对于问题的第二部分,我假设目标是 select 表单项及其值。您可以通过 selecting 所有 div.question-inline
标签和每个项目的下一个 code
标签来做到这一点。
library(rvest)
url <- "https://www.askebsa.dol.gov/mewaview/View/Index/6219"
nodes <- html_nodes(read_html(url), 'div.question-inline, div.question')
data <- list()
for (i in nodes) {
n = trimws(html_text(html_node(i, xpath='./text()')))
if (length(html_nodes(i, 'code')) == 0) {
text <- html_nodes(i, xpath = '../address/code/text()')
v <- paste(trimws(text), collapse = '\r\n')
} else {
v <- html_text(html_nodes(i, 'code'))
}
data[[n]] = v
}
print(data)
此代码生成一个包含所有表单项的命名列表,但可以修改为生成嵌套列表或更合适的结构。
在这一点上我必须说我对 R 的经验很少,所以这段代码可能不是一个好的编码示例。非常欢迎任何提示或其他评论。
我正在尝试使用 rvest
或 RSelenium
提取 https://www.askebsa.dol.gov/epds/default.asp 上的内容,但当 javascript 页面以搜索框开头时找不到指导?将所有这些内容放入一个简单的 CSV 文件中会很棒。
在那之后,从像 https://www.askebsa.dol.gov/mewaview/View/Index/6219 这样的个人文件中提取数据似乎是可能的..但我也很感激这样做的明确建议。谢谢
对于问题的第一部分,这种使用 rvest
的方法应该有效。我在最后一步收到错误消息,找不到所需的名称标签。
这是我的方法 -
# open a html-session
web_session <- html_session("https://www.askebsa.dol.gov/epds/default.asp")
# get the form
test_search <- html_form(read_html("https://www.askebsa.dol.gov/epds/default.asp"))[[2]]
# set the required values for fields such as company_name, ein_number etc
# pass that info and submit the form - here i am getting an error
# it cannot recognize the 'search button' name
# if that is resolved it should work
set_values(test_search, 'm1company' = "Bend", 'm1ein' = '81-6268978' ) %>%
submit_form(web_session, ., submit = "cmdSubmitM1") %>%
read_html(.) -> some_html
如果我有时间,我会尝试做更多的研究并回复您。我发现了一些关于类似主题的教程和 SO 问题 here and
第二部分比较容易,因为您不涉及任何动态元素。我能够通过使用 "selector-gadget" 检索表单中的所有地址并将所有节点名称复制粘贴到 html_nodes()
函数中。
# read the file and save it into a nested list
test_file_with_address <- read_html("https://www.askebsa.dol.gov/mewaview/View/Index/6219")
# copy paste all the css node names and get the text from the html file
test_file_with_address %>%
html_nodes(".border-top:nth-child(19) code , .border-top:nth-child(18) code , .border-top:nth-child(14) code , .border-top:nth-child(13) code , .border-top:nth-child(12) code , .border-top:nth-child(11) code , .border-top:nth-child(9) code , .section-header+ .border-top code
") %>% html_text()
[1] "\r\n Bend Chamber of Commerce Benefit Plan and Trust for Wood Products Employers\r\n 777 N.W. Wall Street, Suite 200\r\n Bend, OR 97703\r\n \r\n "
[2] "(541) 382-3221"
[3] "81-6268978"
[4] "501"
[5] "\r\n Bend Chamber of Commerce\r\n 777 N.W. Wall Street, Suite 200\r\n Bend, OR 97703\r\n \r\n "
[6] "(541) 382-3221"
[7] "93-0331932"
[8] "\r\n Katy Brooks\r\n Bend Chamber of Commerce\r\n 777 N.W. Wall Street, Suite 200\r\n Bend, OR 97703\r\n \r\n "
[9] "(541) 382-3221"
[10] "katy@bendchamber.org"
[11] "\r\n Deb Oster\r\n Scott Logging/Scott Transportation\r\n 400 S.W. Bluff Drive, #101\r\n Bend, OR 97702\r\n \r\n "
[12] "(541) 536-3636"
[13] "debo@scotttransport.com"
[14] "\r\n Karen Gibbons\r\n Allen & Gibbons Logging\r\n P.O. Box 754\r\n Canyonville, OR 97417\r\n \r\n "
[15] "(541) 839-4294"
[16] "agibbonslog@frontiernet.net"
[17] "\r\n Cascade East Benefits\r\n dba Johnson Benefit Planning\r\n 777 N.W. Wall Street, Suite 100\r\n Bend, OR 97703\r\n \r\n "
[18] "(541) 382-3571"
[19] "del@johnsonbenefitplanning.com"
[20] "93-1130374"
[21] "\r\n PacificSource Health Plans\r\n P.O. Box 7068\r\n Springfield, OR 97475-0068\r\n \r\n "
[22] "(541) 686-1242"
[23] "george.sherwood@pacifcsource.com"
[24] "93-0245545"
[25] "\r\n PacificSource Health Plans\r\n P.O. Box 7068\r\n Springfield, OR 97475-0068\r\n \r\n "
[26] "(541) 686-1242"
[27] "george.sherwood@pacificsource.com"
[28] "93-0245545"
[29] "N/A"
这需要更多 regex
魔法来清理并将它们放入 data.frame
,但基本构建块在那里可以看到。
这里是使用 RSelenium
获取单个文件链接的示例。检索链接后,其余的应该很简单。您可以使用 rvest
导航到这些 URL(就像您之前所做的那样)并借助 stringr
等字符串操作工具解析内容。对于第二部分,期待所有形式的系统结构是乐观的。请尝试花一些时间构建特定的 regular expression
s 以从检索到的文本中提取您需要的内容。
下面的代码不一定是解决您问题的最有效方法,但它包含正确的 RSelenium
概念和想法。随意根据您的需要进行调整。
附加信息:RSelenium: Basics
# devtools::install_github("ropensci/RSelenium")
library(RSelenium)
# launch a remote driver
driver <- rsDriver(browser=c("chrome"))
remDr <- driver[["client"]]
# select an URL
url <- "https://www.askebsa.dol.gov/epds/default.asp"
# navigate to the URL
remDr$navigate(url)
# choose year - option[2] corresponds to 2017
year <- remDr$findElements(using = 'xpath', '//*[@id="m1year"]/option[2]')
year[[1]]$clickElement()
# choose company
company <- remDr$findElements(using = 'xpath', '//*[@id="m1company"]')
company[[1]]$sendKeysToElement(list("Bend"))
# enter ein
ein <- remDr$findElements(using = 'xpath', '//*[@id="m1ein"]')
ein[[1]]$sendKeysToElement(list("81-6268978"))
# sumbit the form to get the results
submit <- remDr$findElements(using = 'xpath', '//*[@id="cmdSubmitM1"]')
submit[[1]]$clickElement()
# get the total number of results
num_of_results <- remDr$findElements(using = 'xpath', '//*[@id="block-system-main"]/div/div/div/div/div/div[1]/form/table[1]/tbody/tr/td/div/b[1]')
n <- as.integer(num_of_results[[1]]$getElementText()[[1]])
# loop through results and print the links
for(i in 1:n) {
xpath <- paste0('//*[@id="block-system-main"]/div/div/div/div/div/div[1]/form/table[3]/tbody/tr[', i + 1, ']/td[1]/a')
link <- remDr$findElements('xpath', xpath)
print(link[[1]]$getElementAttribute('href'))
}
# [[1]]
# [1] "https://www.askebsa.dol.gov/mewaview/View/Index/5589"
#
# [[1]]
# [1] "https://www.askebsa.dol.gov/mewaview/View/Index/6219"
请注意,如果您不缩小搜索范围,您将获得超过 50 个结果,因此结果会超过一页。在这种情况下,您需要对代码进行额外的调整(for 循环内的 xpath 结构可能会发生变化,您可能需要导航到额外的页面,循环应限制为 50 次迭代等)。
我相信这涵盖了您的实际问题,即动态抓取。您可能希望 post 单独提出后续问题,因为它们包含不同的概念。那里有很多 regex
专家,他们会帮助您解析这些表单,只要您使用合适的标签在不同的问题中解决这个特定问题。
为了获得结果,您必须填写表格并提交。您可以通过检查 html 找到 url 和字段名称。
url <- "https://www.askebsa.dol.gov/epds/m1results.asp"
post_data <- list(
m1year = 'ALL', # Year
m1company = '', # Name of MEWA (starts with)
m1ein = '', # EIN
m1state = 'ALL', # State of MEWA Headquarters
m1coverage = 'ALL', # State(s) where MEWA offers coverage
m1filingtype = 'ALL', # Type of filing
cmdSubmitM1 = 'Search',
# hidden fields
auth = 'Y',
searchtype = 'Q',
sf = 'EIN',
so = 'A'
)
现在我们可以提交表单并收集链接了。我们可以用 select 或 table.table.table-condensed td a
抓取链接。
html <- read_html(POST(url, body = post_data, encode = "form"))
links <- html_nodes(html, 'table.table.table-condensed td a') %>% html_attr("href")
links <- paste0("https://www.askebsa.dol.gov", links)
这会生成第一页的所有链接。
检查 HTTP 流量时,我注意到通过提交带有一些额外字段(m1formid、allfilings、page)的相同表单来加载下一页。我们可以通过在循环中增加页面值来获取下一页。
library(httr)
library(rvest)
url <- "https://www.askebsa.dol.gov/epds/m1results.asp"
post_data <- list(
m1year='ALL', m1company='', m1ein='', m1state='all',
m1coverage='all', m1filingtype='ALL', cmdSubmitM1 = 'Search',
auth='Y', searchtype='Q', sf='EIN', so='A',
m1formid='', allfilings='', page=1
)
links = list()
while (TRUE) {
html <- read_html(POST(url, body = post_data, encode = "form"))
page_links <- html_nodes(html, 'table.table.table-condensed td a') %>% html_attr("href") %>% paste0("https://www.askebsa.dol.gov/", .)
links <- c(links, page_links)
last <- html_text(tail(html_nodes(html, 'div.textnorm > a'), n=2)[1])
if (last != 'Last') {
break
}
post_data['page'] <- post_data[['page']] + 1
}
print(links)
对于问题的第二部分,我假设目标是 select 表单项及其值。您可以通过 selecting 所有 div.question-inline
标签和每个项目的下一个 code
标签来做到这一点。
library(rvest)
url <- "https://www.askebsa.dol.gov/mewaview/View/Index/6219"
nodes <- html_nodes(read_html(url), 'div.question-inline, div.question')
data <- list()
for (i in nodes) {
n = trimws(html_text(html_node(i, xpath='./text()')))
if (length(html_nodes(i, 'code')) == 0) {
text <- html_nodes(i, xpath = '../address/code/text()')
v <- paste(trimws(text), collapse = '\r\n')
} else {
v <- html_text(html_nodes(i, 'code'))
}
data[[n]] = v
}
print(data)
此代码生成一个包含所有表单项的命名列表,但可以修改为生成嵌套列表或更合适的结构。
在这一点上我必须说我对 R 的经验很少,所以这段代码可能不是一个好的编码示例。非常欢迎任何提示或其他评论。