Здравствуйте ещё раз! Я прочёл её и мне показалось, что её можно продолжить.

image

Ни для кого не секрет, что самая популярная и прибыльная площадка для рекламы, бизнеса и прочего — Instagram. Почему им стал именно сервис, в котором по началу можно было загружать только картинки определённого размера (соотношение сторон имеется ввиду) и не было абсолютно ничего, что было в тогдашних соцсетях — совсем непонятно, но факт есть факт. Ввиду чего все стараются проникнуть на площадку Instagram и захватить оттуда наибольшее количество аудитории, и делают, это, конечно же, не вручную. А за этим следует, что Instagram жёстко блокирует доступ для ботов, спамеров и прочему, дабы сеть оставалась чистой.

  1. Самые полезные функции (постинг и удаление постов) доступны только из мобильного приложения Instagram, эмуляция запросов сложна, так как надо вытащить из приложения ключ, который с каждой новой версией обновляется.
  2. Web-версия обрезана, но радует, что в ней есть возможность лайкать, комментировать и удалять комментарии
  3. Есть API, но процедура его получения удручающе долгая и спамерам и ботам такой путь точно не светит. Плюс было много моментов, когда соглашения в API менялись, что не всегда удобно.

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

Хочется сказать, что работать с Web-версией Instagram очень даже приятно по двум причинам:

1. О любой страничке можно получить краткую информацию, если отправить GET запрос вида:

https://instagram.com/zuck/?__a=1

И ответом является JSON с доступной информацией, первыми 10 постами странички и прочим. Очень приятно.

2. Если же краткой информации не хватает, то тут есть ещё одна приятная новость. Дозагрузить фоточки, подписки, комментарии можно со помощью определённого запроса вида

https://www.instagram.com/graphql/query/?query_id=17888483320059182&variables=...

, где в variables передаются переменные для обработки в формате JSON. Ответом также является JSON. Да и вообще, очевидно, что работает это всё на GraphQL, так что чтобы понять, как обрабатываются запросы, можно даже погуглить.

На основе данных знаний и построена вся библиотека. Я вкратце опишу, как её можно использовать, может, кому-то пригодится. Кстати, я там в репозитории указал лицензию BSD 3. Подскажите, может, мне стоит её поменять, чтобы не было никаких трудностей?

Установка


Устанавливать её не надо. Точнее, мне было лень прописывать всякие setup.py или упаковывать, когда библиотека состоит всего из одного файла. Поэтому там просто файл instagram.py, который подключается так:

import instagram

Как ей пользоваться?


Взаимодействие с Instagram возможно либо с авторизацией, либо без. Без авторизации отсутствуют функции просмотра подписок и подписчиков, и, очевидно, невозможно что-то лайкнуть, что-то откомментировать и так далее. Единственные ограничения с авторизацией: это невозможно выкладывать посты и удалять их.

Приведу пример взаимодействия без авторизации:


import instagram

agent=instagram.Agent()
account=instagram.Account("zuck")

agent.update(account)

media=agent.getMedia(account, count=100)
for m in media:
    print(m)

Как вы поняли, данный скрипт прогружает информацию о странице Марка Цукерберга, загружает последние 100 постов с его странице и выводит их на экран.

Хочу сказать, что если бы я не написал

agent.update(account)

то выполнить загрузку постов не получилось бы, так как никакой информации о странице Цукерберга известно не было.

А вот пример с авторизацией:


import instagram

agent=instagram.AgentAccount("oleg.yurchik", "imasuperpassword")
agent.update()
account=instagram.Account("zuck")
agent.update(account)
# and etc.

Это, так называемый Hello, world!. Или быстрый старт.

А теперь расскажу подробнее:

Instagram, на самом деле, имеет всего 5 сущностей:

  1. Аккаунт
  2. Пост
  3. Геолокация
  4. Комментарий
  5. Хэштег

Всё остальное — это просто списки этих сущностей, такие как лайки, подписки, подписчики и прочее. И для каждой сущности есть свой класс. Для аккаунтов — Account, постов — Media, геолокаций — Location, комментариев — Comment, хэштегов — Tag. И каждый из них (кроме комментариев) нужно обновить, прежде чем работать с ним. То есть если хочется загрузить все свои посты, пролайкать их и получить список геолокаций, то нужно выполнить следующее:


import instagram

agent=instagram.AgentAccount('oleg.yurchik', 'anothersuperpassword')
agent.update()
media=agent.getMedia(count=agent.media_count)
locations=[]
for m in media:
    agent.like(m)
    agent.update(m)
    if agent.location:
        locations.append(agent.location)

А если позже надо получить последние 10 постов по определённой геолокации, то надо будет сделать следующее:


agent.update(location)
media=agent.getMedia(location, count=10)

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

Библиотека основана на библиотеке requests, и одной из фишек я считаю то, что в методы также можно передать дополнительные параметры для requests. Такая идея пришла ко мне, когда я первый раз получил 429 ошибку от Instagram. Нужно было использовать прокси.

Например, можно сделать так:


media=agent.getMedia(count=agent.media_count, settings={'proxies': {'https': '127.0.0.1:80'}})

где 127.0.0.1:80 — можно указать свой прокси

Также ещё одной фишкой, я думаю, может являться перехват ошибок.

В классах Agent и AgentAccount (те, что и производят общение с Instagram) есть словарь, организованный как дерево, он называется exception_actions. В нём в виде ключей хранятся классы исключений, а в виде значений — функции. Если вдруг произошла какая-то ошибка, она перехватывается и выполняется функция из словаря. Этой функции передаётся объект исключения и параметры, с которыми выполнялся запрос. Она может выполнить какое-то действие и вернуть изменённые (или нет) параметры запроса. Выполнение запроса повторится снова. И будет повторятся столько раз, сколько указано в параметре Agent.repeats. По умолчанию стоит 1.

А ещё можно не беспокоиться о переполнении памяти.

У класса каждой сущности есть словарь, в котором хранятся все объекты данного класса (или объекты подкласса даже). Таким образом, если Вы случайно создадите, например, аккаунт, который уже был создан, конструктор вернёт вам ссылку на ранее созданный аккаунт.

Если вы случайно пропустили ссылку на репозиторий в тексте, то вот она ещё раз.

И напоследок скажу, что из-за некоторых решений появились и некоторые проблемы:

  1. Например, проблема при повторном создании объекта. Если вдруг вы захотите использовать аккаунт как рабочий и взаимодействовать через него, а он уже ранее был создан как обычный аккаунт, то создать его снова не получиться. Пока я не знаю, как это решить.
  2. Перехват ошибок иногда ведёт себя очень странно и не до конца протестирован.

Я очень надеюсь, что, может быть, данное решение кому-нибудь пригодится, надеюсь на любые полезные комментарии и на помощь в допиливании этой штуки. В указанной мною статье был приведён пример такого скрипта на PHP, но он занимался только сбором информации и, по-моему, он работал только со старой версией веб-нитерфейса Instagram.

Спасибо за внимание.

Комментарии (36)


  1. MakarkinPRO
    08.10.2017 23:34

    А получив это API доступ к Instagram, rtmp случайно не появляется для стриминга?


    1. Ryder95 Автор
      08.10.2017 23:44

      Я не знаю, я ещё года 2 назад пытался получить доступ к API, но мне не дали) Его, как мне рассказывали, дают в приоритете каким-либо веб-приложениям, и чаще всего уже запущенным


  1. Hugiron
    09.10.2017 00:30
    +1

    Очень жаль, что не все методы работают (например, получение лайков и комментариев без авторизации). Насколько мне известно, query_id привязывается к сессии, а вы их вынесли в качестве магических констант.


    1. Ryder95 Автор
      09.10.2017 00:34

      Насколько мне известно, query_id привязывается к сессии, а вы их вынесли в качестве магических констант.

      Это действительно магические константы) Точнее, они требуются для того, чтобы указать, что запрашивается. Это проверено опытным путём
      Очень жаль, что не все методы работают (например, получение лайков и комментариев без авторизации).

      Нет, без авторизации точно можно получать комментарии, а лайки, если честно, не пробовал. Но если web-интерфейс позволяет, то и в приложении можно.


  1. Hazrat
    09.10.2017 01:39
    +1

    Если кому интересно, делал как-то телегам бот для масс фолловинга t.me/instanode_bot
    Использовал приватное api instagram, в итоге имея базу прогоняю по ним аккаунты
    Проект на github github.com/hazratgs/instalator-telegram


  1. xilix
    09.10.2017 02:21
    +3

    2 года назад написал плагин, который публикует товары в инстаграм
    www.webasyst.ru/store/plugin/shop/instagram
    Он эмулирует телефон.
    Как работал ключ, так и работает до сих пор.


    1. Ryder95 Автор
      09.10.2017 02:29

      Он маскируется под старую версию приложения? Я думал, они закрывают доступ)


      1. xilix
        09.10.2017 02:32
        +2

        Могу дать доступ в репо на гитлаб, если в личку скинешь мыло. Посмотришь класс, который генерит клиента. Я его делал на основе другого класса, который нашел на гитхабе.


  1. DnAp
    09.10.2017 08:09

    Бегло посмотрел код, как я понимаю список новостей авторизованного пользователя получить нельзя?


    1. Ryder95 Автор
      09.10.2017 08:12

      Пока нет, но в теории можно)


      1. DnAp
        09.10.2017 10:27

        Наверно возьмусь как время высвободится. Давно хочу ленту из инстаграма отправить в rss читалку.


  1. KoToSveen
    09.10.2017 10:09
    -1

    когда библиотека состоит всего из одного файла

    всего из 756 строк.
    Может я и придираюсь, но я бы всё раскидал по разный файлам (эксепшионы, авторизация, действия)


    1. Ryder95 Автор
      09.10.2017 10:11
      +2

      Не, всё верно, но пока я не увидел в этом смысла) и мне удобнее было писать, когда всё в одном файле


    1. firk
      09.10.2017 12:00
      +2

      756 строк — это не много
      А вот делать много файлов с каким-то специальным библиотечным оформлением, когда можно сделать один, встраиваемый под видом части своего исходника — уже наоборот "много".


  1. largotek
    09.10.2017 10:11

    А у инстаграма есть ограничения по запросам? И как это обходите? Например у вк 3 запроса в секунду, и нормально парсить только если сбор распределять на разные аккаунты.


    1. Ryder95 Автор
      09.10.2017 10:13

      Как я выше писал, все запросы делаются на основе библиотеки requests. Если использовать парсинг с авторизацией, то прокси не поможет, это да. Мне приходилось вставлять обработчик ошибок, чтобы при 429 он ожидал какое-то время


      1. largotek
        09.10.2017 10:16

        А сам инстаграм не даёт никаких цифр запросы в секунду? И по опыту можете, пожалуйста, сказать сколько нужно времени (вместе с ожиданием) что бы скачать например 10000 постов?


        1. Ryder95 Автор
          09.10.2017 10:33

          Официально у них описано только API, и там тоже не ахти. В варианте веб версии некоторую инфу можно вытаскивать анонимно, а с API это невозможно. Если про реальные цифры, то чтобы не уйти в 429 я пробовал ставить ожидание после каждого запроса от 1 до 2 секунд. С 1 секундой он уходит в 429 ошибку, с 2 — никогда. Думаю, при таком варианте — это где-то 40-50 запросов в минуту. Так как максимум можно вытащить около 1000 запросов за раз (скорее всего, есть цифра точная, но я не ставил экспериментов пока), то на 10000 постов надо будет потратить около 3-4 часов. Это если быть авторизованным. А если вытаскивать посты без авторизации с использованием прокси — то ограничений нет. Опять же, если бы мобильное приложение или API давали лучшие результаты(


        1. Ryder95 Автор
          09.10.2017 10:34

          1000 постов за запрос*


        1. Ryder95 Автор
          09.10.2017 10:37

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


          1. largotek
            09.10.2017 11:15

            Спасибо. Да я имел ввиду картинка, текст, теги и т.д.


            1. Ryder95 Автор
              09.10.2017 11:27

              На самом деле, технически можно достать и за полминуты. По-моему, из запросов типа ?__a=1 можно достать ещё маленькие изображения и, кажется, текст. Но это не точно


              1. largotek
                09.10.2017 12:05

                Хм… интересно, спасибо. Как перейду к инсте надо будет видимо исследовать этот вопрос.


        1. gerzog
          09.10.2017 10:45

          Читайте
          Если кратко — 2 часа (если Ваше приложение Instagram заапрувил). Это не считая комментариев к постам, т.к. они выкачиваются отдельными запросами, а значит требуют дополнительных лимитов.


          1. gerzog
            09.10.2017 10:52

            И кстати там используется довольно интересная штука с time-sliding limits, т.е. кол-во запросов в час считается не относительно некоторого времени (например с 11.00 до 12.00) а за час назад отсчитывая от текущего момента


            1. largotek
              12.10.2017 15:13

              Спасибо, да полезный линк.


  1. petriichuk
    09.10.2017 11:22

    вот кстати интересный скрипт для накрутки, github.com/timgrossmann/InstaPy слелан с использованиям Selenium


  1. vlade11115
    09.10.2017 16:23

    Для класса который знает о своих экземплярах хорошо бы взять weakref.WeakSet. Тогда не нужно будет писать кастомный __del__, и когда на экземпляр не будет ссылок тогда из WeakSet он пропадёт автоматически. Да и в целом код станет немного проще.


  1. zhuharev
    09.10.2017 16:40

    Ни для кого не секрет, что самая популярная и прибыльная площадка для рекламы, бизнеса и прочего — Instagram.

    Сильное заявление

    Рекомендую библиотеку, которая эмулирует поведение android-приложения и позволяет делать почти всё (сейчас живые трансляции не доступны), что возможно в приложении https://github.com/mgp25/Instagram-API/.

    Если вам нужен только постинг, используйте мой докер-контейнер (https://github.com/zhuharev/instagram-rest-api), который запускается как микро-сервис и позволяет (пока только) постить фото и галлереи просто rest-запросом.


    1. inoyakaigor
      09.10.2017 18:21

      Может кто подскажет такое же, но только для ноды?


      1. zhuharev
        09.10.2017 19:55

        Вообще все проекты гуглятся по запросу «instagram unofficial api»

        Есть адаптация для ноды https://github.com/huttarichard/instagram-private-api и для питона https://github.com/danleyb2/Instagram-API

        Лучше использовать оригинальную библиотеку, потому что у неё бОльшее комьюнити и библиотеку часто обновляют.


        1. Ryder95 Автор
          09.10.2017 23:14

          А она, как я понял, также эмулирует приложение, да? И в нём надо обязательно авторизовываться?


          1. zhuharev
            09.10.2017 23:58

            Она шлёт такие же запросы, как и приложение. Да, работа с библиотекой доступна только по логину и паролю.


  1. kAIST
    09.10.2017 18:47
    +2

    По поводу эмуляции клиента и эавторизации добавлю. Когда ты делаешь ее на сервере, который географически удален от того места, где ты обычно используешь аккаунт, авторизация не проходит. Нужно зайти в веб версию инстаграма, залогинится там и подтвердить что это был ты.
    Столкнулся с этим, когда делал инстаграм клиент для часов pebble (исходники, кому интересно)


    1. Ryder95 Автор
      09.10.2017 18:50

      Да, есть такое. Это тоже можно обойти, но из-за того, что эта проблема встречается редко — я не смог её решить(


      1. zhuharev
        09.10.2017 19:58
        +1

        нужно авторизироваться на своём компьютере, например, (что бы ip был такой же, как и ip где вы авторизировались с мобильного), а потом просто скопировать cookies на удалённый сервер