Tian chi

⚠️版权声明:文章可以转载,但请注明文章来源:http://itanch.github.io/

  • 主页
  • 技术
  • 记录
所有文章 友链 关于我

Tian chi

⚠️版权声明:文章可以转载,但请注明文章来源:http://itanch.github.io/

  • 主页
  • 技术
  • 记录

豆瓣电影Top250获取

2015-08-29

豆瓣API说明

豆瓣为开发者提供了用于应用开发的Api接口,通过这些Api接口可以获得豆瓣的部分内容。

豆瓣Api V2认证使用了OAuth2,使得用户的授权过程更为安全,返回数据的格式为json,便于应用开发者解析获得的数据。豆瓣没有提供官方的SDK,但是提供了其他非官方的基于多种语言的SDK,我们采用了Java语言的SDK。由于该版本的Java SDK基于较早的豆瓣API的v1版本,所以需要进行部分修改适应新的v2版本,其中我们修改了电影相关的代码(新的源代码)。

Java SDK为Maven工程,可以使用Maven编译打包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
mvn package -Dmaven.test.skip=true
```
为了将所有依赖一起打包进去,我们使用了fatjar工具进行打包,生成可以调用的函数库([jar](https://github.com/ITanCh/Douban-Java-SDK-OAuth2/raw/origin/Douban-Java-SDK-OAuth2-origin_fat.jar))。
<!--more-->
### API使用
#### 相关库
```java
import com.dongxuexidu.douban4j.model.app.AccessToken;
import com.dongxuexidu.douban4j.model.app.DoubanException;
import com.dongxuexidu.douban4j.model.app.RequestGrantScope;
import com.dongxuexidu.douban4j.model.v2.DoubanCastObject;
import com.dongxuexidu.douban4j.model.v2.DoubanDirectorObj;
import com.dongxuexidu.douban4j.model.v2.DoubanSubjectListObj;
import com.dongxuexidu.douban4j.model.v2.DoubanSubjectObj;
import com.dongxuexidu.douban4j.playground.BrowserLauncher;
import com.dongxuexidu.douban4j.playground.PlayGround;
import com.dongxuexidu.douban4j.provider.OAuthDoubanProvider;
import com.dongxuexidu.douban4j.service.DoubanBookMovieMusicService;
```
#### AccessToken获取
通过豆瓣API获取用户相关的信息时需要获取AccessToken,在Java中可以实现如下:
```java
public static String testAccessToken() {
try {
OAuthDoubanProvider oauth = new OAuthDoubanProvider();
oauth.setApiKey("your api key").setSecretKey(
"your secret key");
oauth.addScope(RequestGrantScope.BASIC_COMMON_SCOPE)
.addScope(RequestGrantScope.SHUO_READ_SCOPE)
.addScope(RequestGrantScope.SHUO_WRITE_SCOPE)
.addScope(RequestGrantScope.BASIC_NOTE_SCOPE)
.addScope(RequestGrantScope.BOOK_READ_SCOPE)
.addScope(RequestGrantScope.EVENT_READ_SCOPE)
.addScope(RequestGrantScope.EVENT_WRITE_SCOPE)
.addScope(RequestGrantScope.MAIL_READ_SCOPE)
.addScope(RequestGrantScope.MAIL_WRITE_SCOPE)
.addScope(RequestGrantScope.MOVIE_READ_SCOPE)
.addScope(RequestGrantScope.MUSIC_READ_SCOPE);
oauth.setRedirectUrl("http://www.liutianchi.com");
BrowserLauncher.openURL(oauth.getGetCodeRedirectUrl());
System.out.println(oauth.getGetCodeRedirectUrl());
System.out.print("Put the code you got here.[Enter]:");
BufferedReader br = new BufferedReader(new InputStreamReader(
System.in));
String code = br.readLine();
System.out.println("code : " + code);
AccessToken at = oauth.tradeAccessTokenWithCode(code);
System.out.println("at : " + at.getAccessToken());
System.out.println("uid : " + at.getDoubanUserId());
return at.getAccessToken();
} catch (DoubanException ex) {
Logger.getLogger(PlayGround.class.getName()).log(Level.SEVERE,
null, ex);
return null;
} catch (IOException ex) {
Logger.getLogger(PlayGround.class.getName()).log(Level.SEVERE,
null, ex);
return null;
}
}
```
获取电影Top250的基本信息不涉及用户内容,所以不必获取AccessToken。
#### 获取Top250电影ID
虽然豆瓣提供了获取Top250的API:

/v2/movie/top250

1
2
但是,通过上述方法获取的电影信息为简单内容,其中演员数为3,无电影的国家信息,无电影内容简介。这些内容无法达到我们数据分析的目的,所以我们首先统计出Top250的ID,然后使用如下API获取每一部电影的详细信息:

/v2/movie/subject/:id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
豆瓣限制了一次获取Top250的电影数目最大为100,所以需要进行3次请求。代码实现如下:
```java
public static void getTop250ID() {
DoubanBookMovieMusicService instance = new DoubanBookMovieMusicService();
DoubanSubjectListObj results = null;
try {
File dirFile = new File(FILEPATH);
dirFile.mkdirs();
File idFile = new File(dirFile, "movie_id");
if (!idFile.exists())
idFile.createNewFile();
BufferedWriter out = new BufferedWriter(new FileWriter(idFile,
false));
int start = 0;
while (start < 300) {
boolean flag = true;
while (flag) {
try {
results = instance.getMoviesTop250(start, 100);
flag = false;
} catch (NoHttpResponseException e) {
System.out.println("NoHttpResponseException");
Thread.sleep(1000);
}
}
List<DoubanSubjectObj> movieList = results.getSubjects();
for (DoubanSubjectObj result : movieList) {
out.write(result.getId());
out.newLine();
}
start += 100;
Thread.sleep(1000);
}
out.write("#");
out.flush();
out.close();
} catch (DoubanException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
```
如下所示为Top250的部分ID:
1292052
1295644
1292720
1291546
1292063
1292001
1295124
1291561
#### 获取每一部电影的信息
代码实现如下:
```java
public static void getTop250Info() {
File dirFile = new File(FILEPATH);
File idFile = new File(dirFile, "movie_id");
if (!idFile.exists()) {
System.err.println("movie id file not exist!");
return;
}
LinkedHashSet<String> castSet = new LinkedHashSet<>();
LinkedHashSet<String> dirSet = new LinkedHashSet<>();
BufferedWriter writer;
BufferedReader reader;
try {
File mvFile = new File(dirFile, "movie_info");
if (!mvFile.exists())
mvFile.createNewFile();
writer = new BufferedWriter(new FileWriter(mvFile, false));
reader = new BufferedReader(new FileReader(idFile));
DoubanBookMovieMusicService instance = new DoubanBookMovieMusicService();
DoubanSubjectObj result = null;
String id = "";
int count = 0;
while (true) {
id = reader.readLine();
if (id == null || id.equals("#"))
break;
count++;
System.out.println(count + ": " + id);
long l = Long.parseLong(id);
boolean flag = true;
while (flag) {
try {
result = instance.getV2MovieInfoById(l);
flag = false;
} catch (NoHttpResponseException | SocketTimeoutException e) {
System.out.println("NoHttpResponseException");
Thread.sleep(2000);
}
}
writer.write(result.getId() + " ");
writer.write(result.getTitle() + " ");
writer.write(result.getRating().getAverage() + " ");
List<DoubanCastObject> castList = result.getCasts();
boolean first = true;
for (DoubanCastObject cast : castList) {
if (!first)
writer.write("#");
writer.write(cast.getId());
castSet.add(cast.getId());
first = false;
}
writer.write(" ");
List<DoubanDirectorObj> dirList = result.getDirectors();
first = true;
for (DoubanDirectorObj dir : dirList) {
if (!first)
writer.write("#");
writer.write(dir.getId());
dirSet.add(dir.getId());
first = false;
}
writer.write(" ");
List<String> strList = result.getCountries();
first = true;
for (String str : strList) {
if (!first)
writer.write("#");
writer.write(str);
first = false;
}
writer.write(" ");
strList = result.getGenres();
first = true;
for (String str : strList) {
if (!first)
writer.write("#");
writer.write(str);
first = false;
}
writer.write(" " + result.getYear());
writer.newLine();
writer.flush();
Thread.sleep(3000);
}
reader.close();
writer.close();
System.out.println("Get movie !");
File castIdFile = new File(dirFile, "cast_id");
if (!castIdFile.exists())
castIdFile.createNewFile();
BufferedWriter castIdWriter = new BufferedWriter(new FileWriter(
castIdFile, true));
Iterator<String> it = castSet.iterator();
while (it.hasNext()) {
castIdWriter.write(it.next());
castIdWriter.newLine();
}
castIdWriter.write("#");
castIdWriter.flush();
castIdWriter.close();
File dirIdFile = new File(dirFile, "dir_id");
if (!dirIdFile.exists())
dirIdFile.createNewFile();
BufferedWriter dirIdWriter = new BufferedWriter(new FileWriter(
dirIdFile, true));
it = dirSet.iterator();
while (it.hasNext()) {
dirIdWriter.write(it.next());
dirIdWriter.newLine();
}
dirIdWriter.write("#");
dirIdWriter.flush();
dirIdWriter.close();
} catch (IOException | DoubanException | InterruptedException e) {
e.printStackTrace();
}
}

在获取电影信息时,我们同时利用哈希集统计了演员的ID和导演的ID,目的是为了进一步统计影人的具体信息。

在这里需要注意的是,豆瓣为了防止恶意访问,对每分钟请求的次数进行了限制,官方文档说为40次/分钟,经过实验发现,这个时间并不准确,最后我们采用3s一次的请求进行了连续的访问。如果请求次数过度频繁,则会出现警告页面,同时导致在该IP下若干小时内无法继续访问。

最后获取的电影信息部分结果如下所示(id,名称,平分,演员id集合,导演id集合,国家,标签集合,发行年份):

1292052 肖申克的救赎 9.6 1054521#1054534#1041179#1000095 1047973 美国 犯罪#剧情 1994
1295644 这个杀手不太冷 9.4 1025182#1054454#1010507#1019050 1031876 法国 剧情#动作#犯罪 1994
1292720 阿甘正传 9.4 1054450#1002676#1031848#1031912 1053564 美国 剧情#爱情 1994
1291546 霸王别姬 9.4 1003494#1050265#1035641#1000905 1023040 中国大陆#香港 剧情#爱情#同性 1993
1292063 美丽人生 9.4 1041004#1000375#1000368#1082051 1041004 意大利 剧情#战争 1997
1292001 海上钢琴师 9.2 1025176#1010659#1027407#1009391 1018983 意大利 剧情#音乐 1998
1295124 辛德勒的名单 9.4 1031220#1054393#1006956#1041165 1054440 美国 剧情#历史#战争 1993
1291561 千与千寻 9.2 1023337#1005438#1045797#1025558 1054439 日本 剧情#动画#奇幻 2001
2131459 机器人总动员 9.3 1009535#1000389#1018022#1049585 1036450 美国 喜剧#爱情#科幻 2008
1292722 泰坦尼克号 9.1 1041029#1054446#1031864#1010555 1022571 美国 剧情#爱情#灾难 1997
3541415 盗梦空间 9.2 1041029#1101703#1012520#1027181 1054524 美国#英国 剧情#动作#科幻 2010
3793023 三傻大闹宝莱坞 9.1 1031931#1049635#1018290#1032430 1286677 印度 剧情#喜剧#爱情 2009  

其中所有的演员和导演的信息用豆瓣赋予的ID表示,ID是豆瓣采用的唯一标示影人的序号。由于豆瓣提供的电影信息内容不完全规范,同一个影人可能在不同电影中使用了不同的名字,例如名字拼写、翻译不同,所以采用ID而不是影人的名字来进行数据分析。

获取影人信息

因为需要对男女演员进行分别统计,所以我们对影人的详细信息又进行了获取,代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public static void getCastInfo() {
File dirFile = new File(FILEPATH);
File idFile = new File(dirFile, "dir_id");
if (!idFile.exists()) {
System.err.println("cast id file not exist!");
return;
}
BufferedWriter writer;
BufferedReader reader;
try {
File infoFile = new File(dirFile, "dir_info");
if (!infoFile.exists())
infoFile.createNewFile();
writer = new BufferedWriter(new FileWriter(infoFile, false));
reader = new BufferedReader(new FileReader(idFile));
DoubanBookMovieMusicService instance = new DoubanBookMovieMusicService();
DoubanCastObject result = null;
String id = "";
int count = 0;
while (true) {
id = reader.readLine();
if (id == null || id.equals("#"))
break;
count++;
System.out.println(count + ": " + id);
boolean flag = true;
while (flag) {
try {
result = instance.getMoviesCast(id);
flag = false;
} catch (NoHttpResponseException | SocketTimeoutException e) {
System.out.println("NoHttpResponseException");
Thread.sleep(2000);
}
}
writer.write(result.getId() + " ");
writer.write(result.getName() + " ");
writer.write(result.getGender());
writer.newLine();
writer.flush();
Thread.sleep(4000);
}
reader.close();
writer.close();
System.out.println("Get movie !");
} catch (IOException | DoubanException | InterruptedException e) {
e.printStackTrace();
}
}

获取的部分演员信息如下(id,名字,性别):

1054521 蒂姆·罗宾斯 男
1054534 摩根·弗里曼 男
1041179 鲍勃·冈顿 男
1000095 威廉姆·赛德勒 男
1025182 让·雷诺 男
1054454 娜塔莉·波特曼 女
1010507 加里·奥德曼 男
1019050 丹尼·爱罗 男
1054450 汤姆·汉克斯 男
1002676 罗宾·怀特 女
1031848 加里·西尼斯 男
1031912 麦凯尔泰·威廉逊 男
1003494 张国荣 男
1050265 张丰毅 男
1035641 巩俐 女

获取的导演信息如下:

1047973 弗兰克·德拉邦特 男
1031876 吕克·贝松 男
1053564 罗伯特·泽米吉斯 男
1023040 陈凯歌 男
1041004 罗伯托·贝尼尼 男
1018983 朱塞佩·托纳多雷 男
1054440 史蒂文·斯皮尔伯格 男
1054439 宫崎骏 男  

数据完善

需要注意的是,获取的源数据形式并不规范,影人的名字格式多样,有的影人没有性别信息,所以对源数据进行过滤修正。

  • 技术
  • 豆瓣
  • 电影

扫一扫,分享到微信

微信分享二维码
slurm安装
Torque安装笔记(多ubuntu节点)
  1. 1. 豆瓣API说明
    1. 1.1. 获取影人信息
    2. 1.2. 数据完善
© 2017 Tian chi
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • Java
  • 技术
  • 云
  • 记录
  • Android
  • 设计模式
  • AngularJS
  • Yeoman
  • JavaScript
  • java
  • git
  • 架构
  • MESOS
  • ubuntu
  • MooseFS
  • Netty
  • Torque
  • Cocos2d-x
  • eclipse
  • docker
  • kubernetes
  • spring
  • slurm
  • React Native
  • 豆瓣
  • 电影

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 友情链接1
  • 友情链接2
  • 友情链接3
  • 友情链接4
  • 友情链接5
  • 友情链接6
计算机界的一个小学生