R语言爬虫实例 初学者自用

这篇具有很好参考价值的文章主要介绍了R语言爬虫实例 初学者自用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文记录了使用rvest & RSelenium 包进行爬虫与网页渲染的相关知识点及本人的编程操作过程。涉及到基本爬取操作、爬取缺失部分如何处理、操作网页过滤等步骤。

本人非计算机专业,如有措辞不慎敬请提出。


爬虫目标

这学期为了凑学分,选了一门R语言的课,才发现R语言远比我们想象的要强大。至少问过身边同学,他们都不知道R还能爬虫qaqq

为了防止自己学过就忘..写一篇blog记录一下被rvest与Rselenium折磨的这一个周的成果。

以下是代码爬取的要求:

  • 从IMDb首页出发,提取该榜单所有电影的user reviews各100条
  • 使用Rselenium进行网页操作:User Reviews可能存在剧透(Spoilers),需要进行隐藏(Hide Spoilers);每个review网页初始显示评论25条,需要点击Load More加载更多评论。
  • 保存每条评论及对应的电影评分。Tips:存在只有内容没有评分的评论。

1 爬虫知识整理

在进行实例展示之前,先回顾一下R语言爬虫需要用到的知识。主要涉及两个库:rvest与rselenium

1.1 Rvest包

Rvest功能强大,语法简洁,用起来真的很顺手。由于本文只用到了读取与提取的API,在这里也只对相关的API进行说明。

编号 函数名 作用
1 read_html() 根据给定的url,【读取其html文档】
2 html_nodes() 提取html文档中的对应【节点与元素】
3 html_name() 提取【标签名称】
4 html_text() 提取标签内的【文本内容】
5 html_attrs() 提取【所有的属性名称及其内容】
6 html_attr() 提取【指定】属性的内容
7 html_table() 将网页数据表的数据解析到R的dataframe中
8 html_form() 提取表单

我们结合具体环境看一下部分代码的作用:

1.1.1 read_html()

在read_html()的参数部分,我们给定一个网址,这个函数就能够返回这个网址指向的HTML网页数据。

# 使用read_html()下载IMDB首页的html文件
url <- "https://www.imdb.com/chart/moviemeter?sort=rk,asc&mode=simple&page=1"
webpage <- read_html(url)
webpage

# 返回结果:
#{html_document}
#<html xmlns:og="http://ogp.me/ns#" xmlns:fb="http://www.facebook.com/2008/fbml">
#[1] <head>\n<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\n<script #...
#[2] <body id="styleguide-v2" class="fixed">\n            <img height="1" width="1" style #...

1.1.2 html_*()

不可避免的,我们需要了解一些HTML的知识:

下图中<>框起的部分就是标签,而每个<>后对应的第一个紫色英文单词就是我们所说的标签(如div);黄色部分是属性名称(如name, class);属性名称 = “?” ,引号中的内容就是我们说的属性内容;黑色部分就是显示的文本

将各部分拆解了以后,我们也就能明白每个函数能提取出什么来——

html_nodes():使用标签进行定位;

html_attrs():提取等号后的属性内容;

html_text():提取“黑色部分”

r语言爬虫,r语言,爬虫,selenium

1. html_nodes()

参数有二:

编号 参数 说明
1 x 可以是html文件,也可以是之前提取过的nodes文件
2 css/xpath 需要提取的节点位置

比较重要的就是节点位置的选取,也就是我们的第二个参数部分。以下图为例,我们想提取header部分,我们可以采用以下方法提取:

r语言爬虫,r语言,爬虫,selenium

① css/xpath:直接复制型

 如上图所示,我们将鼠标移到对应元素的html文档上面,点击右键→复制→复制selector/复制XPath,即可获得路径如下→GET!

#css:
 "#main > section > div.lister > div.header"
#xpath: 
"//*[@id="main"]/section/div[2]/div[1]"

② 标签.属性内容 型

标签:div;属性:name;属性内容:header。将属性(黄色部分)划了去,直接div.header→GET!定位成功!

P.S 有时如果掌握不好这个方法,也可以将元素选择鼠标放到对应的位置上,就会自动显示出节点。比如说图中左侧的div.header

③  标签(空格)标签 型

这里换一个例子比较合适。使用薄荷健康食品库的网页(因为比较简单)。

 如果我们想爬取食品类别和烹饪方式,发现对应元素标签<li> <a href....>

r语言爬虫,r语言,爬虫,selenium

那么我们的节点就可以写为:

cooking_style <- start %>% html_nodes("li a")

# 返回结果
#{xml_nodeset (40)}
# [1] <a href="/foods/list?ifood_group_id=1">谷薯主食</a>
# [2] <a href="/foods/list?ifood_group_id=2">肉蛋及制品</a>
# ...

2. html_text():

这个函数正如我们上面所说,爬的是黑色部分——文本。

那还是薄荷健康的例子,在获取了cooking_style这个具体的元素块了以后,我们对文本进行提取:

cooking_style <- start %>% html_nodes("li a") %>% html_text(trim = TRUE)

# 返回结果
# [1] "谷薯主食"   "肉蛋及制品" "奶类及制品" "蔬果和菌藻" "坚果及制品" "饮料"       "油类及制品"
# [8] "调味品"     "零食及冷饮" "其它"       "扒"         "拔丝"       "炒"         "炖"        
# ...

trim = TRUE能够将文本中的空格进行剔除,这样获得的文本也会更加规范。

3. html_attrs():

这个函数最常见的用途一定是获得其他网页的url了!而url出现的位置:a href = "巴拉巴拉巴" 就是我们说的【引号中的部分】

在薄荷健康中,如果我们想获取每种食物or烹饪方式的网址,那么:

website <- start %>% html_nodes("div.knowledgeTagTableviewBorder a") %>% 
  html_attr("href")

# 返回结果:
# website
# [1] "/foods/list?ifood_group_id=1"  "/foods/list?ifood_group_id=2"  "/foods/list?ifood_group_id=3" 
# [4] "/foods/list?ifood_group_id=4"  "/foods/list?ifood_group_id=5"  "/foods/list?ifood_group_id=6" 

But 我们一看,这个网址和实际上的不一样嘛!

这就需要我们使用paste()进行网址的补全:

website <- paste("http://m.boohee.com/", website, sep = "")

# 返回结果:
# website
# [1] "http://m.boohee.com//foods/list?ifood_group_id=1" 
# [2] "http://m.boohee.com//foods/list?ifood_group_id=2" 
# ... 

这样就对了!可以访问这些链接了!

while Rvest包中还存在着一些处理乱码、进行行为模拟操作的API。虽然我没有用到,但在这里还是展示一下:

分类 编号 函数名 作用

乱码处理

*_encoding()

1 guess_encoding() 用来探测文档的编码,方便我们在读入HTML文档时设置正确的编码格式
2 repair_encoding() 修复HTML文档读入后的乱码问题
行为模拟(如输入账号、密码等) 1 set_values() 修改表单
2 submit_form() 提交表单
3 html_session() 模拟HTML浏览器会话
4 jump_to() 得到相对链接或绝对链接
5 follow_link() 通过表达式找到当前页面下的链接
6 session_history() 历史记录导航工具

1.2 RSelenium包

Rvest包是帮助你对给定网页直接进行信息爬取的工具,而RSelenium包则是进行“网页自动控制”的工具。它能够自动打开网页,并根据我们的代码指令进行比如说像点击、查询特定信息等活动,帮助我们进行更精确的爬虫操作。

P.S rselenium包是基于JAVA存在的,因此在使用之前需要提前下载安装Java SE Development Kit

加载如下packages:

library(tidyverse)
library(rvest)
# install.packages("RSelenium")
library(RSelenium)
# install.packages("netstat")
library(netstat) # we are going to use the function free_port() in this package

1.2.1 打开浏览器(谷歌chrome)

rs_driver_object <- rsDriver(browser = "chrome",chromever = "106.0.5249.21",verbose = F, port = free_port())
remDr <- rs_driver_object$client

可以通过在Chrome浏览器中键入“chrome://settings/help”或在R中输入binman::list_versions("chromedriver")查看自己的浏览器版本。

1.2.2 网页导航

1. 打开一个网页:

remDr$navigate("http://www.imdb.com/title/tt1856010/reviews")

2. 刷新操作:

remDr$refresh()

3. 得到当前页面网址:

remDr$getCurrentUrl()

这个功能还是需要说一下的。正如我们之前所说,Rvest包与RSelenium包功能不同,所以也不能用一种逻辑使用两种工具包。

我们在对一个网页进行所有selenium操作后,需要注意,此时的url和之前是不同的,会显示很多条件。

r语言爬虫,r语言,爬虫,selenium

 r语言爬虫,r语言,爬虫,selenium

 这时,我们需要使用remDr$getCurrentUrl()语句得到当前的url,然后使用read_html()读入其HTML文件,进行爬取工作。

4. 前进、回撤动作

remDr$goBack()
remDr$goForward()


1.2.3 定位HTML元素

我们可以使用id, name, class 或css selector、xpath等定位方式寻找我们需要的元素。

使用语句findElement()即可。第一个参数为定位方式,第二个参数为元素名称。

# id方式
loadmore <- remDr$findElement(using = "id", value = "load-more-trigger")
# css方式
loadmore <- remDr$findElement(using = "css", "#load-more-trigger")

1.2.4 将操作传递给元素

1. 点击操作click

(1) 直接单击操作:clickElement()

loadmore$clickElement()

(2) 如果要控制点击的左右键:click(buttonId=0/1/2)

click(buttonId = 0) 

0单击左键,1单击滚动条,2单击右键。

(3) 双击:doubleclick()

doubleclick(buttonId = 0)

2. 模仿鼠标的一些其他操作,如使用滚轮滑到页面最下端

bottom <- remDr$findElement("css", "body")
bottom$sendKeysToElement(list(key = "end"))  #“滚动到最下端”

sendKeysToElement()功能主要用于在指定元素中输入文本。一般是先使用findelement()定位到该元素,再使用sendKeysToElement()进行内容与操作的传递。sendKeysToElement()的参数必须为list形式。

3. 传递文本信息

query <- remDr$findElement(using = "css", "#suggestion-search")
query$sendKeysToElement(list("The Godfather", key = "enter"))
# 输入文本the godfather, 然后回车搜索

1.2.5 检索页面源代码

正如前面getCurrentUrl()步骤所说,在进行完一系列操作后,我们需要获得此时的url,然后才能进行接下来的爬取工作。

page_source <- remDr$getPageSource()[[1]]
remDr$getCurrentUrl()
page_source %>% read_html()

2. 爬取IMDb电影网的数据

(1)安装相应的package

library(tidyverse)
library(rvest)
library(xml2)
library(RSelenium)
library(netstat)

(2)从电影网首页出发,获取其HTML文件

# 使用read_html()下载IMDB首页的html文件
webpage <- read_html("https://www.imdb.com/chart/moviemeter?sort=rk,asc&mode=simple&page=1")
webpage

(3)使用html_nodes() %>% html_attrs(),获取排行榜中各电影主页的链接

# 从首页信息出发,提取100部电影首页的网址
website <- html_nodes(webpage, "td.titleColumn a") %>% html_attr("href")
# 使用paste()将url补充完整
website_title <- paste("http://www.imdb.com",website,sep = "")

由于提取的URL缺少部分内容,我们使用字符串拼接paste()函数将其补全

paste(..., sep = " ", collapse = NULL)

① ...:需要拼接的文本

② sep:使用什么符号将文本分隔开,default = 空格

③ collapse:若不指定值(default = NULL),则结果返回由sep中指定符号连接而成的字符型向量;若指定值(如“,”),则将字符型向量间通过collapse的值连接形成一个字符串

(4) 由于各电影主页中包含多种“评论”的链接,我们需要在各电影首页提取user reviews的网址

review_page <- c()
for (i in 1:100){
  all_page <- read_html(website_title[i])
  reviews <- html_nodes(all_page, ".isReview") %>% html_attr("href")
  # 上一步会返回user/critic/metascore 三个网址,在这里只保留返回的第一个结果
  review_page <- c(review_page, reviews[1])
}

# 补充url
review_title <- paste("http://www.imdb.com",review_page,sep = "")
review_title

·定义review_page()为一个空的向量,在每次读取URL后将新的内容补充进去。

·使用paste补充网址,将结果存储到review_title变量中。

(5)使用RSelenium对网页进行操作

# 连接chrome浏览器
rs_driver_object <- rsDriver(browser = "chrome", chromever = "106.0.5249.61", 
                             verbose = F, port = free_port())
remDr <- rs_driver_object$client

# total用于存储所有页面的评论与评分信息
total <- data.frame() 

在100部电影的user reviews页面,我们需要勾选“隐藏剧透”的单选框,并通过点击load more键,获取100条评论及其评分

① 对于review_title中的网址,我们需要将其转换为character格式,然后再进行navigate导航。

② 隐藏剧透:使用findElement进行定位,通过clickElement点击单选框

③ 加载更多:

A. 在不点击的情况下,一个界面提供25条评论;

B. 确认该电影的评论数量:使用read_html()读取界面HTML文档,定位至评论数量。由于返回的文本格式为“xxx Reviews”,我们使用字符串截取substr()函数进行文本提取。

substr(s, first, last)

① s:需要处理的字符串

② first:起始位置(包含在内)

③ last:结束位置(包含在内)

【nchar:确认字符串长度】

我们需要将上一步的评论数量转化为数值型,以便进行下一步判断。如果评论数量上千会出现分位符,我们使用替换字符gsub()函数将其消掉。

gsub("目标字符", "替换字符", 对象)

然后使用if else语句进行判断。

(6) 爬取100条评论:

将Rselenium操作后的网址保存,再使用read_html读取其HTML文件。将评论区的一整块保存到all变量中。

对于该电影的所有评论(seq_along(all)),如果评分存在,则读取其评分与评论内容。

判断评分是否存在的代码为:length != 0 ,如果不存在则是空值,其长度为0,也就不进行接下来的操作。

使用rbind()函数,将每一次读取的评分与评论内容补充到dataframe中。

(record用于存储某一部电影的内容;total用于存储全部内容)

for (i in 1:100){
  url <- as.character(review_title[i])
  remDr$navigate(url)
  # remDr$refresh()
  
  # 隐藏剧透
  hide <- remDr$findElement(using = "xpath", value = "//*[@id='main']/section/div[2]/div[1]/form/div/div[1]/label/span[1]")
  hide$clickElement()
  
  # 加载更多
  thispage <- read_html(url)
  numreview <- c()
    # 读取当前页面的评论数量,用于分析如何进行点击操作
  numreview <- html_nodes(thispage,"#main > section > div.lister > div.header > div > span") %>%
    html_text(trim = TRUE) %>% substr(1,nchar(.)-8) 

  numreview <- as.numeric(gsub(",","", numreview))
  
  if (numreview >= 25){
    loadmore <- remDr$findElement(using = "id", value = "load-more-trigger")
    loadmore$clickElement()# 一次会出现25条评论,点4次即可获得100条评论
    Sys.sleep(2)           # 由于网速限制,中间需要有间隔时间暂停
    loadmore$clickElement() 
    Sys.sleep(2)
    loadmore$clickElement()
    Sys.sleep(2)
    loadmore$clickElement()
  } else {
    Sys.sleep(1)
  }
  
  # 获取前面步骤已完成后的网址,用于后续爬取工作
  page_source <- remDr$getPageSource()[[1]]
  remDr$getCurrentUrl()
  page_source <- read_html(page_source)
  
  # all中存储了每一个评论块的xml文件
  all <- html_nodes(page_source, "div.review-container")
  
  # records用于存储当前页面的评论与评分信息
  records <- data.frame()
  
  # 爬取当前页面的评论与评分
  for (j in seq_along(all)){
    #设置判断:避免评分空值
    if (html_nodes(all[j], "span.rating-other-user-rating") %>% length != 0){
      nodes <- html_nodes(all[j], "span.rating-other-user-rating") %>% 
        html_text(trim = TRUE) %>% substr(1,nchar(.)-3)
      notes <- html_nodes(all[j], "div.text.show-more__control")%>% html_text(trim = TRUE)
    }
    # 设置一个新的dataframe,用于存储每一次新爬取的评论与评分信息
    new_record <- data.frame(RANKS = nodes, REVIEWS = notes)
    # 将新的信息组合到records中。
    records <- rbind(records, new_record)
  }
  # 每一次循环的信息保存到total的数据框中
  total <- rbind(total, records)
}

# 保存爬取的所有文件
write_excel_csv(total, "111.csv")

在这里使用write_excel_csv()函数保存内容。用了其他的保存文件函数都出现了乱码...设置encoding = UTF8也不行,只有这个函数是好用的。如果出现乱码大家也可以自行百度,多试试几个函数。

这样,我们就爬取了100部电影及其评论文本&评论评分!文章来源地址https://www.toymoban.com/news/detail-782464.html

到了这里,关于R语言爬虫实例 初学者自用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android Studio初学者实例:仿网易音乐播放器

    本期带来的是以Service为主要的知识点的网易音乐播放器 看一下效果图  首先项目准备: 在res下新建raw文件夹,并在文件夹中添加喜爱的mp3音乐  OK,第一步,先写一个背景文件,在res/drawable文件夹中新建xml文件: btn_bg_selector.xml  编写主界面代码activity_main.xml 编写MusicServic

    2024年02月05日
    浏览(51)
  • Android Studio初学者实例:RecyclerView学习--模仿今日头条

    本案例来自于学校的一个简单的课程实验 先看效果图,可以显然的看到,一些item是不同的布局,而其他布局就是简单的布局嵌套 看一下xml代码:  XML代码中部分重复样式写入到了style文件中 看一下加入style.xm的代码,这个文件是存放在value文件夹下,存放样式、主题等。 看

    2024年02月06日
    浏览(65)
  • Android Studio初学者实例:ListView学习--购物商城

    此实践案例由课堂上学习ListView控件提供。先上效果图,使用Listview控件实现一个简单的购物商城界面 显然,界面由Textview与ListView构成,看一下XML代码 父布局使用LinearLayout布局,我也是比较喜欢用该布局的,使用orientation属性来设置布局的方向,此时vertical即为垂直方向,例

    2024年02月06日
    浏览(62)
  • Android Studio初学者实例:ContentProvider读取手机通讯录

    该实验是通过ContentProvider读取手机通讯录 知识点包含了RecyclerView控件、UriMatcher、ContentResolver 先看效果,显示手机通讯录  首先是界面的布局代码 activity_main59.xml 其次是RecyclerView的item布局代码,其中使用了CardView是为了方便快捷的弄个圆角储来 main59_item.xml 一个联系人的实体

    2024年02月03日
    浏览(50)
  • Android Studio初学者实例:SQLite实验:绿豆通讯录

    本次实验是使用SQLite对一个通讯录表进行简单增删改查 以下是实验效果:  首先是继承SQLiteOpenHelper的数据库自定义类 对于此类必须继承于SQLiteOpenHelper ,当new创造该类的实例的时候会执行创建数据库以及表的操作,例如本代码中数据库名为itcast,数据库表名为informatoin。db

    2024年02月08日
    浏览(48)
  • python爬虫——爬取豆瓣top250电影数据(适合初学者)

    爬取豆瓣top250其实是初学者用于练习和熟悉爬虫技能知识的简单实战项目,通过这个项目,可以让小白对爬虫有一个初步认识,因此,如果你已经接触过爬虫有些时间了,可以跳过该项目,选择更有挑战性的实战项目来提升技能。当然,如果你是小白,这个项目就再适合不过

    2024年02月07日
    浏览(83)
  • Android Studio初学者实例:Fragment学习--仿美团外卖界面

    本次课程为Fragment为主题,课程的示例仿美团外卖界面,不同于底部导航栏的Fragment案例,此界面分为左侧切换与顶部切换。本文先是发布代码与效果,后续讲解将会在后续补充。先看看效果: 首先是布局文件代码:Activity布局:activity_main.xml: 首先父布局用的LinearLayout布局,

    2024年02月03日
    浏览(69)
  • Android Studio初学者实例:音乐播放器与Service学习

    本次一个案例实现的一个简单的音乐播放器 用到的知识点最主要的几点是:Service、handler(实现音乐播放的进度条更新与图片旋转)以及用于播放音频的MediaPlayer 看一下案例效果:  由于Service是Android的四大组件之一,Activity、Service等等一个重要知识点就是生命周期的问题,

    2024年02月03日
    浏览(47)
  • C语言初学者自序

    在这篇博客的开头,我首先说明,本人是金融专业大一的菜鸟。为什么会学习C语言以及与计算机的不解之缘,我会在下面一一解答。 我与计算机的故事,得从我幼年时说起。当然,这不是老太婆裹脚——又臭又长的故事。毕竟我自己也时时回顾这段经历,它有如晨钟暮鼓。

    2023年04月09日
    浏览(42)
  • 大语言模型初学者指南 (2023)

    大语言模型 (LLM) 是深度学习的一个子集,它正在彻底改变自然语言处理领域。它们是功能强大的通用语言模型,可以针对大量数据进行预训练,然后针对特定任务进行微调。这使得LLM能够拥有大量的一般数据。如果一个人想将LLM用于特定目的,他们可以简单地根据各自的目的

    2024年02月11日
    浏览(67)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包