網(wǎng)絡(luò)爬蟲
(web crawler)
,也叫網(wǎng)絡(luò)蜘蛛(spider)
,是一種用來自動瀏覽萬維網(wǎng)的網(wǎng)絡(luò)機器人。其目的一般為編纂網(wǎng)絡(luò)索引毡惜。各大搜索引擎都可以被看做爬蟲,根據(jù)爬取的內(nèi)容更新自身的網(wǎng)站內(nèi)容或其對其他網(wǎng)站的索引斯撮。一般如果想批量從網(wǎng)頁獲取數(shù)據(jù)经伙,有download
或者API
(之前推送過使用API提取TCGA數(shù)據(jù))頁面最好,沒有的話可以考慮使用爬蟲爬取。
??本期使用R語言批量爬取NCBI基因注釋信息帕膜,主要用到了XML
包的getNodeSet
函數(shù)枣氧。需要使用者有一定html+css
基礎(chǔ),以及理解并能使用XML路徑語言(xpath)
垮刹。
使用R爬取NCBI人類基因信息流程如下:
??首先準備目標基因文件达吞,我們以下面這幾個基因(gene symbol的形式)為例進行爬取其在NCBI(gene)中的信息,基因列表文件可以從這里下載(https://pan.baidu.com/s/1c2jbvby)。
載入要用到的包并讀入基因列表:
library(RCurl)
library(stringr)
library(XML)
library(clusterProfiler)
rm(list=ls())
# 讀入基因列表:
genes <- read.table("test_genes.txt",header = T,stringsAsFactors = F)
從下圖可以發(fā)現(xiàn)NCBI對于基因頁面的索引方式都是 https://www.ncbi.nlm.nih.gov/gene/Entrze ID 的方式荒典。
所以我們需要將gene symbos
轉(zhuǎn)為entrze ID
酪劫,這里使用clusterProfiler
包的bitr
函數(shù)進行轉(zhuǎn)換:
# 將gene symbol轉(zhuǎn)為entrze ID:
genes <- bitr(genes$SYMBOL, fromType="SYMBOL", toType="ENTREZID", OrgDb="org.Hs.eg.db")
然后獲得每個基因在NCBI中的索引鏈接:
# 網(wǎng)址數(shù)據(jù)框:
genes$NCBI_url <- paste("https://www.ncbi.nlm.nih.gov/gene/",genes$ENTREZID,sep="")
head(genes)
??使用XML
包的getNodeSet()
函數(shù)需要兩個參數(shù)寺董,一個是根據(jù)URL獲得的網(wǎng)頁XML document
對象覆糟,另一個是要定位的節(jié)點(xpath
格式)。不了解xpath
的可以點擊頁面左下角閱讀全文
查看其基本語法。不過我們可以在不了解語法的情況下獲得要定位節(jié)點的xpath
。只需要在chrome瀏覽器里打開NCBI
的gene信息頁面矗愧,我們以基因DBNDD1
為例,然后再按一下F12
就可以調(diào)出chrome瀏覽器自帶的開發(fā)者工具:
??比如說我們要爬取基因的Official Full name
信息麦箍,我們只需要在調(diào)出來的開發(fā)者工具欄右上角點幾下那個小箭頭,然后在點下Official Full name
然后在右上方的源代碼顯示Official Full name
的位置點擊右鍵魄藕,選擇Copy
,Copy XPath
背率。
我們可以得到這樣的xpath字段:
# Official Full name的xpath://*[@id="summaryDl"]/dd[2]/text()
??使用同樣的方法,我們可以獲得基因的HGNC ID
嫩与,Gene type
和Summary
等任何部分的xpath。
# HGNC ID的xpath://*[@id="summaryDl"]/dd[3]/a
# Gene type的xpath://*[@id="summaryDl"]/dd[5]/text()
# Summary的xpath://*[@id="summaryDl"]/dd[10]/text()
到這里準備工作就結(jié)束了划滋,接下來構(gòu)建并調(diào)用函數(shù)來爬取每個基因這4個字段的信息:
# 根據(jù)xpath獲取節(jié)點內(nèi)容:
getNodesTxt <- function(html_txt1,xpath_p){
els1 = getNodeSet(html_txt1, xpath_p)
# 獲得Node的內(nèi)容同窘,并且去除空字符:
els1_txt <- sapply(els1,xmlValue)[!(sapply(els1,xmlValue)=="")]
# 去除\n:
str_replace_all(els1_txt,"(\\n )+","")
}
# 處理節(jié)點格式,為character且長度為0的賦值為NA:
dealNodeTxt <- function(NodeTxt){
ifelse(is.character(NodeTxt)==T && length(NodeTxt)!=0 , NodeTxt , NA)
}
使用一個for循環(huán)獲得每個基因的信息并存儲到數(shù)據(jù)框:
for(i in 1:nrow(genes)){
# 獲得網(wǎng)址:
doc <- getURL(genes[i,"NCBI_url"])
cat("成功獲得網(wǎng)頁想邦!\t")
# 獲得網(wǎng)頁內(nèi)容
html_txt1 = htmlParse(doc, asText = TRUE)
# 獲得Full Name:
genes[i,"FullName"] <- dealNodeTxt(getNodesTxt(html_txt1,'//*[@id="summaryDl"]/dd[2]/text()'))
cat("寫入基因\t")
# 獲得HGNC ID:
genes[i,"HGNC_ID"] <- str_replace_all(dealNodeTxt(getNodesTxt(html_txt1,'//*[@id="summaryDl"]/dd[3]/a')),"HGNC|:","")
cat("寫入HGNC_ID\t")
# 獲得Gene type:
genes[i,"GeneType"] <- dealNodeTxt(getNodesTxt(html_txt1,'//*[@id="summaryDl"]/dd[5]/text()'))
cat("寫入GeneType\t")
# 獲得summary:
genes[i,"Summary"] <- ifelse(length(getNodesTxt(html_txt1,'//*[@id="summaryDl"]/dd[10]/text()'))!=0,getNodesTxt(html_txt1,'//*[@id="summaryDl"]/dd[10]/text()'),NA)
cat("寫入Summary\n")
print(paste("完成第",i,"個了丧没!"))
}
爬取結(jié)果如下:
??上面的節(jié)點的xpath中的標簽是按照順序在chrome生成的鹰椒,這樣就存在一個問題锡移,如果某個基因沒有某個屬性,則這個屬性后續(xù)的所有節(jié)點的xpath都將發(fā)生改變漆际。如下圖所示的兩個基因淆珊,一個有別名,一個沒有別名奸汇,則這兩個基因的Summary
的xpath
就是不同的施符,而我們是按照有別名基因的xpath爬取的,所以爬取到?jīng)]有別名的基因時的summary就會出錯茫蛹。
??為了能夠精確爬取到想要的數(shù)據(jù)操刀,這里就需要使用到xpath
的軸
和函數(shù)
獲得準確的節(jié)點定位。下面直接附上代碼:
# xpath精確定位:
for(i in 1:nrow(genes)){
# 獲得網(wǎng)址:
doc <- getURL(genes[i,"NCBI_url"])
cat("成功獲得網(wǎng)頁婴洼!\t")
# 獲得網(wǎng)頁內(nèi)容
html_txt1 = htmlParse(doc, asText = TRUE)
# 獲得Full Name:
genes[i,"FullName"] <- str_split(dealNodeTxt(getNodesTxt(html_txt1,'//*[@id="summaryDl"]/dd[preceding-sibling::dt[contains(text(),"Symbol") and position()=1 ] ]')),"provided")[[1]][1]
cat("寫入基因\t")
# 獲得HGNC ID:
genes[i,"HGNC_ID"] <- str_replace_all(getNodesTxt(html_txt1,'//*[@id="summaryDl"]/dd[preceding-sibling::dt[text()="Primary source" and position()=1 ] ]')," |HGNC|:","")
cat("寫入HGNC_ID\t")
# 獲得Gene type:
genes[i,"GeneType"] <- dealNodeTxt(getNodesTxt(html_txt1,'//*[@id="summaryDl"]/dd[preceding-sibling::dt[text()="Gene type" and position()=1 ] ]'))
cat("寫入GeneType\t")
# 獲得summary:
genes[i,"Summary"] <- dealNodeTxt(getNodesTxt(html_txt1,'//*[@id="summaryDl"]/dd[preceding-sibling::dt[text()="Summary" and position()=1 ] ]'))
cat("寫入Summary\n")
print(paste("完成第",i,"個了骨坑!"))
}
精確爬取結(jié)果如下,驗證都是正確的柬采。
??爬取結(jié)果的準確性依賴于節(jié)點定位是否準確欢唾,定位既可以通過xpath
,也可以通過CSS
粉捻,rvest
包提供里這兩種定位方式礁遣。并且rvest
包使用magrittr
包的%*%操作符,增強了代碼的可讀性肩刃。
更多原創(chuàng)精彩視頻敬請關(guān)注生信雜談: