楼主: sssyunsheng
13371 25

[程序分享] R与抓取豆瓣电影2000-2015年数据 [推广有奖]

  • 2关注
  • 47粉丝

已卖:107份资源

博士生

52%

还不是VIP/贵宾

-

威望
0
论坛币
3 个
通用积分
4.4708
学术水平
47 点
热心指数
49 点
信用等级
43 点
经验
5127 点
帖子
201
精华
0
在线时间
306 小时
注册时间
2012-2-21
最后登录
2025-9-22

楼主
sssyunsheng 在职认证  发表于 2015-6-7 09:04:25 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

最近发了份电影的评论,发表了一些浅见,今天特地整理了一下文中电影数据的来源,给缺乏动手能力的童鞋参考参考。《“大数据”评评2015年国产电影》文运用到2000到2015年豆瓣共47000部电影数据。

先说说怎么抓取数据吧。

首先一起看看豆瓣这个网址http://www.**.com/tag/2000/movie?start=0,有两个数字要注意一下,2000指的是2000年的意思,0代表的是第0部电影。我们在爬取其他年份的数据时,除了这两个数据外,其他的部分都是固定不变的。

这里需要用到XML包和数据整理包plyr包,用readLines函数抓取网页源码:

  1. library(XML)
  2. library(plyr)
  3. url<-'http://www.**.com/tag/2000/movie?start=0' #记得修改年份
  4. web <- readLines(url,encoding="UTF-8")
  5. system.time(for(i in 1:147){
  6.   Sys.sleep(sample(15:20, 1))
  7.   url1<-paste('http://www.**.com/tag/2000/movie?start=',15*i,sep="")#记得修改年份
  8.   web1 <- readLines(url1,encoding="UTF-8")
  9.   web<-c(web,web1)
  10.   label <- i
  11. })
  12. web2000 <-web
  13. webtotal <- c(web2000, web2001)#将读取的年份合并为一个
  14. save(webtotal, file = "webtotal.Rdata")#保存
复制代码

经亲测,发现当爬取的页面超过100页时,豆瓣会封IP。所以如果要爬取的数据量比较大的话,尽量每爬100页就换一次IP地址,实在懒得去换的话,可以分几次去爬。另外,如果不小心被封了IP也不用担心,第二天就会解封的。

把数据爬下来后已经成功了一半了(木有错,就是这么几行代码),然后我们要用正则表达式把我们感兴趣的内容抓出来(方法不分高低,使用就行嘿嘿),不知道什么是正则表达式的百度一下。

首先,我们要找出我们感兴趣的数据附近都有什么标志符。如电影名附近:<a href="http://movie.**.com/subject/1292402/?from=tag_all" class="title" target="_blank">西西里的美丽传说 Malèna</a> ,除了电影名称外,其他如评分,评价人数,电影属性(电影属性包括导演、演员、国家、日期)等就在电影名称所在行的下面。需要注意的是,有些电影并没有评分数据,或者没有评论人数。如果先把电影名全部提取,再提取评分,我们会发现,数据错位了,无法将名称和评分绑定在一起,速7的评分可能就对上了大话天仙(还记得2014年的国产lan片吗)的评分。观察一下我们发现大约每部电影的信息共占有12行。因此,我们首先要把每一部电影相关的行全部抓取出来,放在list的同一个值内。

  1. temp1 <- grep('class="title" target="_blank"',webtotal)
  2. film <- list()#将电影相关信息放在一起,以免单独提取导致信息错位,比如有些电影没有评分
  3. for (i in (1: length(temp1))) {
  4.   film[i] <- list(webtotal[temp1[i]:(temp1[i] + 12)])
  5. }#信息放在filmlist中
复制代码

这样list值的编码就代表一部电影,而且电影相关的所有数据都在这个值内。

下面我们就可以逐个提取信息了。

首先是电影名称:

  1. #提取电影名称
  2. name <- webtotal[grep('class="title" target="_blank">',webtotal)]#提取含有电影名称的行,一般电影都有名称,笑话
  3. mname <- list()
  4. for (i in (1: length(name))) {
  5.   y <- regexpr('>.{1,200}<', name[i], TRUE)#返回的结果为模式之前的字符数和模式的长度
  6.   z <- y + attr(y, "match.length")-1
  7.   mname[i] <- substr(name[i], y+1, z-1)#提取y,z之间的字符
  8. }
  9. name <-unlist(mname)
复制代码

regexpr函数很有用,它返回的是模式之前有多少个字符和模式本身有多长,我们要的电影名称就在>十二公民<尖嘴符号之间,这样我们根据它返回的数字就可以用substr函数到电影名称所在行提起电影名称了,substr提取字符串两个参数之间的字符,最后我们将电影名称放在了name向量中。

其次提取电影评分:

  1. #提取评分
  2. pingfen <- list()
  3. for (i in (1: length(film))) {
  4.   x <- unlist(film[i])
  5.   if (length(x[grep('span class="rating_nums"',x)]) == 0)
  6.     pingfen[i] <- ""
  7.   else pingfen[i] <- x[grep('span class="rating_nums"',x)]
  8. }#提取含有评分的部分,并保证没有评分的电影该部分赋值为""
  9. score <- list()
  10. for (i in (1: length(pingfen))) {
  11.   y <- regexpr('>.{1,10}<', pingfen[i], TRUE)#返回的结果为模式之前的字符数和模式的长度
  12.   z <- y + attr(y, "match.length")-1
  13.   score[i] <- substr(pingfen[i], y+1, z-1)#提取y,z之间的字符
  14. }#提取评分
  15. score <- as.numeric(unlist(score))
  16. filmData <- data.frame(name, score, stringsAsFactors = F)
复制代码

并非每一部电影都有评分,有些电影由于评价人数很低或没有人评价,就没有评分,我们首先需要将每一部电影包含评分的那一行从film中提取出来,如果某部电影缺少这一行,我们就给他赋个个空值占位,这样我们就保证了电影名称和评分可以对应在一起。然后在提取评分,提取评分和提取名称用到的函数一样,不在赘述。

然后是提取评论人数,过程和方法同提取评分一样:

  1. #提取评价人数
  2. renshu <- list()
  3. for (i in (1: length(film))) {
  4.   x <- unlist(film[i])
  5.   if (length(x[grep('span class="rating_nums"',x)]) == 0)
  6.     renshu[i] <- ""
  7.   else renshu[i] <- x[grep('span class="rating_nums"',x) + 1]
  8. }#提取含有评价人数,并保证没有评分的电影该部分赋值为""
  9. person <- list()
  10. for (i in (1: length(renshu))) {
  11.   y <- regexpr('>.{1,10}人', renshu[i], TRUE)#返回的结果为模式之前的字符数和模式的长度
  12.   z <- y + attr(y, "match.length")-1
  13.   person[i] <- substr(renshu[i], y+1, z-1)#提取y,z之间的字符
  14. }#提取评价人数
  15. person <- as.numeric(unlist(person))
  16. filmData <- data.frame(filmData, person, stringsAsFactors = F)
复制代码

最后提取电影属性行:

  1. ###提取电影属性###
  2. filmAttri <- list()
  3. for (i in (1: length(film))) {
  4.   x <- unlist(film[i])
  5.   if (length(x[grep('<div class="desc">',x) + 1]) > 0)
  6.     filmAttri[i] <- x[grep('<div class="desc">',x) + 1]
  7.   else filmAttri[i] <- ""
  8. }#提取含有评分的部分,并保证没有评分的电影该部分赋值为""
  9. filmAttri <- gsub(" ", "", filmAttri)#去除前面的空格
  10. filmData <- data.frame(filmData, filmAttri, stringsAsFactors = F)
  11. filmData <- filmData[!duplicated(filmData[,c(1,3)]),]#如果一部电影名称,演员,产地,时间,分类均相同我们认为是重复记录,否则不为重复
  12. id <- seq(1:length(filmData[,1]))
  13. filmData <- data.frame(id, filmData)
  14. #write.csv(filmData, "filmData.csv")
复制代码

电影属性行独立一行,所以为我么省了很多麻烦,最后提取完成之后,要进行一次去重,因为同一部电影可能被豆瓣贴上不同年份的标签,但是不要只对电影名称去重,因为电影名称相同可能仍然是不同的电影,所以只有电影的属性也相同时才认为是重复。

到这里我们就提取了电影的所有数据,但是要做分析还是有点欠火候,我们需要处理电影属性,分离出年份、国家、类别、导演、演员等,处理方法我们将在另外一篇文章中解释,期盼高手指正。

关于我们

关注理性与文艺,用数据创作内容性的精致阅读。关注请加微信公众号:dayinrushuang或扫描下方二维码,如果你也有将技术写成故事的冲动,欢迎加入我们

qrcode_for_gh_89f96c48034b_258.jpg

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:豆瓣电影 Library BRARY Start Lines 数据抓取 豆瓣

qrcode_for_gh_89f96c48034b_258.jpg (27.99 KB)

qrcode_for_gh_89f96c48034b_258.jpg

已有 6 人评分经验 论坛币 学术水平 热心指数 信用等级 收起 理由
李会超 + 80 + 60 精彩帖子
jameschin007 + 5 + 5 + 5 精彩帖子
Nicolle + 40 + 40 精彩帖子
日新少年 + 2 + 2 + 2 精彩帖子
fantuanxiaot + 30 + 1 + 1 + 1 精彩帖子
kychan + 100 + 1 + 1 + 1 奖励积极上传好的资料

总评分: 经验 + 250  论坛币 + 100  学术水平 + 9  热心指数 + 9  信用等级 + 9   查看全部评分

本帖被以下文库推荐

沙发
a443115637 发表于 2015-6-7 10:50:20
顶一下

藤椅
godback009 发表于 2015-6-7 10:53:26
学习了。。。{:3_59:}

板凳
亚米UM 发表于 2015-6-7 15:01:00
楼主 提取数据的那一段的web表示的是什么?不是有一个Web1了么

报纸
亚米UM 发表于 2015-6-7 17:51:38
看了一下午 学习了一下 楼主的代码里有两个小问题:
1.在抓取数据的时候,web1是每一页的源信息,但是我们要将所有页面的都保存下来,所以要存放在web里面,这才有了web <- c(web,web1) 楼主应该是漏给web赋值了 只要Web <- "" 就行

2.有一段用list代表电影信息的时候代码有点错误,应该如下
film = list()
for ( i in (1:length(temp1)))
{
  film1 <- list(web[temp1[i]:(temp1[i]+12)])
  film <- c(film,film1)
}
length(film)

3.感谢楼主的分享,我也是入门的。

地板
Nicolle 学生认证  发表于 2015-6-7 21:35:27
提示: 作者被禁止或删除 内容自动屏蔽

7
sssyunsheng 在职认证  发表于 2015-6-7 22:08:24
多谢各位的参与,由于我们这是一整套项目,从抓取数据,数据整形到入库分析等等,写文章只是提取了一小部分,所以匆忙成文难免有些遗漏指出,其中两个点已经由@亚米UM指出,以后会注意的,如果感兴趣可以加微信讨论,不仅仅是技术

8
auirzxp 学生认证  发表于 2015-6-8 03:53:50
提示: 作者被禁止或删除 内容自动屏蔽

9
qwe369 发表于 2015-6-13 04:08:38
非常好,谢谢分享

10
泡菜稀饭 发表于 2015-6-15 12:19:44
关注微信,多多学习

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2025-12-29 01:30