作者:李誉辉
四川大学在读研究生
简介:
rvest
是Hadley大神开发的包,使用非常简单,不需要懂得太多的HTML和CSS知识,
当然对于反爬虫的web,基本上就力不从心了,这种情况还是使用Python吧,毕竟术业有专攻。
首先安装SelectorGadget
(/webstore/detail/selectorgadget/mhjhnkcfbdhnjickkkdbjoemdmbfginb),这个插件很方便,可以获得网页中某些部分的相关tags。
如果不懂HTML和CSS,最好安装,如果懂,还是用Python吧。
常用函数:
read_html()
, 读取html文档或链接,可以是url链接,也可以是本地的html文件,
甚至是包含html的字符串。
html_nodes()
, 选择提取文档中指定元素的部分。
支持css
路径选择, 或xpath
路径选择。
如果tags层数较多,必须使用selectorGadget复制准确的路径。
使用方式:开启SelectorGadget,然后鼠标选中位置,右击选择检查元素,光标移动到tags上。
然后选择copy,选择selector或xpath 选项。
html_text()
,提取tags内文本,
html_table()
, 提前tags内表格。
html_form()
,set_values()
, 和submit_form()
分别表示提取、修改和提交表单。
1.文本提取
我们以boss直聘
/?ka=header-home-logo,网站为例进行演示。 首先在搜索框内输入“数据分析”进行搜索,范围选择全国, 可以打开如下页面:
然后我们单击Selector Gadget插件按钮以开启该功能,再次点击可关闭。
单击后,鼠标指针悬浮于web上任意的tags元素,都会出现黄色的高亮框。如下图所示:
选中需要的元素后,右击,然后“检查”就能打开源代码并定位到该元素,如下图:
通过浏览器,发现左侧的岗位tags为.info-primary .name
,公司名称为.info-company .name
。
其中的句点.
表示类对象,多级类对象用空格隔开。
然后用read_html()
打开该web。
2library(magrittr) 3 4#打开网页 5site_1<-"/job_detail/?query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&scity=100010000&industry=&position=" 6web_1<-read_html(x=site_1) 7 8tag_job<-".info-primary.name.job-title"#岗位名字 9tag_rev<-".info-primary.name.red"#薪水 10tag_com<-".info-pany-text.name"#公司名字 11 12#开始抓取 13job_1<-html_nodes(x=web_1,css=tag_job) 14rev_1<-html_nodes(x=web_1,css=tag_rev) 15com_1<-html_nodes(x=web_1,css=tag_com) 16 17#从tags中提取文本内容 18job_1%<>%html_text() 19rev_1%<>%html_text() 20com_1%<>%html_text() 21 22#合并向量为数据框 23job_com<-data.frame(job=job_1, 24revenue=rev_1, 25company=com_1, 26stringsAsFactors=FALSE) 27head(job_com) 28rm(site_1,web_1,job_1,com_1)1library(rvest)
提取web中的文本,就采用这种方法,很多时候,文本内容复制,
无法直接用html_text()
将文本提取出来,
这时候就需要用正则表达式和stringr
包。
2.多重页面
很多时候,一个web项目中,有多重页面,即下一页。
这就需要找到每一页的url规律,找到规律后,增加循环就能搞定了。
这里我们发现第2页开始,url就出现变化了,从第2页到最后一页(最后1页还没找到), 每一页都只改变url末尾的page=n。事实上,大多数网页都有这个page=n。
通过不断点击下一页,发现最后一页是第10页,
接下来我们爬取第2页到第10页
2library(magrittr) 3 4url_begin<-"/c100010000/?query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&page=" 5 6 7for(nin2:10){ 8myurl<-paste0(url_begin,n) 9page_n<-read_html(x=myurl) 10 11#开始抓取 12job_n<-html_nodes(x=page_n,css=tag_job)%>%html_text() 13rev_n<-html_nodes(x=page_n,css=tag_rev)%>%html_text() 14com_n<-html_nodes(x=page_n,css=tag_com)%>%html_text() 15 16#合并向量为数据框 17job_com_n<-data.frame(job=job_n, 18revenue=rev_n, 19company=com_n, 20stringsAsFactors=FALSE) 21 22 23job_com<-rbind(job_com,job_com_n)#添加到job_com内 24} 25 26rm(job_n,rev_n,com_n,job_com_n) 27str(job_com) 28DT::datatable(job_com)#交互式表格输出1library(rvest)
2##$job:chr"数据分析""数据分析专家""数据分析""数据分析(洛阳)"... 3##$revenue:chr"6k-9k""12k-18k""3k-5k""6k-7k"... 4##$company:chr"腾讯""中国石油规划总院""万声""哈啰出行"...1##'data.frame':300obs.of3variables:
3.表格提取
这里我们以pm2.5 in(http://www.pm25.in/)网站上的空气污染为例,进行表格提取。
首先打开该网站,然后我们选择一个城市,如选择“成都”,寻找url变化规律。
发现新增url后缀:chengdu。使用SelectorGadget审查元素,发现表格的类为“table”。
下面我们同时提取10个大城市的表格。
2library(magrittr) 3 4city_name<-c("beijing","shanghai","guangzhou","shenzhen","hangzhou", 5"tianjin","chengdu","nanjing","xian","wuhan") 6url_cites<-paste0("http://www.pm25.in/",city_name) 7 8for(nin1:length(city_name)){ 9 10#提取表格 11pm_city<-read_html(x=url_cites[n])%>% 12html_nodes(css=".aqis_live_data.container.table")%>% 13.[[2]]%>%#注意这里的点 14html_table() 15 16#批量生成变量 17assign(x=paste0("pm_",city_name[n]),value=pm_city) 18 19} 20rm(url_cites,pm_city) 21 22DT::datatable(pm_chengdu) 23DT::datatable(pm_beijing)1library(rvest)
(截屏预览不全)
(截屏预览不全)
4.图片提取
这里我们打开觅元素
(/),在搜索框中输入“花”,在分类中选择“动植物元素”。
可以发现url跳转到
/search/hua-40-0-0-0-1/。
同样使用SelectorGadget审查元素,发现图片都有类:.img-wrap .lazy
。
我们点击一张图片,发现跳转到另一个url,将这个url复制,在审查元素中搜索,
可以发现该url类为img-wrap
或i-title-wrap
。
2library(rvest) 3library(stringr) 4 5#提取nodes 6url_first<-"/search/hua-40-0-0-0-1/" 7flower_nodes<-read_html(x=url_first)%>% 8html_nodes(css=".img-wrap") 9 10#查看字符串,以使用正则表达式 11flower_nodes[[1]]1rm(list=ls());gc()#清空内存
2##Ncells71703638.3119792064119792064 3##Vcells135624510.4838860864261615220 4##{xml_node} 5##<aclass="img-wrap"href="/sc/cvctvrhmhh.html"target="_blank"> 6##[1]<imgclass="lazy"src="/component/base/img/...1##used(Mb)gctrigger(Mb)maxused(Mb)
正则表达式匹配,^(http)
(.html)$
这种形式只能在一行内匹配,不能匹配多行字符串。
2library(stringr) 3library(magrittr) 4library(rlist) 5 6flower_nodes%<>% 7str_extract_all(pattern="http.*\\.html")%>%#.*表示任何字符串,以http开头,.html结束 8unlist() 9 10flower_nodes[1]1library(rvest)
1##[1]"/sc/cvctvrhmhh.html"
提取图片的url链接
2library(stringr) 3 4image_url<-vector()#生成空向量 5 6for(nin1:length(flower_nodes)){ 7image_url[n]<-read_html(x=flower_nodes[n])%>% 8html_nodes(css=".img-wrap.show-image")%>% 9str_extract_all(pattern="http.*\\.jpg")%>% 10unlist() 11 12} 13 14image_url[1]1library(rvest)
1##[1]"/pic3/cover/02/00/29/5984a5c877c73_610.jpg"
读取url图片并保存
2 3file_path<-"E:/R_input_output/images_output/scrapt_collection/" 4 5for(nin1:length(image_url)){ 6image_read(path=image_url[n])%>%#读取url图片 7image_write(path=paste0(file_path,n,".jpg"))#保存图片 8} 9 10#动画展示保存到文件夹中的图片 11image_animate(image= 12image_read(path=paste0(file_path,as.character(1:length(image_url)),".jpg")))1library(magick)
(原为动图)
5.模拟对话
函数:
html_session()
,jump_to()
,follow_link()
,back()
,forward()
,submit_form()
,
可以用来模拟网上浏览行为,这里我们使用豆瓣网来模拟。
使用html_session()
来创建会话。
2library(rvest) 3library(magrittr) 4 5u<-"/" 6session<-html_session(u)#创建会话1rm(list=ls());gc()#清空内存
什么是表单? HTML 中的表单被用来搜集用户的不同类型的输入。
例如,登录表单、搜索框表单等。
HTML 表单包含表单元素,表单元素是指不同类型的 input元素、复选框(box)、
单选(radio)、提交按钮(submit)等。
穿越表单分为以下3步:
提取出你所需要的表单:
html_form()
填写你的表单:
set_values(form, name1=value1, name2=value2)
提交表单,发送给服务器:
submit_form(session, form)
2 3forms<-session%>%html_form() 4forms1library(rvest)
2form<-forms[[1]]#forms中的第一个列表是我们的目标列表 3form1library(rvest)
在上面的结果中,只有‘search_text’ :的冒号后为空,
这表明 ‘search_text’ 还没有填充任何值,而我们的填充任务就是把它填上。
比如说我要搜索“流浪地球”,
那么我就在set_values()
中指定一个search_text
参数,令它的值为“流浪地球”。
那么,现在我们的表单已经填充好了,只需要把它提交给服务器了。
2 3filled_form<-set_values(form,search_text="流浪地球")#填写表单 4session2<-submit_form(session,form=filled_form)#提交表单 5 6session2$url#查看提交表单后,返回的新会话session2的url 7iconv(URLdecode(session2$url),"UTF8")#重新编码1library(rvest)
6.项目
这里我们准备爬流浪地球豆瓣评论,然后分词并绘制词云图。
6.1
爬流浪地球豆瓣评论
首先打开流浪地球评论web,
/subject/26266893/comments?sort=new_score&status=P
因为豆瓣网页元素层数比较多,所以必须使用SelecorGadget, 审查元素后,右击进行复制,
通常可以选择selector或xpath,如图所示:
2library(rvest) 3 4url_movie<-"/subject/26266893/comments?sort=new_score&status=P" 5 6path_comments<-paste0("#comments>div:nth-child(", 7as.character(1:20), 8")>ment>p>span") 9 10text_comments<-vector()#创建空向量 11#爬取第一页的评论 12for(nin1:20){#1页20个评论 13comments_n<-read_html(x=url_movie)%>% 14html_nodes(css=path_comments[n])%>% 15html_text()%>% 16unlist() 17 18text_comments[n]<-comments_n 19} 20 21print(text_comments[1])1rm(list=ls());gc()#清空内存
爬取所有页,
通过手动点击下一页,发现页面url的规律,那就是start=n, n步长为20,初始值为20。
通过二分法找到最后一个页面,发现未登陆时仅可访问前220条评论。
下面是爬取第20条到第220条评论。
2url_pages<-paste0("/subject/26266893/comments?start=", 3as.character(seq(from=20,to=200,by=20)), 4"&limit=20&sort=new_score&status=P&percent_type=") 5for(min1:length(url_pages)){ 6 7for(nin1:20){#1页20个评论 8comments_mn<-read_html(x=url_pages[m])%>% 9html_nodes(css=path_comments[n])%>% 10html_text()%>% 11unlist() 12 13text_comments[m*20+n]<-comments_mn 14} 15Sys.sleep(20)#延迟时间20秒,避免豆瓣IP异常 16} 17 18 19#保存为txt文件 20write.table(x=text_comments, 21file="E:/R_input_output/data_output/流浪地球-豆瓣评论.txt", 22quote=FALSE,sep="\n",row.names=TRUE, 23qmethod="double",fileEncoding="UTF-8")1library(rvest)
爬其它电影评论也是一样的,只需要改id号,和保存文件名。
6.2
分词并计算词频
中文分词采用专门的包jiebaR
,更详细的资料可以看文末的参考来源。
2library(jiebaR) 3library(dplyr) 4library(readr) 5library(magrittr) 6 7#读取要分词的文本 8text_comments<-readLines(con="E:/R_input_output/data_output/流浪地球-豆瓣评论.txt", 9encoding="UTF-8") 10 11#分词 12##导入停止词 13setwd("E:/R_input_output/data_input/jiebaR_documents") 14wk<-worker(stop_word="sea.txt") 15split_1<-segment(text_comments,wk) 16split_combined<-sapply(split_1,function(x){paste(x,collapse="")})#空格分割 17 18#计算词频 19comments_freq<-freq(split_combined) 20##去除数字 21comments_freq<-comments_freq[!grepl(pattern="^\\d$",comments_freq$char),]#逻辑索引 22##排序并取前300个 23comments_freq%<>%arrange(desc(freq))%>%.[1:300,]1rm(list=ls());gc()#清空内存
6.3
词云图
安装方式:
devtools::install_github("lchiffon/wordcloud2")
。
目前wordcloud2()
绘制的图自动保存比较困难,还是截图吧。
2 3letterCloud(comments_freq,word="6",wordSize=4,color="red")1library(wordcloud2)
2color="random-light",size=1,shape='star')1wordcloud2(comments_freq,
下面是用同样的方式,爬海王豆瓣评论的词云图:
参
考来源
rvest易上手爬虫
https://cran.r-/web/packages/httr/vignettes/api-packages.html
datacamp rvest爬虫教程
/community/tutorials/r-web-scraping-rvest
R爬虫小白实例教程 - 基于rvest包
/p/543ce849eef6
R语言:rvest包学习爬虫–笔记
/p/c092d57d275f
github地址
/tidyverse/rvest
rvest穿越表单
/tidyverse/rvest
rvest爬虫教程
/article/465317
正则表达式
http://yphuang.github.io/blog//03/15/regular-expression-and-strings-processing-in-R/
rvest抓取图片
https://stat4701.github.io/edav//04/02/rvest_tutorial/
jump_to()与follow_link()
https://rdrr.io/cran/rvest/man/jump_to.html
follow_link的使用
/questions/28863775/scraping-linked-html-webpages-by-looping-the-rvestfollow-link-function
批量生成变量
/questions/10838/produce-a-list-of-variable-name-in-a-for-loop-then-assign-values-to-them
xpath语法
/2621.html
Sys.sleep
/xxzhangx/article/details/53650605
推迟时间
/questions/1174799/how-to-make-execution-pause-sleep-wait-for-x-seconds-in-r
R语言自然语言处理:中文分词
如何用R语言做词云图,以某部网络小说为例
Wordcloud2 introduction
https://cran.r-/web/packages/wordcloud2/vignettes/wordcloud.html
R语言中文分词包jiebaR
http://blog.fens.me/r-word-jiebar/
R学习整理笔记(五)——用jiebaR包进行中文分词
/p/35846130
分词 | jiebaR 常用函数
/p/35581757
jiebaR 中文分词文档
/jiebaR/
jiebaR github
/qinwf/cidian
——————————————
往期精彩:
清华、北大、浙大的计算机课程资源集都在这里了
身处大公司的非核心部门,如何破局?
IT男,程序猿在婚恋市场有多受欢迎?
R语言中文社区终文章整理(作者篇)
R语言中文社区终文章整理(类型篇)