分析自己在大学期间读过的书(四)

前情提要

前一篇文章中,因为豆瓣的 API 请求限制,我无法一次性请求整个读书记录的信息列表,于是想到在每个请求前随机等待若干时间,以避免豆瓣的请求限制。

前有堵截,后有追兵

文档描述与实际情况不一致?

运行代码,发现还是无法获得预期效果。用 Postman 再次查看信息,发现出现的错误信息跟之前一样:

{
    "msg": "rate_limit_exceeded2: 43.243.12.21",
    "code": 112,
    "request": "GET /v2/book/search"
}

又到网络上搜索资料,这次发现,有很多开发者遇到了类似的问题,而且他们在自己的博客中指出,豆瓣限制的其实不只是文档中写明的一小时的请求频率,还有一分钟的请求频率。

我将信将疑,等时间限制过了之后,用 Postman 再次发送请求,这次我重点查看 response header,发现有了两个参数跟文档上描述得不一致。

插图

我的请求限制是 100 次
豆瓣文档明明写的是 500 次

插图

文档上最低的请求限制是 500 次每小时,可在我得到的响应中,写得却是 100 次每小时。
难道是因为我没有申请豆瓣的开发者账号吗?
算了,且不纠结这个。

每分钟 35 次限制?

看别人的博客时,发现有的博主说到,豆瓣的 API 还有个每分钟不能超过 35 个请求的限制。
我不是很请求这个限制是否真的有,也不想试,因为请求次数很宝贵,试上两次就得等个一小时才能重新发请求了。
干脆直接就将这个条件纳入考虑。

每分钟速度限制 + 每小时次数限制

综合考虑到这两个限制之后,我大概的思路是这个样子的:

  1. 将两百多条记录做个 partition,分为四份,一个小时请求一次
  2. 每个请求前,随机等待 0 - 5 秒钟 (试了十几次,最长的一次请求返回之间大概是三秒,稍微多等待一点时间)

程序是下面这个样子

const agent = require('superagent');
const async = require('async');
const _ = require('underscore');
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(5);
  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);
           }
         }
       );
}


function partition(items, size) {
  let result = _.groupBy(items, function(item, i) {
    return Math.floor(i/size);
  });
  return _.values(result);
}

const milliseconds_of_one_hour = 60 * 60 * 1000;

partition(bookTitleList, 80).forEach(subList => {
  async.map(subList, requestTags, (err, tags) => {
    tags.forEach(tag => {
      console.log(tag);
    })
  });
  sleep(milliseconds_of_one_hour);
})

写好程序之后,我满心欢喜,运行命令,就直接工作去了。想着晚上下班了直接看效果就行了

当头棒喝

没想到呀没想到,结果还是错的,这是怎么搞得!
命名已经将时间限制和次数限制都加上了呀,还有什么其他问题呢?
仔细地看了错误信息,发现很奇怪的一点,有几个请求是成功的,但是还是无法拿到 tag,报了空指针异常,也就是在 const tag = res.body.books[0].tags; 这一行报错了。
欸,难道是这本书不存在。

的确有可能,为了验证这个想法,我加了个防御语句

let book = res.body.books[0];
const tag = book ? book.tags : `=======================================================empty book ${bookTitle}`

只有当响应中包含 books 并且第一个元素不为空时,我才去取 tags,对于不存在的书,返回特定的字符串加上书名,后面好看得出来是哪本书没有得到响应。

Deadline 是第一生产力

改完之后,发现时间已经不够用了,距离 11 点写作训练的截止时间只剩下不到两小时。如果还按照这个程序执行的话,我就无法完成今天的训练了。

情急之下,我把读书记录分为 8 份,每份 30 条记录左右。手动执行程序,在一个小时多一点的时间内,拿到了所有的豆瓣标签,并将它们合到了一块。

重新使用抄来的 python 程序,成功生成词云图,由于这次直接使用标签而不是书名,所以我拿掉了 分词 的语句。但是,又遇到了编码的问题,几经周
折,最后终于在既定时间内以非常丑陋的代码既定的目标。

最后生成的标签词云如下:

大学读书记录 豆瓣标签

对比上一次使用分词工具对书名处理过后得到的词云图,结果看起来区别还是很大的。


book history

比如,在新的图片中,看不到重复的词(比如旧图中重复的 Java),也没有被错误分开的词语(比如 皮格马利翁效应 )。总的来说,这次生成的词云应该算是成功的。

未完待续……

因为赶时间,所以我最后是以非常丑陋的代码实现的这些功能。在下一篇文章给中,我想讲讲我如何重构我这些丑陋的代码,使得它们不那么丑陋(挽回一点面子 -_-|| )。

如果你想看下有多丑陋,点击前往代码库

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,999评论 4 368
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,102评论 1 302
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,709评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,439评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,846评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,881评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,062评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,783评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,517评论 1 248
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,762评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,241评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,568评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,236评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,145评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,941评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,965评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,802评论 2 275

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,589评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,105评论 18 139
  • 前情提要 前一篇文章中,我想明白了:使用 书名 搜索,得到的豆瓣返回结果集的第一个元素其实就是目标书的信息。于是,...
    afaren阅读 690评论 3 2
  • 佛法常讲无我,究竟什么是无我呢?这可能要从反面来讲更容易理解。 事例1: 老婆在教育儿子,语气稍微有些急躁,我在一...
    厚天下阅读 253评论 0 0
  • 我们断断续续走了许久,有时候我们甚至都以为我们习惯了孤独。过多了一个人的生活,一个人吃饭,去图书馆,看书,旅行;也...
    JARRETT1994阅读 204评论 0 0