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

news2025/1/22 15:55:53

1.网络爬虫

1.1 什么是网络爬虫


网络爬虫(web crawler),也被称为网络蜘蛛(web spider),是在万维网浏览网页并按照一定规则提取信息的脚本或者程序。
浏览网页时,一般流程如下:
在这里插入图片描述

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

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结束位置(包含)

在这里插入图片描述

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布尔值,不清楚

在这里插入图片描述
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

在这里插入图片描述

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

在这里插入图片描述
可以使用Reduce()函数对cont_total进行行合并(rbind)操作,这样大大优化了代码:

tl <- Reduce(rbind,cont_total)
tl

参考资料:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/414109.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++语法(17)---- 二叉搜索树

1.概念 1.父节点的左子树全小于本身 2.父节点的右子树全大于本身 3.左右子树也是二叉搜索树 时间复杂度&#xff1a;O(N)&#xff0c;有可能只有左数&#xff0c;这样就遍历了所有&#xff0c;所有复杂度为N 平衡二叉树的时间复杂度才是&#xff1a;O(logN) 2.模拟 1.数据元素…

Postman抓包教程

目录 什么是抓包&#xff1f; 如何使用 Postman 进行抓包 查看历史抓包数据 使用抓包数据进行接口测试和开发 抓包技巧和注意事项 什么是抓包&#xff1f; 在计算机网络中&#xff0c;抓包是指捕获网络流量的过程。抓包工具可以截获进出计算机网络的数据流&#xff0c;并将…

反向传播推导+numpy实现

很久没有看深度学习了&#xff0c;忘了好多东西。本来想着推导一下&#xff0c;后来发现自己不会了。 再看看以前写的代码&#xff0c;又避开了最终的东西&#xff0c;于是决定重新推导一下。 数据的说明 首先&#xff0c;我们要做一个回归的任务&#xff0c;我们使用numpy随…

5.Java循环控制语句

Java循环控制语句 循环是Java中应用最为广泛的一个知识点&#xff0c;所以也是很需要掌握的。所谓循环&#xff0c;即通过判断条件&#xff0c;重复执行一段代码&#xff0c;根据条件的变化&#xff0c;来确定代码是否执行&#xff0c;执行次数。 一、循环结构 1、while循环…

Java IO常用操作详解(代码示例)

概览 Java I/O操作指的是数据的输入/输出操作。 Java的I/O操作类在java.io包中&#xff0c;主要分以下几种&#xff1a; 基于字节操作的I/O接口&#xff1a; InputStream和OutputStream基于字符操作的I/O接口&#xff1a; Writer和Reader基于磁盘操作的I/O接口&#xff1a; …

5个令人惊艳的AI项目,开源了。。

大家好&#xff0c;我是 Jack。 今天清明&#xff0c;小伙伴们都去哪里玩了&#xff1f; 上个月我已经出去浪过了&#xff0c;清明就老实在家歇着了。 翻看了一些最近热点的开源项目&#xff0c;发现还是 AIGC 的天下。 今天&#xff0c;我将继续着重挑选几个近期的优质开源…

2023第十四届蓝桥杯C++B组菜鸡的落幕

时隔几天&#xff0c;终于还是忍不住来复盘一下蓝桥杯了&#xff0c;还记得去年参加做下填空&#xff0c;再做对个把编程&#xff0c;后面不会的大题打打表混混分&#xff0c;最后就能混个省奖&#xff0c; 这回估计凉透了,填空没对似乎&#xff0c;编程也没对几个&#xff0c;…

Kettle8.2.0连接Hive3.1.2(踩坑,亲测有效)

这是目前遇到的最简单但最头疼的安装&#xff0c;因为是在公司之前用过的服务器上进行安装测试&#xff0c;加上又使用比较新的版本&#xff0c;结果踩了不少坑。Kettle连接Hive这个坑&#xff0c;从2023年4月11日下午开始&#xff0c;一致到2023年4月12日中午才弄好&#xff0…

uni-app常用配置

保存自动格式化 工具》设置》编辑器设置》保存时自动格式化 JS语法检查 安装eslint-js插件eslint-js - DCloud 插件市场 用于校验js和html中的js代码https://ext.dcloud.net.cn/plugin?id2037工具》设置》插件配置》eslint-js 启用实时校检 Vue语法检查 安装eslint-vue插…

【星界探索——通信卫星】铱星:从“星光坠落”到“涅槃重生”,万字长文分析铱星卫星系统市场

【星界探索——通信卫星】铱星&#xff1a;从“星光坠落”到“涅槃重生”一、铱星简介二、铱星系统设计思路2.1 工作原理2.2 铱星布局三、铱星优势四、发展历程五、第一代铱星公司的破产原因分析5.1 终端和资费价格高昂&#xff0c;市场用户群体小5.2 财务危机5.3 市场分析不足…

一文吃透低代码平台源代码交付的重要性(避坑指南)

一、前言 作为这两年IT界的风口&#xff0c;低代码在众人眼里已经不是什么陌生的概念。 对标于传统的纯代码开发&#xff0c;低代码是一种快速开发软件&#xff08;应用程序&#xff09;的方法&#xff0c;平台通过对大量功能与场景做提前封装&#xff0c;使得用户可以在可视…

MySQL开发05-MySQL开发规范

文章目录1、命名规范2、表设计规范3、索引规范4、SQL语句规范5、SQL脚本规范6、数据架构规范7、配置文件建议8、其他规范9、总结1、命名规范 命名应有意义&#xff0c;包括库名、表名、用户名等&#xff0c;以使用方便记忆、描述性强的可读性名称为第一准则&#xff0c;尽量避…

Docker网络案例

bridge 是什么 Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机…

C#基础复习

语句 目录 语句 switch&#xff1a; 跳转语句 标签语句 标签&#xff1a; 标签语句的作用域 goto语句 using 语句 资源的包装使用 using 语句示例&#xff1a; 多个资源和嵌套 语句是描述某个类型或让程序执行某个动作的源代码指令 块在语法上算作一个单条嵌入语句。任何语…

【cmake学习】搭建一个简单的cmake工程(初级版)

目录 1、工程框架介绍 2、编写CMakeLists.txt (1) 限制cmake最低版本、工程命名 (2) 引入头文件目录 (3) 引入库目录&#xff08;可选&#xff09; (4) 引入源文件 (5) 生成可执行文件 / 生成动静态库 (6) 链接库文件&#xff08;可选&#xff09; 3、完整CMakeLists…

uefi 内存管理

PEI 阶段 PEI 阶段最为重要的结构是HOB, 初始化内存服务前&#xff0c;PEI 申请的内存其实是插入到FV 文件 也就是FLASH 里面去运行。 在此状态下&#xff0c;FLASH 可读不可写&#xff0c;所以是不能使用全局变量的。如果有需要模块间共享信息&#xff0c;需要申请HOB. HO…

gtkmm给组件添加css

设置方式 使用CSS分为两步&#xff0c;1:为组件设这css名称&#xff0c;2:加载样式表。 样式表我们写在文件中就行&#xff08;似乎也可以从字符串加载&#xff0c;不过不推荐&#xff09;。 1. 设置css名称 使用gtk的接口&#xff1a;gtk_widget_class_set_css_name()。 这…

rk3568点亮E-ink

rk3568 Android11/12 适配 E-ink “EINK”是英语ElectronicInk的缩写。翻译成中文为“电子墨水”。电子墨水由数百万个微胶囊(Microcapsules)所构成&#xff0c;微胶囊的大小约等同于人类头发的直径。每个微胶囊里含有电泳粒子──带负电荷的白色以及带正电荷的黑色粒子&#…

Ubuntu 交叉编译Windows 版本的ffmpeg最佳实践

之前介绍在Windows上采用msys2+minGW或者cygwin在Windows编译方法。很多读者觉得在Windows搭建一个类Linux比较麻烦或者说方法不够通用,本文就介绍在流行的Linux发行版Ubuntu上编译window版本的ffmpeg。即介绍一种通用办法来编译Windows版本ffmpeg,该方法可以推广到android,…

算法 贪心4 || 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球

860.柠檬水找零 很简单的一题&#xff0c;完全是常识题 class Solution { public:bool lemonadeChange(vector<int>& bills) {unordered_map<int,int> map;for(int i 0; i < bills.size(); i){map[bills[i]];if(bills[i] ! 5){if(map[5] 0) return fals…