我是一个 Instagram 重度用户,关注了很多有意思的 po 主,因此经常需要将这些 po 主的所有图片打包下载。(国外非常注重版权,下载图片只能个人使用,商业用途请严格遵循版权保护流程。)
ig 的账户分为公开账户和私有账户。这里只讨论公开账户的图片的获取方式。
我们知道在 ig 用户的 profile 业务可以看到用户发布的所有图片,例如:https://www.instagram.com/instagram/
,即格式为:
1 2 |
https://www.instagram.com/{username}/ |
很久以前,我们通过 https://www.instagram.com/{username}/?__a=1
的方式可以获取该用户的所有图片。但是这个方法被大家玩烂了,ig做了一些限制,先是下线了这个私有接口,后来又恢复了这个接口,但是需要用户处于登录状态。考虑到这个接口被下线过,继续使用该接口不确定性较大,且让帐户处于登录状态去调用这种私有接口被封号的概率是很大的。于是,尝试使用其他方式。
前端无秘密,ig 的接口其实还是比较奔放的。在用户 profile 页面转了一圈,发现其使用了一个通用的 graphql 接口来获取用户图片:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
url: https://www.instagram.com/graphql/query/ header: :authority: www.instagram.com :method: GET :scheme: https accept: */* accept-encoding: gzip, deflate, br accept-language: zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7,zh-TW;q=0.6 referer: https://www.instagram.com/instagram/ user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36 x-ig-app-id: 936619743392459 x-instagram-gis: 32deb78bf683bfa59631bc5e68f6e099 x-requested-with: XMLHttpRequest query: query_hash: f2405b236d85e8296cf30347c9f08c2a variables: {"id":"25025320","first":12,"after":"QVFBZDJCYUdCMXNHeWJCWVlQRThsTXFNRkxGWmpqRDZQbDQ4YlVrLVdIVm10ZDE3MUhaLVNuTkFzcThQampFR0JJekFRZEpQRE9MMmVZcG9CLXdMaHMyOA=="} |
那么接下来的事情简单了,确定其请求的参数就可以模型请求获取用户图片了。
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 实现:
1 2 3 4 |
const generateRequestSignature = function(rhxGis, queryVariables) { return crypto.createHash('md5').update(`${rhxGis}:${queryVariables}`, 'utf8').digest("hex"); }; |
rhxGis
参数可以通过用户页面的全局变量 window._sharedData
获取到:
1 2 |
window._sharedData = {..."rhx_gis":"9fc41e6e27cffb347d931f7eed08f056",... |
queryVariables
对应上诉 variables
参数。
至此,关键参数获取方式都已搞定。可以开心的在 ig 上逛图啦。
扩展阅读
How to perform unauthenticated Instagram web scraping in response to recent private API changes?