Skip to content

Commit 6f6db85

Browse files
committed
Merge branch 'master' of github.com:LevPasha/Instagram-API-python into delete_media
2 parents 46f1ce8 + c17f33a commit 6f6db85

File tree

8 files changed

+251
-11
lines changed

8 files changed

+251
-11
lines changed

InstagramAPI/InstagramAPI.py

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def setProxy(self, proxy=None):
8585

8686
if proxy is not None:
8787
print('Set proxy!')
88-
proxies = {'http': 'http://' + proxy, 'https': 'http://' + proxy}
88+
proxies = {'http': proxy, 'https': proxy}
8989
self.s.proxies.update(proxies)
9090

9191
def login(self, force=False):
@@ -388,7 +388,63 @@ def configureTimelineAlbum(self, media, albumInternalMetadata, captionText='', l
388388
except:
389389
pass
390390
return False
391-
391+
392+
def direct_message(self, text, recipients):
393+
if type(recipients) != type([]):
394+
recipients = [str(recipients)]
395+
recipient_users = '"",""'.join(str(r) for r in recipients)
396+
endpoint = 'direct_v2/threads/broadcast/text/'
397+
boundary = self.uuid
398+
bodies = [
399+
{
400+
'type' : 'form-data',
401+
'name' : 'recipient_users',
402+
'data' : '[["{}"]]'.format(recipient_users),
403+
},
404+
{
405+
'type' : 'form-data',
406+
'name' : 'client_context',
407+
'data' : self.uuid,
408+
},
409+
{
410+
'type' : 'form-data',
411+
'name' : 'thread',
412+
'data' : '["0"]',
413+
},
414+
{
415+
'type' : 'form-data',
416+
'name' : 'text',
417+
'data' : text or '',
418+
},
419+
]
420+
data = self.buildBody(bodies,boundary)
421+
self.s.headers.update (
422+
{
423+
'User-Agent' : self.USER_AGENT,
424+
'Proxy-Connection' : 'keep-alive',
425+
'Connection': 'keep-alive',
426+
'Accept': '*/*',
427+
'Content-Type': 'multipart/form-data; boundary={}'.format(boundary),
428+
'Accept-Language': 'en-en',
429+
}
430+
)
431+
#self.SendRequest(endpoint,post=data) #overwrites 'Content-type' header and boundary is missed
432+
response = self.s.post(self.API_URL + endpoint, data=data)
433+
434+
if response.status_code == 200:
435+
self.LastResponse = response
436+
self.LastJson = json.loads(response.text)
437+
return True
438+
else:
439+
print ("Request return " + str(response.status_code) + " error!")
440+
# for debugging
441+
try:
442+
self.LastResponse = response
443+
self.LastJson = json.loads(response.text)
444+
except:
445+
pass
446+
return False
447+
392448
def direct_share(self, media_id, recipients, text=None):
393449
if not isinstance(position, list):
394450
recipients = [str(recipients)]
@@ -727,6 +783,20 @@ def unlike(self, mediaId):
727783
'media_id': mediaId})
728784
return self.SendRequest('media/' + str(mediaId) + '/unlike/', self.generateSignature(data))
729785

786+
def save(self, mediaId):
787+
data = json.dumps({'_uuid': self.uuid,
788+
'_uid': self.username_id,
789+
'_csrftoken': self.token,
790+
'media_id': mediaId})
791+
return self.SendRequest('media/' + str(mediaId) + '/save/', self.generateSignature(data))
792+
793+
def unsave(self, mediaId):
794+
data = json.dumps({'_uuid': self.uuid,
795+
'_uid': self.username_id,
796+
'_csrftoken': self.token,
797+
'media_id': mediaId})
798+
return self.SendRequest('media/' + str(mediaId) + '/unsave/', self.generateSignature(data))
799+
730800
def getMediaComments(self, mediaId, max_id=''):
731801
return self.SendRequest('media/' + mediaId + '/comments/?max_id=' + max_id)
732802

@@ -827,6 +897,37 @@ def generateUUID(self, type):
827897
def generateUploadId(self):
828898
return str(calendar.timegm(datetime.utcnow().utctimetuple()))
829899

900+
def createBroadcast(self, previewWidth=1080, previewHeight=1920, broadcastMessage=''):
901+
data = json.dumps({'_uuid': self.uuid,
902+
'_uid': self.username_id,
903+
'preview_height': previewHeight,
904+
'preview_width': previewWidth,
905+
'broadcast_message': broadcastMessage,
906+
'broadcast_type': 'RTMP',
907+
'internal_only': 0,
908+
'_csrftoken': self.token})
909+
return self.SendRequest('live/create/', self.generateSignature(data))
910+
911+
def startBroadcast(self, broadcastId, sendNotification=False):
912+
data = json.dumps({'_uuid': self.uuid,
913+
'_uid': self.username_id,
914+
'should_send_notifications': int(sendNotification),
915+
'_csrftoken': self.token})
916+
return self.SendRequest('live/' + str(broadcastId) + '/start', self.generateSignature(data))
917+
918+
def stopBroadcast(self, broadcastId):
919+
data = json.dumps({'_uuid': self.uuid,
920+
'_uid': self.username_id,
921+
'_csrftoken': self.token})
922+
return self.SendRequest('live/' + str(broadcastId) + '/end_broadcast/', self.generateSignature(data))
923+
924+
def addBroadcastToLive(self, broadcastId):
925+
# broadcast has to be ended first!
926+
data = json.dumps({'_uuid': self.uuid,
927+
'_uid': self.username_id,
928+
'_csrftoken': self.token})
929+
return self.SendRequest('live/' + str(broadcastId) + '/add_to_post_live/', self.generateSignature(data))
930+
830931
def buildBody(self, bodies, boundary):
831932
body = u''
832933
for b in bodies:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ This is the Python port of https://github.com/mgp25/Instagram-API which is writt
1010
It is still a work in progress to copy all of its API endpoints.
1111

1212
NOTE: To successfully parse for a long time you should verify your phone number in your Instagram account.
13-
The new fake Instagram account with an unverifird phone number after ~ 1-24 hours could not do any requests. All requests will be redirected to the page instagram.com/challenge
13+
The new fake Instagram account with an unverified phone number after ~ 1-24 hours could not do any requests. All requests will be redirected to the page https://instagram.com/challenge
1414

1515
### Installation Instructions
1616

examples/evaluation/__init__.py

Whitespace-only changes.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Use text editor to edit the script and type in valid Instagram username/password
5+
6+
from InstagramAPI import InstagramAPI
7+
from examples.evaluation.evaluation_log import EvaluationLog
8+
from examples.user_followers import getTotalFollowers
9+
10+
11+
def evaluate_method(function, parameters, function_name=None):
12+
evaluation_log = EvaluationLog()
13+
evaluation_log.start_log(function_name)
14+
response = function(*parameters)
15+
evaluation_log.end_log(function_name)
16+
17+
print('response size:', len(response))
18+
print('number of unique users:', len(set([user['username'] for user in response])))
19+
print()
20+
21+
22+
if __name__ == "__main__":
23+
api = InstagramAPI("username", "password")
24+
api.login()
25+
26+
# For a user with over 22k followers, use: user_id = '1461295173'
27+
user_id = api.username_id
28+
29+
evaluate_method(api.getTotalFollowers, [user_id], 'api.getTotalFollowers')
30+
evaluate_method(getTotalFollowers, [api, user_id], 'getTotalFollowers')

examples/evaluation/evaluation_log.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from time import time, process_time, strftime, localtime
2+
from datetime import timedelta
3+
4+
5+
def time_to_str(elapsed=None):
6+
if elapsed is None:
7+
return strftime("%Y-%m-%d %H:%M:%S", localtime())
8+
else:
9+
return str(timedelta(seconds=elapsed))
10+
11+
12+
class EvaluationLog():
13+
14+
def start_log(self, s="Start Program"):
15+
self.start = time()
16+
self.cpu_start = process_time()
17+
self.log(s)
18+
19+
def end_log(self, s="End Program"):
20+
self.end = time()
21+
self.cpu_end = process_time()
22+
elapsed_time = self.end - self.start
23+
cpu_time = self.cpu_end - self.cpu_start
24+
self.log(s, time_to_str(elapsed_time), time_to_str(cpu_time))
25+
26+
@staticmethod
27+
def log(s, elapsed_time=None, cpu_time=None):
28+
line = "=" * 40
29+
print(line)
30+
print(time_to_str(), '-', s)
31+
32+
if elapsed_time:
33+
print("Elapsed time:", elapsed_time)
34+
if cpu_time:
35+
print("CPU time:", cpu_time)
36+
37+
print(line)

examples/live_broadcast.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Use text editor to edit the script and type in valid Instagram username/password
5+
6+
import subprocess
7+
8+
from InstagramAPI import InstagramAPI
9+
10+
USERNAME = ''
11+
PASSWORD = ''
12+
FILE_PATH = '/path/to/video/file'
13+
PUBLISH_TO_LIVE_FEED = False
14+
SEND_NOTIFICATIONS = False
15+
16+
api = InstagramAPI(USERNAME, PASSWORD, debug=False)
17+
assert api.login()
18+
19+
# first you have to create a broadcast - you will receive a broadcast id and an upload url here
20+
assert api.createBroadcast()
21+
broadcast_id = api.LastJson['broadcast_id']
22+
upload_url = api.LastJson['upload_url']
23+
24+
# we now start a boradcast - it will now appear in the live-feed of users
25+
assert api.startBroadcast(broadcast_id, sendNotification=SEND_NOTIFICATIONS)
26+
27+
ffmpeg_cmd = "ffmpeg -rtbufsize 256M -re -i '{file}' -acodec libmp3lame -ar 44100 -b:a 128k -pix_fmt yuv420p -profile:v baseline -s 720x1280 -bufsize 6000k -vb 400k -maxrate 1500k -deinterlace -vcodec libx264 -preset veryfast -g 30 -r 30 -f flv '{stream_url}'".format(
28+
file=FILE_PATH,
29+
stream_url=upload_url.replace(':443', ':80', ).replace('rtmps://', 'rtmp://'),
30+
)
31+
32+
print("Hit Ctrl+C to stop broadcast")
33+
try:
34+
subprocess.call(ffmpeg_cmd, shell=True)
35+
except KeyboardInterrupt:
36+
print('Stop Broadcasting')
37+
38+
assert api.stopBroadcast(broadcast_id)
39+
40+
print('Finished Broadcast')
41+
42+
if PUBLISH_TO_LIVE_FEED:
43+
api.addBroadcastToLive(broadcast_id)
44+
print('Added Broadcast to LiveFeed')

examples/thread_download.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,6 @@ def save(self):
6666
InstagramAPI = InstagramAPI("login", "password")
6767
InstagramAPI.login()
6868

69-
inst = DownloadThead(InstagramAPI, thread_id)
69+
inst = DownloadThread(InstagramAPI, thread_id)
7070
inst.download()
7171
inst.save()

examples/user_followers.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,38 @@
55

66
from InstagramAPI import InstagramAPI
77

8-
api = InstagramAPI("login", "password")
9-
api.login() # login
10-
api.tagFeed("cat") # get media list by tag #cat
11-
media_id = api.LastJson # last response JSON
12-
api.like(media_id["ranked_items"][0]["pk"]) # like first media
13-
api.getUserFollowers(media_id["ranked_items"][0]["user"]["pk"]) # get first media owner followers
14-
print(api.LastJson)
8+
9+
def getTotalFollowers(api, user_id):
10+
"""
11+
Returns the list of followers of the user.
12+
It should be equivalent of calling api.getTotalFollowers from InstagramAPI
13+
"""
14+
15+
followers = []
16+
next_max_id = True
17+
while next_max_id:
18+
# first iteration hack
19+
if next_max_id is True:
20+
next_max_id = ''
21+
22+
_ = api.getUserFollowers(user_id, maxid=next_max_id)
23+
followers.extend(api.LastJson.get('users', []))
24+
next_max_id = api.LastJson.get('next_max_id', '')
25+
return followers
26+
27+
28+
if __name__ == "__main__":
29+
api = InstagramAPI("username", "password")
30+
api.login()
31+
32+
# user_id = '1461295173'
33+
user_id = api.username_id
34+
35+
# List of all followers
36+
followers = getTotalFollowers(api, user_id)
37+
print('Number of followers:', len(followers))
38+
39+
# Alternatively, use the code below
40+
# (check evaluation.evaluate_user_followers for further details).
41+
followers = api.getTotalFollowers(user_id)
42+
print('Number of followers:', len(followers))

0 commit comments

Comments
 (0)