前情提要
前一篇文章中,我想明白了:使用 书名
搜索,得到的豆瓣返回结果集的第一个元素其实就是目标书的信息。于是,在这一篇文章中,我将调用豆瓣 API 得到借书记录中所有的书的读书标签,并生成相应的词云。
使用豆瓣 API 根据书名搜索书
搜索豆瓣 API,找到开发者文档。豆瓣的 API 看着很清晰,一下子就找到我需要的接口。看了一下,还可以限制返回数量,于是理所当然的,将 count
限制为 1
就获取第一条数据了。
使用 Postman 验证想法
在 Postman
中输入搜索 API,加上查询条件,发送请求,查看结果集。OK,正是我想要的。
查看 tags
对象,很好,不但有标签,还有类似权重之类的 count
,可能未来还有更多的用途,目前先不管它。
Javascript 代码实现获取所有 tag
写了段简单的 JS 代码,验证是否得到与 Postman
一致的结果。结果,出错了……
URL 编码问题
使用 Javascript 请求图书信息挺奇怪的,使用的 URL 跟 Postman 的是一样的,为什么会出错呢?
看了看错误信息,status_code 是 400,请求有问题?
这个请求里面只有 URL,那就是 URL 有问题。想了想,难道是因为 URL 中的中文吗?
试着把书名改为只有英文的 Java,嘿,成功了。
那么问题就在于中文编码了。
解决
网络上搜索了一下,发现使用 Javascript 发网络请求,需要使用 encodeURI
将中文编码之后才可以正常请求。
第一次遇到 URL 编码问题是大二,后面就陆陆续续遇到同样的问题。可是到现在我也没有彻底搞明白这个问题。为什么 URL 不能有中文呢?以后可能还会遇到同样的问题,得找个机会彻底搞明白。当然,这是后话,且按下不表。
简单地写完了获取所有 tag 的代码,截取了部分书名,作为测试数据。执行 node getTags.js
,成功获得数据。
速度限制
出错
将测试数据改为完整的书名列表,结果出现了错误。
很费解,看了一会儿之后,猜测是因为请求数量太多了,豆瓣把我的请求给禁掉了。
在 Postman
重新请求验证想法,发现如我所料。
{
"msg": "rate_limit_exceeded2: 43.243.12.21",
"code": 112,
"request": "GET /v2/book/search"
}
查了 豆瓣的 API 文档,发现,请求确实是有限制的。
我得到的错误信息是这个
rate_limit_exceeded 速度限制
解决方法
读书记录中的书名有两百多个,一次性发请求的话,肯定会超出限制。想了个方法,就是在每个请求前随机等待若干时间,这样或许可以避免豆瓣的请求限制。
最后的代码如下
const agent = require('superagent');
const async = require('async');
const bookTitleList = require('./book_title_list');
function sleep(milliseconds) {
let start = new Date().getTime();
for (let i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
function random_sleep(second) {
sleep(Math.floor((Math.random() * second) + 1) * 1000)
}
function requestTags(bookTitle, done) {
random_sleep(20);
agent.get(encodeURI(`https://api.douban.com/v2/book/search?q="${bookTitle}"&count=1`))
.end((err, res) => {
if (err) {
console.log(err);
} else {
const tag = res.body.books[0].tags;
done(null, tag);
}
}
);
}
async.map(bookTitleList, requestTags, (err, tags) => {
tags.forEach(tag => {
console.log(tag);
})
});
我还没有验证它是否可以正常工作,因为限制时间还没过呢……
网友评论