https://habrahabr.ru/post/339620/Здравствуйте ещё раз!
Я прочёл
её и мне показалось, что её можно продолжить.
Ни для кого не секрет, что самая популярная и прибыльная площадка для рекламы, бизнеса и прочего — 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 сущностей:
- Аккаунт
- Пост
- Геолокация
- Комментарий
- Хэштег
Всё остальное — это просто списки этих сущностей, такие как лайки, подписки, подписчики и прочее
И для каждой сущность есть свой класс. Для аккаунтов — 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.
А ещё можно не беспокоится о переполнении памяти.
У класса каждой сущности есть словарь, в котором хранятся все объекты данного класса (или объекты подкласса даже). Таким образом, если Вы случайно создадите, например, аккаунт, который уже был создан, конструктор вернёт вам ссылку на ранее созданный аккаунт.
Если вы случайно пропустили ссылку на репозиторий в тексте, то вот она ещё раз:
https://github.com/OlegYurchik/InstagramLib
И напоследок скажу, что из-за некоторых решений появились и некоторые проблемы:
1. Например, проблема при повторном создании объекта. Если вдруг вы захотите использовать аккаунт как рабочий и взаимодействовать через него, а он уже ранее был создан как обычный аккаунт, то создать его снова не получиться. Пока я не знаю, как это решить.
2. Перехват ошибок иногда ведёт себя очень странно и не до конца протестирован.
Я очень надеюсь, что, может быть, данное решение кому-нибудь пригодится, надеюсь на любые полезные комментарии и на помощь в допиливании этой штуки. В указанной мною статье был приведён пример такого скрипта на PHP, но он занимался только сбором информации и, по-моему, он работал только со старой версией веб-нитерфейса Instagram.
Спасибо за внимание.