R爬虫实战—抓取PubMed文章的基本信息

前几期简单介绍了一系列R爬虫的基础知识、核心R包以及一些辅助工具,其中,基础知识包括R爬虫必备基础——HTML和CSS初识R爬虫必备基础——静态网页+动态网页R爬虫必备基础—HTTP协议R爬虫必备基础—动态异步加载;核心R包包括R爬虫必备——rvest包的使用R爬虫必备基础—rvest为什么不用于动态网页?R爬虫必备—httr+POST请求类爬虫(网易云课堂)R爬虫必备——httr+GET请求类爬虫(解螺旋课程);辅助工具包括R爬虫必备基础——CSS+SelectorGadgetR爬虫必备基础—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类请求

image
image

共计有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达到异步加载的目的。

image

查看这几个more的Headers信息,会发现明显的规律(如下所示),都是向https://pubmed.ncbi.nlm.nih.gov/more/发起请求,通过POST提交表单信息,只要修改page即可,按照这个思路也可以爬取所有文章信息。需要注意的是,这种动态加载的POST请求类爬虫是从第二页开始的。

image

爬虫策略

第一种策略

构建有规律的网址【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条信息,内容如下:

image

以上代码主要是为了展示httr+rvest这类组合如何完成GET请求类爬虫,整体代码是比较简单粗糙的,没有添加访问出错时的应对方式,也没有设置代理池,且访问速度也不是很快,应付少量的文章爬取还是OK的。如果有小伙伴,的确有整理汇总Pubmed文章信息的需求,可以直接从官网上导出即可。新版PubMed可以提供一次性导出(10000条信息以内),具体方法,根据自身要求设置筛选条件后,点击save,选择All results即可。

image

结果如下图所示,内容很多,但却没有文章摘要信息,仍是美中不足(虽然网站是可以导出摘要信息的,但为txt文本格式,不直观)。所以,爬虫在一定程度上来说还是有用的。

image

当爬取到这些文章的基本信息后,可以本地查阅每篇文章的主要内容。对于看英文有困难,可以将其翻译成中文。将输出的文章信息修改成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请求类爬虫(解螺旋课程)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349