我试图使用R从以下链接中提取表格: https://pubchem.ncbi.nlm.nih.gov/compound/1983#section=DrugBank-Interactions&fullscreen=true
我尝试了以下内容:
url <- "https://pubchem.ncbi.nlm.nih.gov/compound/1983#section=DrugBank-Interactions&fullscreen=true"
require(XML)
url.table <- readHTMLTable(url, which = 1, header = FALSE, stringsAsFactors = FALSE)
我收到以下错误:
Error in (function (classes, fdef, mtable) :
unable to find an inherited method for function ‘readHTMLTable’ for
signature ‘"NULL"’
In addition: Warning message:
XML content does not seem to be XML:
'https://pubchem.ncbi.nlm.nih.gov/compound/1983#section=DrugBank-
Interactions&fullscreen=true'
我不太熟悉网页抓取,有没有办法将表格从上面的链接中提取到R?另外,我如何确定数据的存储格式; XML,JSON等?
感谢。
答案 0 :(得分:4)
正如其他人所指出的那样,问题是数据是通过Javascript而不是HTML加载的,所以你需要一个能够执行JS的工具来提取信息。 Ian在他的回答中演示了使用RSelenium控制机器上的浏览器来完成任务。在这种情况下,还有另一种不需要RSelenium的方式。
使用Chrome(其他浏览器也可能这样做),您可以打开开发人员工具并查看浏览器的网络活动。虽然这是开放的,但是如果您加载上面的链接,您可以看到所有的网页所涉及的后台活动。这很重要,因为Javascript不只是让数据神奇地出现,而是从某处。此选项卡将让我们查看数据的来源。
下一步需要一些调查工作 - 我们需要找到加载数据的步骤。通常这将采用JSON格式。在活动列表的大部分时间里,我们看到有两个JSON步骤,一个用于索引,一个用于数据。我们可以右键单击并在新选项卡中打开。
This link包含(乍一看)表格中的所有数据。我们现在可以将此链接读入R并提取表格。
library(httr)
library(jsonlite)
library(magrittr)
json = GET("https://pubchem.ncbi.nlm.nih.gov/rest/pug_view/data/compound/1983/JSON/?") %>%
content(as='text') %>%
fromJSON()
GET
是一个http动词,用于从网站检索数据,来自httr
包。 content
将GET
的结果作为文本提取,fromJSON
将其转换为R中的列表(并且来自jsonlite
包。现在我们有一个大的列表,我们可以导航到查找数据。
json$Record$Section$TOCHeading
[1] "2D Structure" "3D Conformer"
[3] "LCSS" "Names and Identifiers"
[5] "Chemical and Physical Properties" "Related Records"
[7] "Chemical Vendors" "Drug and Medication Information"
[9] "Agrochemical Information" "Pharmacology and Biochemistry"
[11] "Use and Manufacturing" "Identification"
[13] "Safety and Hazards" "Toxicity"
[15] "Literature" "Patents"
[17] "Biomolecular Interactions and Pathways" "Biological Test Results"
[19] "Classification"
您正在寻找的数据是“生物分子相互作用和途径”(第17个元素),它导致另一个数据框架,显示药物库交互是第三行。
json$Record$Section$Section[[17]]$TOCHeading
[1] "Protein Bound 3-D Structures" "Biosystems and Pathways" "DrugBank Interactions"
这给出了一个包含一列的data.frame,每行都是一个包含数据帧的长度为1的列表。
dbi = json$Record$Section$Section[[17]]$Information[[3]]$Table
我们可以编写一个函数并使用一些lapply
来提取表格。
extractValues = function(i,d){
sv = dbi[d,][[1]][i,][[1]]$StringValue
out = data.frame(Key = sv[1],Value = sv[2],stringsAsFactors = F)
return(out)
}
dbi_Tables = lapply(1:nrow(dbi),function(d){
out = lapply(1:nrow(dbi[d,][[1]]),extractValues,d=d) %>%
do.call(rbind,.)
return(out)
})
现在你有一个键/值表列表。
不可否认,这比一个很好的rvest
调用要多得多,而且这个JSON是 super 凌乱,但作为处理JS加载数据的策略,它可以快得多并且不如RSelenium脆弱。
答案 1 :(得分:3)
这是一个解决javascript问题的RSelenium方法:
library(RSelenium)
library(rvest)
#this sets up the phantomjs driver
pjs <- wdman::phantomjs()
#open a connection to it
dr <- rsDriver(browser = 'phantomjs')
remdr <- dr[['client']]
#go to the site
remdr$navigate("https://pubchem.ncbi.nlm.nih.gov/compound/1983#section=DrugBank-Interactions&fullscreen=true")
#get tables
tables <- remdr$findElements('class', 'table-container')
tableList <- list()
for(i in 1:length(tables)){
x <- tables[[i]]$getElementAttribute('innerHTML') %>%
unlist() %>%
read_html() %>%
html_table()
tableList[[i]] <- x[[1]]
}
请注意,输出是一个数据帧列表 - 这是必要的,因为它们可以有不同的长度。
如果您遇到错误,可能需要在代码中加入一些暂停,以说明RSelenium可能会不堪重负。我不能想到围绕这个问题的另一个好方法。