Как я могу получить медиа пользователя из Instagram без аутентификации в качестве пользователя?

Я пытаюсь поместить последние медиа Instagram пользователя на боковой панели. Я пытаюсь использовать API Instagram для извлечения информации.

http://instagram.com/developer/endpoints/users/

в документации говорится, чтобы получить https://api.instagram.com/v1/users/<user-id>/media/recent/, но он говорит, чтобы передать токен доступа OAuth. Маркер доступа представляет собой разрешение действовать от имени пользователя. Я не хочу, чтобы пользователи входили в Instagram, чтобы увидеть это на боковой панели. Им даже не нужно иметь Аккаунт Instagram.

например, я могу пойти в http://instagram.com/thebrainscoop без входа в Instagram и просмотра фотографий. Я хочу сделать это через API.

в API Instagram запросы, не прошедшие проверку подлинности пользователя, проходят client_id вместо access_token. Если я попробую это, я получу:

{
  "meta":{
    "error_type":"OAuthParameterException",
    "code":400,
    "error_message":""access_token" URL parameter missing. This OAuth request requires an "access_token" URL parameter."
  }
}

Итак, это невозможно? Нет ли способа получить последние (общедоступные) медиа пользователя, не попросив пользователя войти в Instagram аккаунт через OAuth?

17 ответов


Это поздно, но стоит, если это помогает кому-то, как я не видел его в документации Instagram.

для выполнения GET on https://api.instagram.com/v1/users/<user-id>/media/recent/ (на данный момент) вам фактически не нужен токен доступа OAuth.

вы можете выполнить https://api.instagram.com/v1/users/[USER ID]/media/recent/?client_id=[CLIENT ID]

[идентификатор клиента] будет действительным идентификатором клиента, зарегистрированным в приложении через управление клиентами(не связанными с пользователем). Вы можете получить [идентификатор пользователя] от имени пользователя, выполнив запрос поиска GET users: https://api.instagram.com/v1/users/search?q=[USERNAME]&client_id=[CLIENT ID]


var name = "smena8m",
  items;
$.getJSON("https://query.yahooapis.com/v1/public/yql", {
  q: "select * from json where url='https://www.instagram.com/" + name + "/?__a=1'",
  format: "json",
  _: name
}, function(data) {
  console.log(data);
  if (data.query.results) {
    items = data.query.results.json.user.media.nodes;
    $.each(items, function(n, item) {
      $('body').append(
        $('<a/>', {
          href: 'https://www.instagram.com/p/'+item.code,
          target: '_blank'
        }).css({
          backgroundImage: 'url(' + item.thumbnail_src + ')'
        }));
    });
  }

});
html, body {
  font-size: 0;
  line-height: 0;
}

a {
  display: inline-block;
  width: 25%;
  height: 0;
  padding-bottom: 25%;
  background: #eee 50% 50% no-repeat;
  background-size: cover;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

вы можете скачать любую фотографию пользователя Instagram в формате JSON с помощью ?__a=1 рядом с адресом целевой страницы такой. Нет необходимости получать идентификатор пользователя или регистрировать приложение, нет токенов, нет oAuth.

min_id и max_id переменные могут использоваться для разбиения на страницы, Вот пример

YQL может не работать внутри отсеченного iframe, поэтому вы всегда можете проверить его вручную консоль YQL

обновление апреля 2018: после последних обновлений instagram вы не можете сделать это на стороне клиента (javascript), потому что пользовательские заголовки для подписанного запроса не могут быть установлены с помощью javascript из-за CORS Access-Control-Allow-Headers ограничения. Это все еще можно сделать через php или любой другой метод на стороне сервера с правильной подписью на основе rhx_gis, csrf_token и параметры запроса. Вы можете прочитать больше об этом здесь.

PHP решение:

    $html = file_get_contents('https://instagram.com/apple/');
    preg_match('/_sharedData = ({.*);<\/script>/', $html, $matches);
    $profile_data = json_decode($matches[1])->entry_data->ProfilePage[0]->graphql->user;

11.11.2017
Поскольку Instagram изменил способ предоставления этих данных, ни один из вышеперечисленных методов не работает в настоящее время. Вот новый способ получить медиа пользователя:
GET https://instagram.com/graphql/query/?query_id=17888483320059182&variables={"id":"1951415043","first":20,"after":null}
Где:
query_id - постоянное значение: 17888483320059182 (обратите внимание, это может быть изменено в будущем).
id - id пользователя. Он может поставляться со списком пользователей. Чтобы получить список пользователей, вы можете использовать следующий запрос: GET https://www.instagram.com/web/search/topsearch/?context=blended&query=YOUR_QUERY
first - количество элементов в получить.
after - id последнего элемента, если вы хотите получить элементы из этого идентификатора.


на прошлой неделе, Instagram инвалидов /media/ urls, я реализовал обходной путь, который работает довольно хорошо на данный момент.

чтобы решить все проблемы в этой теме, я написал следующее:https://github.com/whizzzkid/instagram-reverse-proxy

Он предоставляет все общедоступные данные instagram, используя следующие конечные точки:

получить пользовательский носитель:

https://igapi.ga/<username>/media
e.g.: https://igapi.ga/whizzzkid/media 

получить пользовательский носитель с ограничением граф:

https://igapi.ga/<username>/media?count=N // 1 < N < 20
e.g.: https://igapi.ga/whizzzkid/media?count=5

использовать JSONP:

https://igapi.ga/<username>/media?callback=foo
e.g.: https://igapi.ga/whizzzkid/media?callback=bar

прокси API также добавляет URL-адреса следующей страницы и предыдущей страницы к ответу, поэтому вам не нужно вычислять это в конце.

Надеюсь, вам понравится!

спасибо @350D за обнаружение этого:)


я смог получить самый последний носитель пользователя, используя следующий API без аутентификации (включая описание, нравится, количество комментариев).

https://www.instagram.com/apple/?__a=1

Э. Г.

https://www.instagram.com/{username}/?__a=1

API Instagram требует аутентификации пользователя через OAuth для доступа к последней конечной точке мультимедиа для пользователя. Кажется, что сейчас нет другого способа получить все носители для пользователя.


Если вы ищете способ создания маркера доступа для использования в одной учетной записи, вы можете попробовать это -> https://coderwall.com/p/cfgneq.

Мне нужен был способ использовать api instagram, чтобы захватить все последние медиа для конкретной учетной записи.


вот решения rails. Это своего рода задняя дверь, которая на самом деле является входной дверью.

# create a headless browser
b = Watir::Browser.new :phantomjs
uri = 'https://www.instagram.com/explore/tags/' + query
uri = 'https://www.instagram.com/' + query if type == 'user'

b.goto uri

# all data are stored on this page-level object.
o = b.execute_script( 'return window._sharedData;')

b.close

объект, который вы получаете обратно, зависит от того, является ли это поиск пользователя или поиск тега. Я получаю такие данные:

if type == 'user'
  data = o[ 'entry_data' ][ 'ProfilePage' ][ 0 ][ 'user' ][ 'media' ][ 'nodes' ]
  page_info = o[ 'entry_data' ][ 'ProfilePage' ][ 0 ][ 'user' ][ 'media' ][ 'page_info' ]
  max_id = page_info[ 'end_cursor' ]
  has_next_page = page_info[ 'has_next_page' ]
else
  data = o[ 'entry_data' ][ 'TagPage' ][ 0 ][ 'tag' ][ 'media' ][ 'nodes' ]
  page_info = o[ 'entry_data' ][ 'TagPage' ][ 0 ][ 'tag' ][ 'media' ][ 'page_info' ]
  max_id = page_info[ 'end_cursor' ]
  has_next_page = page_info[ 'has_next_page' ]
end

затем я получаю другую страницу результатов, построив url-адрес следующим образом:

  uri = 'https://www.instagram.com/explore/tags/' + query_string.to_s\
    + '?&max_id=' + max_id.to_s
  uri = 'https://www.instagram.com/' + query_string.to_s + '?&max_id='\
    + max_id.to_s if type === 'user'

благодаря постоянно меняющейся (и ужасно разработанной) схеме API Instagram большинство из вышеперечисленных больше не будет работать с апреля 2018 года.

вот последний путь для доступа к отдельным данным post, если вы запрашиваете их API напрямую с помощью https://www.instagram.com/username/?__a=1 метод.

предполагая, что вы вернулись JSON данные $data вы можете перебирать каждый результат, используя следующие примеры пути:

foreach ($data->graphql->user->edge_owner_to_timeline_media->edges as $item) {

    $content_id = $item->node->id; 
    $date_posted = $item-node->taken_at_timestamp;
    $comments = $item->node->edge_media_to_comment->count;
    $likes = $item->node->edge_liked_by->count;
    $image = $item->node->display_url;
    $content = $item->node->edge_media_to_caption->edges[0]->node->text;
    // etc etc ....
}

основные вещи в этом недавнем изменении были graphql и edge_owner_to_timeline_media.

похоже, что они собираются убить этот доступ к API для не "деловых" клиентов в декабрь 2018 так сделать большую часть этого, пока вы можете.

надеюсь, это кому-то поможет;)


просто хочу добавить к ответу @350D, так как мне было трудно понять.

моя логика в коде следующее:

при первом вызове API я вызываю только https://www.instagram.com/_vull_ /media/. Когда я получаю ответ, я проверяю логическое значение more_available. Если это правда, я получаю последнюю фотографию из массива, получаю ее идентификатор, а затем снова вызываю API Instagram, но на этот раз https://www.instagram.com/_vull_/media/?max_id=1400286183132701451_1642962433.

важно знать, что здесь этот идентификатор является идентификатором последнего изображения в массиве. Поэтому, когда вы просите maxId с последним идентификатором изображения в массиве вы получите следующие 20 изображений и так далее.

надеюсь, это прояснит ситуацию.


Если вы обходите Oauth, вы, вероятно,не знаете, какой пользователь instagram они. При этом есть несколько способов получить изображения instagram без аутентификации.

  1. API Instagram позволяет просматривать самые популярные изображения пользователя без аутентификации. Используя следующую конечную точку:вот ссылка

  2. Instagram предоставляет RSS-каналы для тегов этой.

  3. пользователей Instagram страницы являются общедоступными, поэтому вы можете использовать PHP с CURL, чтобы получить их страницу и парсер DOM для поиска тегов изображений в html.


еще один трюк, поиск фотографий по хештегу:

GET https://www.instagram.com/graphql/query/?query_hash=3e7706b09c6184d5eafd8b032dbcf487&variables={"tag_name":"nature","first":25,"after":""}

где:

query_hash - постоянное значение (я верю, что его хэш 17888483320059182, может быть изменен в будущем)

tag_name - название говорит само за себя

first - количество элементов, чтобы сделать (я не знаю, почему, но это значение не работает, как ожидалось. Фактическое количество возвращенных фотографий немного больше, чем значение, умноженное на 4.5 (около 110 для значения 25 и около 460 за значение 100))

after - id последнего элемента, если вы хотите получить элементы из этого идентификатора. Значение end_cursor из ответа JSON можно использовать здесь.


Ну как /?__a=1 перестал работать сейчас, лучше использовать curl и анализировать страницу instagram, как написано в этом ответе:создать маркер доступа Instagram API, без необходимости входа в систему?


обновление

этот метод больше не работает

JSFiddle

Javascript:

$(document).ready(function(){

    var username = "leomessi";
    var max_num_items = 5;

    var jqxhr = $.ajax( "https://www.instagram.com/"+username+"/?__a=1" ).done(function() {
        //alert( "success" );
    }).fail(function() {
        //alert( "error" );
    }).always(function(data) {
        //alert( "complete" )
        items = data.graphql.user.edge_owner_to_timeline_media.edges;
        $.each(items, function(n, item) {
            if( (n+1) <= max_num_items )
            {
                var data_li = "<li><a target='_blank' href='https://www.instagram.com/p/"+item.node.shortcode+"'><img src='" + item.node.thumbnail_src + "'/></a></li>";
                $("ul.instagram").append(data_li);
            }
        });

    });

});

HTML:

<ul class="instagram">
</ul>

CSS:

ul.instagram {
    list-style: none;
}

ul.instagram li {
  float: left;
}

ul.instagram li img {
    height: 100px;
}

приведенный ниже код nodejs очищает популярные изображения со страницы Instagram. Функция "ScrapeInstagramPage" заботится о пост-старении.

var request = require('parse5');
var request = require('request');
var rp      = require('request-promise');
var $       = require('cheerio'); // Basically jQuery for node.js 
const jsdom = require("jsdom");    
const { JSDOM } = jsdom;


function ScrapeInstagramPage (args) {
    dout("ScrapeInstagramPage for username -> " + args.username);
    var query_url = 'https://www.instagram.com/' + args.username + '/';

    var cookieString = '';

    var options = {
        url: query_url,
        method: 'GET',
        headers: {
            'x-requested-with' : 'XMLHttpRequest',
            'accept-language'  : 'en-US,en;q=0.8,pt;q=0.6,hi;q=0.4', 
            'User-Agent'       : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
            'referer'          : 'https://www.instagram.com/dress_blouse_designer/',
            'Cookie'           : cookieString,
            'Accept'           : '*/*',
            'Connection'       : 'keep-alive',
            'authority'        : 'www.instagram.com' 
        }
    };


    function dout (msg) {
        if (args.debug) {
            console.log(msg);
        }
    }

    function autoParse(body, response, resolveWithFullResponse) {
        // FIXME: The content type string could contain additional values like the charset. 
        // Consider using the `content-type` library for a robust comparison. 
        if (response.headers['content-type'] === 'application/json') {
            return JSON.parse(body);
        } else if (response.headers['content-type'] === 'text/html') {
            return $.load(body);
        } else {
            return body;
        }
    }

    options.transform = autoParse;


    rp(options)
        .then(function (autoParsedBody) {
            if (args.debug) {
                console.log("Responce of 'Get first user page': ");
                console.log(autoParsedBody);
                console.log("Creating JSDOM from above Responce...");
            }

            const dom = new JSDOM(autoParsedBody.html(), { runScripts: "dangerously" });
            if (args.debug) console.log(dom.window._sharedData); // full data doc form instagram for a page

            var user = dom.window._sharedData.entry_data.ProfilePage[0].user;
            if (args.debug) {
                console.log(user); // page user
                console.log(user.id); // user ID
                console.log(user.full_name); // user full_name
                console.log(user.username); // user username
                console.log(user.followed_by.count); // user followed_by
                console.log(user.profile_pic_url_hd); // user profile pic
                console.log(autoParsedBody.html());
            }

            if (user.is_private) {
                dout ("User account is PRIVATE");
            } else {
                dout ("User account is public");
                GetPostsFromUser(user.id, 5000, undefined);
            }
        })
        .catch(function (err) {
            console.log( "ERROR: " + err );
        });  

    var pop_posts = [];
    function GetPostsFromUser (user_id, first, end_cursor) {
        var end_cursor_str = "";
        if (end_cursor != undefined) {
            end_cursor_str = '&after=' + end_cursor;
        }

        options.url = 'https://www.instagram.com/graphql/query/?query_id=17880160963012870&id=' 
                        + user_id + '&first=' + first + end_cursor_str;

        rp(options)
            .then(function (autoParsedBody) {
                if (autoParsedBody.status === "ok") {
                    if (args.debug) console.log(autoParsedBody.data);
                    var posts = autoParsedBody.data.user.edge_owner_to_timeline_media;

                    // POSTS processing
                    if (posts.edges.length > 0) {
                        //console.log(posts.edges);
                        pop_posts = pop_posts.concat
                        (posts.edges.map(function(e) {
                            var d = new Date();
                            var now_seconds = d.getTime() / 1000;

                            var seconds_since_post = now_seconds - e.node.taken_at_timestamp;
                            //console.log("seconds_since_post: " + seconds_since_post);

                            var ageing = 10; // valuses (1-10]; big value means no ageing
                            var days_since_post = Math.floor(seconds_since_post/(24*60*60));
                            var df = (Math.log(ageing+days_since_post) / (Math.log(ageing)));
                            var likes_per_day = (e.node.edge_liked_by.count / df);
                            // console.log("likes: " + e.node.edge_liked_by.count);
                            //console.log("df: " + df);
                            //console.log("likes_per_day: " + likes_per_day);
                            //return (likes_per_day > 10 * 1000);
                            var obj = {};
                            obj.url = e.node.display_url;
                            obj.likes_per_day = likes_per_day;
                            obj.days_since_post = days_since_post;
                            obj.total_likes = e.node.edge_liked_by.count;
                            return obj;
                        }
                        ));

                        pop_posts.sort(function (b,a) {
                          if (a.likes_per_day < b.likes_per_day)
                            return -1;
                          if (a.likes_per_day > b.likes_per_day)
                            return 1;
                          return 0;
                        });

                        //console.log(pop_posts);

                        pop_posts.forEach(function (obj) {
                            console.log(obj.url);
                        });
                    }

                    if (posts.page_info.has_next_page) {
                        GetPostsFromUser(user_id, first, posts.page_info.end_cursor);
                    }
                } else {
                    console.log( "ERROR: Posts AJAX call not returned good..." );
                }
            })
            .catch(function (err) {
                console.log( "ERROR: " + err );
            }); 
    }
}


ScrapeInstagramPage ({username : "dress_blouse_designer", debug : false});

попробуй здесь

пример: Для данного URL'https://www.instagram.com/dress_blouse_designer/ ' можно вызвать функцию

ScrapeInstagramPage ({username : "dress_blouse_designer", debug : false});

это работает с помощью простого вызова ajax и итерации путей изображения.

        var name = "nasa";
        $.get("https://www.instagram.com/" + name + "/?__a=1", function (data, status) {
            console.log('IG_NODES', data.user.media.nodes);
            $.each(data.user.media.nodes, function (n, item) {
                console.log('ITEMS', item.display_src);
                $('body').append(
                    "<div class='col-md-4'><img class='img-fluid d-block' src='" + item.display_src + "'></div>"
                );
            });
        })

jsfiddle

    $(document).ready(function(){

    var username = "hadidapp";
    var max_num_items = 5;

    var jqxhr = $.ajax( "https://www.instagram.com/"+username+"/?__a=1&" ).done(function() {
        //alert( "success" );
    }).fail(function() {
        //alert( "error" );
    }).always(function(data) {
        //alert( "complete" )
    items = data.graphql.user.edge_owner_to_timeline_media.edges;
        $.each(items, function(n, item) {
            if( (n+1) <= max_num_items )
            {
                var data_li = "<li><a target='_blank' href='https://www.instagram.com/p/"+item.node.shortcode+"'><img src='" + item.node.thumbnail_src + "'/></a></li>";
                $("ul.instagram").append(data_li);
            }
        });

    });
});

рабочий образец