电商评论数据爬取--R语言

1.网络爬虫

1.1 什么是网络爬虫


网络爬虫(web crawler),也被称为网络蜘蛛(web spider),是在万维网浏览网页并按照一定规则提取信息的脚本或者程序。
浏览网页时,一般流程如下:
电商评论数据爬取--R语言_第1张图片

利用网络爬虫爬取信息就是模拟这个过程.用脚本模仿浏览器,向网站服务器发出浏览网页内容的请求,在服务器检验成功后,返回网页的信息,然后解析网页并提取需要的数据,最后将提取得到的数据保存即可。

1.2 为什么要学习网络爬虫

在数据量爆发式增长的互联网时代,网站与用户的沟通本质上是数据的交换:搜索引擎从数据库中提取搜索结果,将其展现在用户面前;电商将产品的描述、价格展现在网站上,以供买家选择心仪的产品;社交媒体在用户生态圈的自我交互下产生大量文本、图片和视频数据等。这些数据如果得以分析利用,不仅能够帮助第一方企业(拥有这些数据的企业)做出更好的决策,对于第三方企业也是有益的。而网络爬虫技术,则是大数据分析领域的第一个环节。

1.3 能从网络上爬取哪些数据

简单来说,平时在浏览网站时,所有能见到的数据都可以通过爬虫程序保存下来。从社交媒体的每一条发帖到团购网站的价格及点评,再到招聘网站的招聘信息,这些数据都可以存储下来。

1.4 网络爬虫存在的风险

网络爬虫这个名字虽然能够形象地描述这项技术,但是有关爬虫的利弊确实存在很多质疑。从目前的情况来看,如果抓取的数据属于个人使用或科研范畴,基本不存在问题;而如果数据属于商业盈利范畴,就要就事而论,有可能属于违法行为,也有可能不违法。 爬虫频繁地访问网站会导致该网站的资源被占用,甚至用户的个人信息和商业信息都受到侵害。
爬虫技术可能存在以下风险:
1)由于大量占用爬取网站的资源,对爬取网站造成访问困难,严重影响网站的可用性;
2)网站敏感信息的获取是否造成不良后果;
3)违背网站爬取设置。

1.5 网络爬虫的技术流程


网络爬虫的流程其实非常简单,主要可以分为三部分:
(1)获取网页;
(2)解析网页(提取数据);
(3)存储数据

在这里插入图片描述

(1)获取网页就是向服务器发送请求,服务器会返回整个网页的数据。类似于在浏览器中键入网址并按回车键;
发起请求之后服务器会对请求进行检验:因为大量的爬虫请求会造成服务器压力过大,可能使得服务器响应速度变慢,影响网站的正常运行。所以网站一般会检验请求头里面的User-Agent(以下简称UA,相当于身份的识别)来判断发起请求的是不是机器人,而我们可以通过自己设置UA来进行简单伪装。在没有UA的伪装下,服务器很容易就能识别出对方是一只网络爬虫的,所以有些网站在发现请求来自网络爬虫时将直接拒绝请求。
(2)解析网页就是从整个网页的数据中提取想要的数据。类似于你在页面中想找到产品的价格,价格就是你要提取的数据;
(3)存储数据也很容易理解,就是把数据存储下来。我们可以存储在csv中,也可以存储在数据库中。

2. 找到评论数据

一般情况下,爬取某个网页数据时,会首先使用R语言获取某个网页的源代码,查看所需要的的数据是否可以通过解析源代码获取。评论数据无法通过解析网页源代码获取,操作步骤如下:

1) 下载Google Chrome 浏览器
2)找到【更多工具】--【开发者工具】
3)打开【Network】面板
4)单击网页中的【商品评价】选项
5)CTRL+R 加载所有资源
6)第一列显示所有请求的文件名,找到【size】降序排列,因为评论数据一般比较大
7) 找到【productPageComments.action?】商品评论
8)右键单击,选择【open in new tab】

即可打开评论数据

2. 获取并读取评论页面网页源码

2.1 获取评论页面网页源码

找到上述评论数据后将url复制下来即可。也可在【Header】下找到【Request URL】复制链接
在这里插入图片描述

2.2 下载单个页面评论数据

下载评论页面数据需要用到【RCurl】库中的【getURL】函数。

2.2.1 下载并载入【RCurl】库

# 安装
install.packages('RCurl')
# 载入
library(RCurl)

2.2.2 发起请求获取网页: getURL()函数

(1) 函数功能

提交请求并返回检索响应

(2) 函数语法
getURL(url, ..., .opts = list(),
        write = basicTextGatherer(.mapUnicode = .mapUnicode),
         curl = getCurlHandle(), async = length(url) > 1,
           .encoding = integer(), .mapUnicode = TRUE)
(3) 函数参数
参数 含义
url 网址链接
控制http请求的一些设置,如user-agent;没有完全理解该参数
.encodings 请求返回内容的编码格式

关于getURL函数“…”中的具体内容,没有找到相关完整资料,尚不理解。

url <- 'https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100010083789&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1'

# install.packages('RCurl')
library(RCurl)

header <- c("User-Agent"="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/
              537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
              "content-encoding"="gzip",   # 非必要
              "content-type"="application/json",    # 非必要
             "charset"="GBK")   # 非必要

tmp <- getURL(url, httpheader=header,.encoding='gbk')
tmp

通过httpheader传入浏览器UA,伪装成为浏览器。编码方式可以通过通过“content-type”中的取值查看。
这里我使用了GBK编码,但是出来依然是中文乱码,不清楚是不是跟返回结果是gzip压缩格式有关系。

为解决中文乱码问题,使用iconv函数转换字符编码格式

2.2.3 对获取的网页内容转码: iconv()函数

(1)函数功能

转换字符编码

(2)函数语法
iconv(x, from = "", to = "", sub = NA, mark = TRUE, toRaw = FALSE)
(3)函数参数
参数 含义
x 要转换的字符
from 字符的现有编码方式
to 字符的目标编码方式
sub 不能转换为目标编码的字符将默认以NA返回,若通过sub指定,则返回sub后指定的字符
tmp <- iconv(tmp,"gbk","utf-8" )
tmp

由于读取到的源码不是标准的JSON格式,因此将符合JSON格式的内容提取出来:

cont <- substr(tmp,nchar('fetchJSON_comment98')+2,nchar(tmp)-2)
cont

2.2.4 截取获取内容,使符合JSON格式: substr()函数

(1)函数功能

截取字符

(2)函数语法
substr(x, start, stop)
(3)函数参数
参数 含义
x 要截取的字符串
start 起始位置(包含)
stop 结束位置(包含)

电商评论数据爬取--R语言_第2张图片

2.2.5 将JSON格式内容转化为列表

使用jsonlite库中的fromJSON函数将获取的标准JSON格式的内容转化为R语言的列表形式:

library(jsonlite)
web1 <- jsonlite::fromJSON(cont)
web1
2.2.6 从列表中提取需要信息,以data.frame格式存储
# 取需要信息并转换成数据框形式
content <- data.frame(id=web1$comments$id,nickname=web1$comments$nickname,creationTime=web1$comments$creationTime,productColor=web1$comments$productColor,content=web1$comments$content)
content 

3. 循环爬取评论数据

要想实现循环爬取评论数据,顾名思义需要用到循环,包括URL与获取内容的保存两部分的循环

3.1 评论网址URL的特点

在这里插入图片描述

从上图可以看出,获取的评论数据以JSON格式存储,URL存在规律,https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100010083789&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1

“?”后面的为查询语句,每个参数之间均以“&”隔开,各查询参数说明如下:

参数名称 说明
productId 产品ID
score 评论类型,score=0表示获取全部评论,score=3表示获取好评,score=1表示获取差评
sortType 评论排序方式,按推荐排序(sortType=5)或时间排序(sortType=6)
page 表示评论页码,默认从0开始递增
pagesize 表示每页展示的评论量,默认为10

不同商品之间的主要不同在于"productId",同一商品不同页面的评论则可通过page参数实现

3.2 构建数据框存放商品不同评论页面的url

由于不同页面的评论只有page参数后面的内容不同,因此,构造不同页面的url如下:

3.2.1 构造空数据框

cont_url <- data.frame(matrix(NA,nrow=3,ncol=1))
names(cont_url) <- 'url'
cont_url

3.2.2 构造不同页面的url并放入数据框:paste0

for (i in 1:3){
  cont_url[i,1] <- paste0('https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100010083789&score=0&sortType=5&page=',i-1,'&pageSize=10&isShadowSku=0&fold=1')
}
cont_url
(1)函数功能

将参数转换为字符串并拼接在一起

(2)函数语法
paste (..., sep = " ", collapse = NULL, recycle0 = FALSE)
paste0(...,            collapse = NULL, recycle0 = FALSE)
(3)函数参数
参数 含义
需要拼接的R对象
sep 分隔拼接对象之间的字符,默认为空格
collapse 可选参数,如果为collapse指定了一个值,则结果中的值将被连接到一个字符串中,元素由collapse的值分隔。
recycle0 布尔值,不清楚

电商评论数据爬取--R语言_第3张图片
paste()函数默认以空格分隔连接的内容,而paste0()函数则在连接的内容中间不放空格,因此paste0()函数相当于paste()函数sep=“”,但是更高效。

a <- paste('a','b',1:2) # 默认以空格分隔
a

bb <- paste('a','b',1:2,sep="") # 指定拼接字符之间无空格
bb

dd <- paste0('a','b',1:2)
dd

电商评论数据爬取--R语言_第4张图片

3.3 循环提取评论

按照2.2下载单个页面评论数据的思路,下载每个页面的评论数据,并提取需要的内容组成数据框,之后将每页内容的数据框放在list列表中。

cont_total <- list()
for (i in 1:3){
  cont_each <- getURL(cont_url[i,1],httpheader=header,.encoding='gbk')
  #print(cont_each)
  cont_cheach <- iconv(cont_each,"gbk","utf-8" )
  cont_cheach
  cont_deal <- substr(cont_cheach,nchar('fetchJSON_comment98')+2,nchar(cont_cheach)-2)
  #print(cont_deal)
  cont_json <- jsonlite::fromJSON(cont_deal)
  #print(cont_json)
  cont_total[[i]] <- data.frame(id=cont_json$comments$id,nickname=cont_json$comments$nickname,creationtime=cont_json$comments$creationTime,
                               productcolor=cont_json$comments$productColor,content=cont_json$comments$content)
}

cont_total

3.4 将获取的评论数据放在一起:Reduce()函数

tl <- data.frame(matrix(NA,nrow=0,ncol=5))
names(tl) <- c('id','nickname','creationtime','productcolor','content')

for (i in 1:3){
  tl <- rbind(tl,cont_total[[i]])
}

tl

还可以使用更简单的累计合并函数Reduce()

(1)函数功能

实现给定向量元素的连续合并

(2)函数语法
Reduce(f, x, init, right = FALSE, accumulate = FALSE)
(3)函数参数
参数 含义
f 函数,对x执行的函数操作
x 执行操作的向量对象,实践表明可以是列表
init 初始值
right 逻辑值,函数操作从左向右执行(默认)还是从右向左执行
accumulate 逻辑值,是否显示每步累计操作结果,默认只显示最终操作结果
b <- Reduce(sum,c(1,2,3,4)) # 对向量中的内容进行sum函数操作,无初始值
b

d <- Reduce(sum,1:4,init=10) # 对向量中的内容进行sum函数操作,给定初始值10
d

e <- Reduce(sum,c(1,2,3,4),accumulate=TRUE) # 对向量中的内容进行sum函数操作,无初始值,显示每步结果
e

f <- Reduce(sum,c(1,2,3,4),init=10,accumulate=TRUE) # 对向量中的内容进行sum函数操作,给定初始值10,显示每步结果
f

电商评论数据爬取--R语言_第5张图片
可以使用Reduce()函数对cont_total进行行合并(rbind)操作,这样大大优化了代码:

tl <- Reduce(rbind,cont_total)
tl

参考资料:

  1. 唐松 Python网络爬虫从入门到实践(第2版)
  2. 李俊翰 大数据采集与爬虫
  3. 沈祥壮 Python数据分析入门:从数据获取到可视化

你可能感兴趣的:(r语言)