javascript - 如何执行未经身份验证的 Instagram 网络抓取以响应最近的私有(private) API 更改?

标签 javascript web-scraping instagram instagram-api

几个月前,Instagram 开始通过删除大多数功能并拒绝接受大多数权限范围的新应用程序来使其公共(public) API 无法运行。 Further changes were made this week 进一步限制了开发者选项。

我们中的许多人已经转向 Instagram 的私有(private)网络 API 来实现我们之前拥有的功能。一个杰出的 ping/instagram_private_api 设法重建了大部分先前的功能,但是,随着本周公开宣布的更改,Instagram 也对其私有(private) API 进行了基础更改,需要魔法变量、用户代理和 MD5 哈希来使网络抓取请求成为可能.这可以通过 following the recent releases on the previously linked git repository 看到,继续获取数据所需的确切更改可以通过 be seen here

这些变化包括:

  • 在请求之间保留用户代理和 CSRF token 。
  • https://instagram.com/ 发出初始请求,以从响应正文中获取 rhx_gis 魔法键。
  • 设置 X-Instagram-GIS header ,它是通过神奇地连接 rhx_gis 键和查询变量,然后再通过 MD5 哈希传递它们而形成的。

低于此值的任何值都将导致 403 错误。这些更改已成功实现 in the above repository,但是,我在 JS 中的尝试仍然失败。在下面的代码中,我试图从用户时间轴中获取前 9 个帖子。确定这一点的查询参数是:

  • query_hash of 42323d64886122307be10013ad2dcc44(从用户的时间线中获取媒体)。
  • variables.id 任何用户 ID 的字符串(从中获取媒体的用户)。
  • variables.first,要获取的帖子数,整数。

以前,可以通过简单地从 https://www.instagram.com/graphql/query/?query_hash=42323d64886122307be10013ad2dcc44&variables=%7B%22id%22%3A %225380311726%22%2C%22first%22%3A1%7D,因为 URL 未 protected 。

但是,我尝试实现成功写入上述存储库的功能并没有奏效,我只收到来自 Instagram 的 403 响应。我在节点环境中使用 superagent 作为我的请求库。

/*
** Retrieve an arbitrary cookie value by a given key.
*/
const getCookieValueFromKey = function(key, cookies) {
        const cookie = cookies.find(c => c.indexOf(key) !== -1);
        if (!cookie) {
            throw new Error('No key found.');
        }
        return (RegExp(key + '=(.*?);', 'g').exec(cookie))[1];
    };

/*
** Calculate the value of the X-Instagram-GIS header by md5 hashing together the rhx_gis variable and the query variables for the request.
*/
const generateRequestSignature = function(rhxGis, queryVariables) {
    return crypto.createHash('md5').update(`${rhxGis}:${queryVariables}`, 'utf8').digest("hex");
};

/*
** Begin
*/
const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5';

// Make an initial request to get the rhx_gis string
const initResponse = await superagent.get('https://www.instagram.com/');
const rhxGis = (RegExp('"rhx_gis":"([a-f0-9]{32})"', 'g')).exec(initResponse.text)[1];

const csrfTokenCookie = getCookieValueFromKey('csrftoken', initResponse.header['set-cookie']);

const queryVariables = JSON.stringify({
    id: "123456789",
    first: 9
});

const signature = generateRequestSignature(rhxGis, queryVariables);

const res = await superagent.get('https://www.instagram.com/graphql/query/')
    .query({
        query_hash: '42323d64886122307be10013ad2dcc44',
        variables: queryVariables
    })
    .set({
        'User-Agent': userAgent,
        'X-Instagram-GIS': signature,
        'Cookie': `rur=FRC;csrftoken=${csrfTokenCookie};ig_pr=1`
    }));

我还应该尝试什么?是什么导致我的代码失败,而上面存储库中提供的代码工作正常?

更新 (2018-04-17)

至少一周内第三次,Instagram 再次更新了他们的 API。更改不再需要 CSRF token 构成散列签名的一部分。

上面的问题已经更新以反射(reflect)这一点。

更新 (2018-04-14)

Instagram 再次更新了他们的私有(private) graphql API。据任何人都可以弄清楚:

  • 用户代理不再需要包含在 X-Instagram-Gis md5 计算中。

上面的问题已经更新以反射(reflect)这一点。

最佳答案

要坚持的值(value)观

您没有在对 Instagram 的第一个查询中保留用户代理(要求):

const initResponse = await superagent.get('https://www.instagram.com/');

应该是:

const initResponse = await superagent.get('https://www.instagram.com/')
                     .set('User-Agent', userAgent);

这必须与 csrftoken cookie 一起保存在每个请求中。

X-Instagram-GIS 标题生成

如您的回答所示,您必须从两个属性生成 X-Instagram-GIS header ,即在您的初始请求中找到的 rhx_gis 值,以及查询下一个请求中的变量。这些必须经过 md5 哈希处理,如上面的函数所示:

const generateRequestSignature = function(rhxGis, queryVariables) {
    return crypto.createHash('md5').update(`${rhxGis}:${queryVariables}`, 'utf8').digest("hex");
};

关于javascript - 如何执行未经身份验证的 Instagram 网络抓取以响应最近的私有(private) API 更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49786980/

相关文章:

javascript - 如何计算图像周围的计算透明区域?

javascript - Firestore 数据不起作用

java - 仅从网页中抓取特定详细信息

javascript - 无法读取来自 insta 的 json

ios - 从 UIDocumentInteractionController 选择 App 会抛出 "LaunchServices: invalidationHandler called"错误

javascript - 在html表中获取倒数第二个 child td

javascript - 使用PrototypeJs,如何异步加载jsp页面

python - BeautifulSoup 网络爬虫 : How to get piece of text

python - Scrapy - FormRequest 在方法为 POST 时发送 GET 请求

python - 为什么我无法从 instagram API 获取媒体调用?