前几期简单介绍了一系列R爬虫的基础知识、核心R包以及一些辅助工具,其中,基础知识包括R爬虫必备基础——HTML和CSS初识,R爬虫必备基础——静态网页+动态网页,R爬虫必备基础—HTTP协议和R爬虫必备基础—动态异步加载;核心R包包括R爬虫必备——rvest包的使用,R爬虫必备基础—rvest为什么不用于动态网页?,R爬虫必备—httr+POST请求类爬虫(网易云课堂),R爬虫必备——httr+GET请求类爬虫(解螺旋课程);辅助工具包括R爬虫必备基础——CSS+SelectorGadget,R爬虫必备基础—Chrome开发者工具(F12)。今天呢,通过爬取PubMed实战案例来进一步巩固前期所学。
爬取目的
当要开展某个领域的研究时,需要检索查看下该领域都研究了什么。通过pubmed检索后文章可能非常多,这个时候不可能每篇都通读,通常都是先看下摘要,然后再选择感兴趣的进行全文查阅。为了避免一篇篇在线点击查阅,也不便于做记录,可以将该领域文章的基本信息(包括摘要内容)爬取下来,然后本地查看,最后通过PMID号下载感兴趣全文。下面,将以lncRNA为关键词,爬取2020年发表的综述类文章的题目、PMID号、作者、发表杂志、摘要等信息。
网页分析
首先打开网站,输入lncRNA关键词,选择review,然后时间限制在2020年,option选择Abstract,得到如下检索界面,网址为:https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract,这为第一条信息,共计显示10条记录。从下图我们知道该网页是个带有Query String Parameters 参数的GET类请求。
共计有390条信息,需要完全获取该怎么办?先尝试点击more后,发现展示了page2(共计10条),将鼠标往下拉,网址会添加&page=2,最终网址:https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract&page=2,Ctrl+R刷新开发工具后台,预览的结果是11-20条。按照如此规律,就可以构建有规律的网址,如下所示。共计390条记录,每页显示10条,那需要39页。按照这个思路就可以爬取所有信息。
https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract
https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract&page=2
https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract&page=3
https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract&page=4
https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract&page=5
https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract&page=6
...
https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract&page=39
但是,还有另一种方式,回到首页,打开开发后台,定位到XHR面板。然后点击more,一直more,注意这个过程不要刷新页面****,发现XHR面板上每点击一次more,就会生成一个more,同时你主网页网址维持不变。这是个典型的通过more达到异步加载的目的。
查看这几个more的Headers信息,会发现明显的规律(如下所示),都是向https://pubmed.ncbi.nlm.nih.gov/more/发起请求,通过POST提交表单信息,只要修改page即可,按照这个思路也可以爬取所有文章信息。需要注意的是,这种动态加载的POST请求类爬虫是从第二页开始的。
爬虫策略
第一种策略
构建有规律的网址【https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&page=页码】 ,共计390条记录,每页显示10条,那需要39页,可以按照这个思路进行爬取,这里它属于一种GET请求类爬虫。对于这类爬虫,有以下几种爬取方式:
- 方法一:rvest,不推荐,之前有专门有推文说过原因。爬取少量的确也能成功,但很容易被封。
- 方法二:httr+rvest组合(推荐),httr解决网络请求问题,rvest解决网页解析和信息提取。
- 方法三:RCurl+XML组合,RCurl解决网络请求问题,XML解决网页解析和信息提取。
第二种策略
根据more发起的动态加载,构建有规律的POST请求,也可以进行爬取,这里它属于一种POST请求类爬虫。对于这类爬虫,主要有以下两种爬取方式:
- 方法一:httr+rvest组合(推荐),httr解决网络请求问题,rvest解决网页解析和信息提取。
- 方法二:RCurl+XML组合,RCurl解决网络请求问题,XML
今天呢,先介绍第一种爬取策略的方法二:httr+rvest组合。
rm(list=ls())
#加载所需要的R包,没安装的提前安装
library("httr")
library("magrittr")
library("rvest")
library("xml2")
library("stringr")
#首先构造第一页的url
url <- c('https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract')
#构造请求提交信息,根据Request headers的内容填写。
mycookie <- 'ncbi_sid=CE8CCD5EEB3B8391_1825SID; _ga=GA1.2.284594426.1588836424; entrezSort=pubmed:; MyNcbiSigninPreferences=O25jYmlscyY%3D; WebCubbyUser=UFSJUQUQPJOPNU17DZHC79N0PN7V14ZM%3Blogged-in%3Dtrue%3Bmy-name%3Dyuanjiuyun%3Bpersistent%3Dtrue%40CE8CCD5EEB3B8391_1825SID; labs-pubmed-csrftoken=xKN3RWUpM9RzswSjmTAC4JiUbvWAqrtcAg0HGZHagClqGImTVx95DdMmRl117GHI; pmc.article.report=; _gid=GA1.2.1075622582.1592800677; sessionid=cwuommk94ngosh06896fslsck0ezxmb6; pm_ncbi_alert_dismiss=nCoV; pm-sid=U_VuaPR2IXwdvtAlIoP3EQ:bac28257745cb37e186420a3d2058fb9; pm-adjnav-sid=yWapb_Ia32GrozOuqYVerQ:54e8575844b60ed67d1216e4ff365989; pm-iosp=; ncbi_pinger=N4IgDgTgpgbg+mAFgSwCYgFwgCwE4BCAIgAykCM+AbAKzaHYBi1ppATPgwMysDsx2rAMKdCAOjKiAtnDJkQAGhABXAHYAbAPYBDVCqgAPAC6ZQrTOCUAjSVHSLO5sFZt2c5gM5QtEAMaJo7kpqxorU5gogsuZyiqzE5nhELBQ0dIzMLOxcvPxCIuJSMjEgrHJYTta2GBUuGJ7efgFBhhgAcgDyrQCiEaxm5c62oio+lsjDapLDyIiiAOYaML240dSclBGc8VgAHJTYm2WRaxv2/SA7rAf2DlgAZlpqnpsHWIYQSlCbO+H2K7vYHisH6KbDbC5A1grUG3EDEURQ0TxUGvZTqbS6AwhHBhLDFNbmSiUMyhVGQiLUDZYZEgag8cw0yhHMiUYjQkBEjxeXyIEAAXz5QA'
#注意比较,保留不变的参数
myheaders <- c('accept' ='text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-encoding' = 'gzip, deflate, br',
'accept-language' = 'zh-CN,zh;q=0.9',
'user-agent' = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
'referer'= 'https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=years.2020-2020&format=abstract'
)
#构造请求头参数信息,根据Query String Parameters内容填写
mypayload <- list("term" = "lncRNA",
"filter" = "pubt.review",
"filter"= "years.2020-2020",
"format" = "abstract")
#执行第一页,httr的GET函数
response <- GET(url = url, add_headers(.headers = myheaders), set_cookies(.cookies =mycookie),timeout(30),query = mypayload)
#读入并解析网页内容
web <- read_html(response, encoding ="utf-8")
paper_inf <- data.frame()
#提取文章题目
paper_title <- web %>% html_nodes("div.full-view h1.heading-title a") %>% html_text() %>% str_replace_all(" ","") %>%str_replace_all("\n","")
#提取文章PMID号
paper_PMID <- web %>% html_nodes("ul.identifiers li span.pubmed strong.current-id") %>% html_text()
paper_PMID <- paper_PMID[seq(2,length(paper_PMID),2)]
#提取发表的杂志
paper_journal <- web %>% html_nodes("div.journal-actions button") %>% html_attr("title")
paper_journal <- paper_journal[seq(2,length(paper_journal),2)]
#提取文章摘要
paper_abstract <- web %>% html_nodes("div.abstract div.selected") %>% html_text() %>% str_replace_all("\n","") %>% str_replace_all(" ","")
#提取文章作者
paper_author <- web %>% html_nodes("div.authors-list") %>% html_text() %>% str_replace_all("\n","") %>% str_replace_all(" ","") %>% str_replace_all("(\u00A0)","")
paper_author <- paper_author[seq(2,length(paper_author),2)]
#创建数据框存储以上信息
papers <- data.frame(paper_title,paper_author,paper_journal,paper_abstract,paper_PMID)
paper_inf <- rbind(paper_inf,papers)
#接下来,利用循环,从第二页开始
for (i in 2:5){
#首先构造第一页的url
url <- c('https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=pubt.review&filter=years.2020-2020&format=abstract')
#构造请求提交信息,根据Request headers的内容填写。
mycookie <- 'ncbi_sid=CE8CCD5EEB3B8391_1825SID; _ga=GA1.2.284594426.1588836424; entrezSort=pubmed:; MyNcbiSigninPreferences=O25jYmlscyY%3D; WebCubbyUser=UFSJUQUQPJOPNU17DZHC79N0PN7V14ZM%3Blogged-in%3Dtrue%3Bmy-name%3Dyuanjiuyun%3Bpersistent%3Dtrue%40CE8CCD5EEB3B8391_1825SID; labs-pubmed-csrftoken=xKN3RWUpM9RzswSjmTAC4JiUbvWAqrtcAg0HGZHagClqGImTVx95DdMmRl117GHI; pmc.article.report=; _gid=GA1.2.1075622582.1592800677; sessionid=cwuommk94ngosh06896fslsck0ezxmb6; pm_ncbi_alert_dismiss=nCoV; pm-sid=U_VuaPR2IXwdvtAlIoP3EQ:bac28257745cb37e186420a3d2058fb9; pm-adjnav-sid=yWapb_Ia32GrozOuqYVerQ:54e8575844b60ed67d1216e4ff365989; pm-iosp=; ncbi_pinger=N4IgDgTgpgbg+mAFgSwCYgFwgCwE4BCAIgAykCM+AbAKzaHYBi1ppATPgwMysDsx2rAMKdCAOjKiAtnDJkQAGhABXAHYAbAPYBDVCqgAPAC6ZQrTOCUAjSVHSLO5sFZt2c5gM5QtEAMaJo7kpqxorU5gogsuZyiqzE5nhELBQ0dIzMLOxcvPxCIuJSMjEgrHJYTta2GBUuGJ7efgFBhhgAcgDyrQCiEaxm5c62oio+lsjDapLDyIiiAOYaML240dSclBGc8VgAHJTYm2WRaxv2/SA7rAf2DlgAZlpqnpsHWIYQSlCbO+H2K7vYHisH6KbDbC5A1grUG3EDEURQ0TxUGvZTqbS6AwhHBhLDFNbmSiUMyhVGQiLUDZYZEgag8cw0yhHMiUYjQkBEjxeXyIEAAXz5QA'
#注意比较,保留不变的参数
myheaders <- c('accept' ='text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-encoding' = 'gzip, deflate, br',
'accept-language' = 'zh-CN,zh;q=0.9',
'user-agent' = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
'referer'= 'https://pubmed.ncbi.nlm.nih.gov/?term=lncRNA&filter=years.2020-2020&format=abstract')
#构造请求头参数信息,根据Query String Parameters内容填写
mypayload <- list("term" = "lncRNA",
"filter" = "pubt.review",
"filter"= "years.2020-2020",
"format" = "abstract",
"page" = i)
#执行第一页,httr的GET函数
response <- GET(url = url, add_headers(.headers = myheaders),set_cookies(.cookies =mycookie),timeout(30),query = mypayload)
#读入并解析网页内容
web <- read_html(response, encoding ="utf-8")
#提取文章题目
paper_title <- web %>% html_nodes("div.full-view h1.heading-title a") %>% html_text() %>% str_replace_all(" ","") %>%str_replace_all("\n","")
#提取文章PMID号
paper_PMID <- web %>% html_nodes("ul.identifiers li span.pubmed strong.current-id") %>% html_text()
paper_PMID <- paper_PMID[seq(2,length(paper_PMID),2)]
#提取发表的杂志
paper_journal <- web %>% html_nodes("div.journal-actions button") %>% html_attr("title")
paper_journal <- paper_journal[seq(2,length(paper_journal),2)]
#提取文章摘要
paper_abstract <- web %>% html_nodes("div.abstract div.selected") %>% html_text() %>% str_replace_all("\n","")
#提取文章作者
paper_author <- web %>% html_nodes("div.authors-list") %>% html_text() %>% str_replace_all("\n","") %>% str_replace_all(" ","") %>% str_replace_all("(\u00A0)","")
paper_author <- paper_author[seq(2,length(paper_author),2)]
#创建数据框存储以上信息
papers <- data.frame(paper_title,paper_author,paper_journal,paper_abstract,paper_PMID)
paper_inf <- rbind(paper_inf,papers)
}
#将数据写入csv文档
write.csv(paper_inf, file="paper_lncRNA_revew_2020.csv")
运行结束后,共计获取390条信息,内容如下:
以上代码主要是为了展示httr+rvest这类组合如何完成GET请求类爬虫,整体代码是比较简单粗糙的,没有添加访问出错时的应对方式,也没有设置代理池,且访问速度也不是很快,应付少量的文章爬取还是OK的。如果有小伙伴,的确有整理汇总Pubmed文章信息的需求,可以直接从官网上导出即可。新版PubMed可以提供一次性导出(10000条信息以内),具体方法,根据自身要求设置筛选条件后,点击save,选择All results即可。
结果如下图所示,内容很多,但却没有文章摘要信息,仍是美中不足(虽然网站是可以导出摘要信息的,但为txt文本格式,不直观)。所以,爬虫在一定程度上来说还是有用的。
当爬取到这些文章的基本信息后,可以本地查阅每篇文章的主要内容。对于看英文有困难,可以将其翻译成中文。将输出的文章信息修改成xls格式,然后打开https://translate.yandex.com/doc,将文件上传上去即可全文翻译。
往期回顾
R爬虫在工作中的一点妙用
R爬虫必备基础——HTML和CSS初识
R爬虫必备基础——静态网页+动态网页
R爬虫必备——rvest包的使用
R爬虫必备基础——CSS+SelectorGadget
R爬虫必备基础—Chrome开发者工具(F12)
R爬虫必备基础—HTTP协议
R爬虫必备—httr+POST请求类爬虫(网易云课堂)
R爬虫必备基础—rvest为什么不用于动态网页?
R爬虫必备——httr+GET请求类爬虫(解螺旋课程)