获取 Instagram 用户所有图片手记

我是一个 Instagram 重度用户,关注了很多有意思的 po 主,因此经常需要将这些 po 主的所有图片打包下载。(国外非常注重版权,下载图片只能个人使用,商业用途请严格遵循版权保护流程。)

ig 的账户分为公开账户和私有账户。这里只讨论公开账户的图片的获取方式。

我们知道在 ig 用户的 profile 业务可以看到用户发布的所有图片,例如:https://www.instagram.com/instagram/,即格式为:

很久以前,我们通过 https://www.instagram.com/{username}/?__a=1 的方式可以获取该用户的所有图片。但是这个方法被大家玩烂了,ig做了一些限制,先是下线了这个私有接口,后来又恢复了这个接口,但是需要用户处于登录状态。考虑到这个接口被下线过,继续使用该接口不确定性较大,且让帐户处于登录状态去调用这种私有接口被封号的概率是很大的。于是,尝试使用其他方式。

前端无秘密,ig 的接口其实还是比较奔放的。在用户 profile 页面转了一圈,发现其使用了一个通用的 graphql 接口来获取用户图片:

那么接下来的事情简单了,确定其请求的参数就可以模型请求获取用户图片了。

query_hash 参数

query_hash 在接口中的作用类似于让服务器知道客户端的版本,这个参数被 hard-coding 在前端的一个 js 文件中。在我的网络环境下,该 js 文件是 b55cb2cfaa46.js,值为 f2405b236d85e8296cf30347c9f08c2a.

该参数获取非常容易,唯一不太确定的是其更新的频率。从实际使用情况来看,这个值已经一个多月没有更新过了。因此,一周自动检测更新一次应该是没有问题的。

query 参数中的 variables 都是业务参数,看一眼就明白。但是,实际测试你会发现,所有的query参数都正确的情况下,服务器依然会返回 403. 二分排除了一下,发现是 header 中的 x-instagram-gis 是一个请求签名验证参数。只有该参数通过了验证,才能获得预期的返回。

x-instagram-gis 参数

签名的生成算法是:signature = md5({rhxGis}:{queryVariables}). 对应 js 实现:

rhxGis 参数可以通过用户页面的全局变量 window._sharedData 获取到:

queryVariables 对应上诉 variables 参数。

至此,关键参数获取方式都已搞定。可以开心的在 ig 上逛图啦。

扩展阅读

How to perform unauthenticated Instagram web scraping in response to recent private API changes?

2018 年终总结

2018 年终总结

年末被各种事情推着走,总结拖到现在才写,也算是保持了过去一年平均时间管理水平😅。

过去的一年,发生和经历的事情挺多,也逐渐到了很多事情不太适合写出来尴尬年龄。不过,一直在路上,缺少盘点的话,总觉得对自己缺乏那么一点交代。

过去的一年,重新捡回来写作的习惯,同时也开始鼓动身边的人开始写作。毕竟这是当前仅存的几项只有好处,但咸有坏处的活动。过去的一年,每月至少有一篇输出,同时靠写作赚了几杯咖啡钱,也因为写作,连接到了一些素未谋面的有趣灵魂们。其中,收到过一位自己喜欢的“大佬”的打赏。这是一些好的方面。换工作以后,写作的时间和频率被动减少了很多,借口就不提了。但好不容易养成的习惯,是无论如何不能被摧毁的,新的一年希望自己有更多与自己交谈的思考和沉淀。

过去的一年,离开了自己舒适区,换了份工作。其实非常舍不得前东家,我知道作为在职场混迹多年的人,依然说这种话是非常不成熟和忌讳的。但是,离开真的并不是因为它有什么不好,只是因为未来两年,我有自己想成长的方向和天空。开弓没有回头箭,下山的弟子要去爬属于自己的那座山,没来得及好好道别的兄弟们,我们江湖再见。来到新的工作岗位心态非常平和,这也是自己一直以来希望自己面对任何事情的基本心态——在智力、心里、脑力、体力之外,一定不能扭曲的就是心态。新的位置压力不大肯定是骗人的,但是希望自己能够保持好这份心态。要不了几年,我依然会从这个山头下山,人说雁过留痕,我希望自己能对得起自己当年的那次下山,当然还有自己的年轮。

过去一年,没有什么像样的出游,如果一定要记录一下的话,那就是在青城山下悠闲的几日,以及带家人去了一趟乐山。这种出游距离和时间,对于成都人来说,也就是一个周末亲自游的水平。但是青城山下,因为放下了所有事情,逛着经不起历史推敲的道观,也算是难得的放空。乐山之行算是特意为家里的四个女人安排的:婆婆,老妈,妞儿还有女儿。乐山我跟老爸都去过很多次了,但是对于前面四位在某些层面来说都是新的:婆婆、女儿从来没有去过乐山;老妈去过乐山,但是没看过大佛;妞儿去过大佛,但是因为四年前自己安排不当,并没有尝到乐山的美食。一天的逛吃下来,在力所能及范围内,用尽了一切便利条件,大小老少都累得够呛。晚饭时候,婆婆说”今天最幸福“,我知道他们那一辈人是很难表达这些感情的,能说出这句话,我真的觉得自己歪打正着的这次安排真的太幸运了。

过去的一年,纸质阅读时间和质量都下降严重。有时候,我甚至已经开始怀疑自己被算法推荐的狗粮给喂成了🐷。这是过去一年时间管理出问题的一个侧面,每天警醒自己,但是每天依然岿然不动,也算是极致的讽刺了。新的一年,需要改变。

过去的一年,莫名其妙的看了很多场电影。最推荐的是《我不是药神》,影评层面的就不提了,仅仅是因为这是这几年陪老妈看的第一部电影。希望以后能陪父母看更多的电影。

过去的一年,经济很冷。自己在投资层面稍有盈余,看看身边各种腰斩的兄dei,至少不算太差。被动收入方面,完成了几个流程性的事情,虽然远比自己预想的要慢,但是这个事情本来也就是在认定的方向上去祈求一个时间的礼物,急不得太多,但须一直坚持下去。希望来年,能有一个姑且能称为产品的达到自己设定的目标吧。

过去的一年,依然没有学会如何哄女儿。跟别人说起来头头是道的 positive 式引导教育,自己实践起来屁用没有。我现在已经接受女儿当前 double two 阶段的这种超乎常人的顽皮,也许她在 third two 的时候,这种顽皮会有所收敛?天知道呢。

过去的一年,送给了妞儿一个大件礼物。其实,她至今没有正式的跟我说声谢谢,但是我能感受到事物本身对她认知的影响。有些事情,不仅是责任,更是义务,其他的并不重要。

过去的一年,没有买到自己心仪已久的大房子,挺遗憾的。希望来年准备好更多子弹,给家人一个更好的居所,也给自己一个更舒适的奋斗窝。

2018年初,我知道会发生很多事情,但是真正做一些事情让预想发生的时候,自己早已没有当时的兴奋,反而会带来一些自己没有考虑到的问题。你说这些重要吗?肯定重要,因为它会影响你的轨迹;但是也没那么重要,毕竟我过去做过如此多最坏的选择,其实也没有太糟糕。新的起点,我想在自己认真的事情上保持认真和专注,在自己没有那么认真的事情上,想清楚,要么认真起来,要么随他而去。2019,心之所向,不过如此。

后端程序员两个周末入门微信小程序开发

再过几个小时,2018就结束了,赶着最后几个小时,完成了一个微信小程序,感谢时间,也感谢自己。

平时工作比较忙,整个开发花了两个周末的休息时间,输出包括后端服务器以及微信小程序,当然还有一些购买和部署服务器、CDN、https 证书等打杂的事情。

很遗憾,作为一个自诩为程序猿老司机的自己并没有在9小时搞定微信小程序开发。作为一个平时只写后端代码的老司机,这个完成速度勉强算及格吧。下面介绍一下自己这两个周末入门小程序开发用到的资料以及遇到的

微信小程序最好的资料

小程序这块技术栈对于自己来说是一个从0到1的过程,因此最开始还是想找找有没有一些现成的教程。看了一些免费教程,发现不太系统,并且很多js的写法在我这个业务选手看来都业余。于是极客时间找到了一个付费专栏:《9小时搞定微信小程序开发》

就在我准备付费的时候,发现其课程大纲不过是官方教程的一个搬运和翻译。

课程目录:

官方教程(部分):

(没有贬低专栏作者的意思,事实上,小程序这块技术栈让我来写,估计目录也差不多。或者说,对于有一定学习能力的👨‍💻‍,根本就不应该存在所谓的学习课程🤭)

作为一个聆听过《左耳听风》耗子叔的极客时间专栏的老司机(好像秒打脸了😂),自然是记得他老人家对于学习知识的谆谆告诫:

我问过几个在别的领域知识付费的专栏作者:你们写的这些东西,不就是卡内基的那些东西吗?不就是某某书里的那些东西吗?不就是某某英文资料里的那些内容吗?

他们告诉我,是的,我们就是搬运知识,有些国外的东西,国人理解不了,需要用他们喜欢的语言讲出来,而他们又不读书,英文水平也一般,但他们想速成,所以,才有了我们的市场。这有点像餐馆,他们不想自己做饭吃,那就我们来做,有的人还要别人喂到嘴边,甚至好些人都需要先帮他们嚼一遍,他们才能吃得下去。所以,我们这些学习能力强的人挣点他们的钱也是应该的。

所以,兜兜转转一圈,最后还是选择了微信团队的官方开发教程。而这个选择从后面的开发过程看,是无比正确的:

  1. 官方教程不长,非常干练,整体系统感强。举个例子,很多奖微信小程序开发的二手教程都会给你说这个API是干嘛的以及如何使用这种废话。但是,微信的框架-API文档中,则直接给你言简意赅的讲解了其所有API涉及的规范和原则,你看了这个规约后,你看到一个API你其实就已经知道它该如何使用了。对于我这种入门菜鸟来说,这种知识点如果在入门时候就知其然,后面会在这个点上重复采坑而不自知,并且后续要知其所以然要花费的时间只会多不会少。
  2. 这是小程序开发第一手资料的来源,具有权威性和最高的时效性。从两年前关注小程序,到现在开发自己的第一个小程序前,一直以为小程序技术这块从发布至今没有什么迭代和更新,但是从其文档的众多的API兼容以及事件兼容描述看,小程序团队过去两年真的是挺努力的。作为一个开发者,迭代造成的不兼容,你只能去适配,因此,第一手的资料往往能给你节省数小时的时间。
  3. 丰富的样式库和源代码示例。这块重点推荐两个资源:

第一个是微信小程序设计指南。如果你需要自己设计产品原型,你一定要研读一下这个设计指南,这样你就不用去重新发明很多UI轮子,也不用纠结这个交互是方案A好还是方案B好。这个指南从一定程度上反应了微信整个的产品观和设计理念,你一定也能找出这些指南中不够完美的地方,但是当前阶段,这的确是一个能够让你快速设计出一个80分微信小程序产品的 Bible. 指南中给出了WeUI_sketch组件库 WeUI_PS组件库以及对应的预览地址,可以帮助你快速设计产品原型。

第二个是WeUI for 小程序. 如果第一个资源主要是辅助你进行产品设计,那么这个资源则是辅助你进行快速开发的必备参考库(老鸟可以无视)。用了这个代码库以后,你开发页面大部分时候就是从这个库里面找你需要的组件和样式,然后复制-粘贴搞定:

那些微信小程序开发中的坑

修改 page data 不生效

坦率讲,这并不是小程序的坑,而是自己看文档不仔细。修改页面的 data 只能通过 setData:

  1. 直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
  2. 仅支持设置可 JSON 化的数据。
  3. 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。
  4. 请不要把 data 中任何一项的 value 设为 undefined ,否则这一项将不被设置并可能遗留一些潜在问题。

setData 可以直接修改一个其下的子字段:

但是有一种情况需要注意:如果你的 key 是一个变量,这样修改子字段是不会生效的:

你应该这样做:

navigateTo 不生效

这个依然是看文档不仔细:

wx.navigateTo(Object object)
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。

如果你要跳转的页面是 tabbar 页面,请使用 wx.switchTab.

列表条目多时出现卡顿

这个问题容易出现在动态加载数据,数据又绑定了前端列表view的场景。根据官方文档,使用 wx:key 解决即可。其原理是:

当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

wx.requestDELETE 传参问题

根据w3c标准,http DELETE 请求中的参数应该跟 GET 方法一样,放在 url query 中,然而微信封装的 wx.request 防范在指定为 DELETE 方法后,data 依然被放在了 body 中。如果你在服务器端获取不到参数,请尝试从 body 中获取。

文件上传阿里云OSS 403 权限问题

如果你直接使用阿里云 OSS 域名上传,因为微信封禁了 OSS 域名,因此你需要参考微信小程序文件上传二三事 绑定自定义域名。同时,千万注意,绑定的域名不要开启CDN,否则,会造成 403 权限错误:

如果同时希望使用阿里云的CDN,请绑定另外一个域名,与上传域名分开。

总结

也许是孕妇效应吧,最近发现很多人都开始做微信小程序。从整体开发体验看,这的确是一个分发自己创意的轻量级产品方案。过去的两年,微信小程序已经远超百万,但是真正让你能记住的可能比你能记住的公众号还少。因此,载体本身的影响能力圈是有限的,还是要回归到你的产品解决了什么问题,这也是你做任何产品的价值所在。此外,因为苹果税的问题,当前 (2018.12.31)iOS 平台的微信小程序无法进行虚拟物品支付(会员、道具、课程等)的,这显然会极大的影响开发者的积极性。虽然你张小龙的理念是小程序用完即走,但是你不能让开发者只有一个广告变现的路径,更不能只是自私的维护好自己的地盘儿不管开发者死活。