diff --git a/main.py b/main.py index b994ded6..4a8d99a8 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from Osintgram import Osintgram +from src.Osintgram import Osintgram import argparse -import printcolors as pc +from src import printcolors as pc import sys @@ -15,15 +15,20 @@ def printlogo(): pc.printout("\_______ /____ >__|___| /__| \___ /|__| (____ /__|_| /\n", pc.YELLOW) pc.printout(" \/ \/ \/ /_____/ \/ \/ \n", pc.YELLOW) print('\n') - pc.printout("Version 0.3 - Developed by Giuseppe Criscione - 2019\n\n", pc.YELLOW) + pc.printout("Version 0.5 - Developed by Giuseppe Criscione - 2019\n\n", pc.YELLOW) pc.printout("Type 'list' to show all allowed commands\n") pc.printout("Type 'FILE=y' to save results to files like '_.txt (deafult is disabled)'\n") pc.printout("Type 'FILE=n' to disable saving to files'\n") + pc.printout("Type 'JSON=y' to export results to a JSON files like '_.json (deafult is " + "disabled)'\n") + pc.printout("Type 'JSON=n' to disable exporting to files'\n") def cmdlist(): pc.printout("FILE=y/n\t") print("Enable/disable output in a '_.txt' file'") + pc.printout("JSON=y/n\t") + print("Enable/disable export in a '_.json' file'") pc.printout("info\t\t") print("Get target info") pc.printout("addrs\t\t") @@ -66,7 +71,7 @@ def cmdlist(): while True: pc.printout("Run a command: ", pc.YELLOW) cmd = input() - if (cmd == "quit" or cmd == "exit"): + if cmd == "quit" or cmd == "exit": pc.printout("Goodbye!\n", pc.RED) sys.exit(0) elif cmd == "list" or cmd == "help": @@ -93,6 +98,10 @@ def cmdlist(): api.setWriteFile(True) elif cmd == "FILE=n": api.setWriteFile(False) + elif cmd == "JSON=y": + api.setJsonDump(True) + elif cmd == "JSON=n": + api.setJsonDump(False) elif cmd == "photos": api.getUserPhoto() elif cmd == "captions": diff --git a/InstagramAPI.py b/src/InstagramAPI.py similarity index 99% rename from InstagramAPI.py rename to src/InstagramAPI.py index 075eb1d7..9df14953 100644 --- a/InstagramAPI.py +++ b/src/InstagramAPI.py @@ -216,18 +216,17 @@ class InstagramAPI: # IGDataPath # Data storage path def __init__(self, username, password, debug=False, IGDataPath=None): + self.uuid = self.generateUUID(True) + self.password = password + self.username = username + self.username_id = "" m = hashlib.md5() m.update(username.encode('utf-8') + password.encode('utf-8')) self.device_id = self.generateDeviceId(m.hexdigest()) - self.setUser(username, password) self.isLoggedIn = False self.LastResponse = None self.s = requests.Session() - def setUser(self, username, password): - self.username = username - self.password = password - self.uuid = self.generateUUID(True) def setProxy(self, proxy=None): """ diff --git a/Osintgram.py b/src/Osintgram.py similarity index 77% rename from Osintgram.py rename to src/Osintgram.py index 929a7246..f180c1ef 100644 --- a/Osintgram.py +++ b/src/Osintgram.py @@ -6,8 +6,8 @@ from geopy.geocoders import Nominatim from prettytable import PrettyTable -import printcolors as pc -from InstagramAPI import InstagramAPI +from src import printcolors as pc +from src.InstagramAPI import InstagramAPI class Osintgram: @@ -18,6 +18,7 @@ class Osintgram: is_private = True target = "" writeFile = False + jsonDump = False def __init__(self, target): u = self.__getUsername__() @@ -35,26 +36,36 @@ def setTarget(self, target): self.__printTargetBanner__() def __getUsername__(self): - u = open("config/username.conf", "r").read() - u = u.replace("\n", "") - return u + try: + u = open("config/username.conf", "r").read() + u = u.replace("\n", "") + return u + except FileNotFoundError: + pc.printout("Error: file \"config/username.conf\" not found!", pc.RED) + pc.printout("\n") + sys.exit(0) def __getPassword__(self): - p = open("config/pw.conf", "r").read() - p = p.replace("\n", "") - return p + try: + p = open("config/pw.conf", "r").read() + p = p.replace("\n", "") + return p + except FileNotFoundError: + pc.printout("Error: file \"config/pw.conf\" not found!", pc.RED) + pc.printout("\n") + sys.exit(0) - def __getAdressesTimes__(self, id): + def __getAdressesTimes__(self, user_id): only_id = {} photos = [] a = None while True: if a is None: - self.api.getUserFeed(id) + self.api.getUserFeed(user_id) a = self.api.LastJson['items'] only_id = self.api.LastJson else: - self.api.getUserFeed(id, only_id['next_max_id']) + self.api.getUserFeed(user_id, only_id['next_max_id']) only_id = self.api.LastJson a = self.api.LastJson['items'] @@ -188,15 +199,30 @@ def getHashtags(self): sortE = sorted(hashtag_counter.items(), key=lambda value: value[1], reverse=True) + file = None + json_data = {} + hashtags_list = [] + if self.writeFile: file_name = "output/" + self.target + "_hashtags.txt" file = open(file_name, "w") - for k, v in sortE: - file.write(str(v) + ". " + str(k.decode('utf-8')) + "\n") - file.close() for k, v in sortE: - print(str(v) + ". " + str(k.decode('utf-8'))) + hashtag = str(k.decode('utf-8')) + print(str(v) + ". " + hashtag) + if self.writeFile: + file.write(str(v) + ". " + hashtag + "\n") + if self.jsonDump: + hashtags_list.append(hashtag) + + if file is not None: + file.close() + + if self.jsonDump: + json_data['hashtags'] = hashtags_list + json_file_name = "output/" + self.target + "_hashtags.json" + with open(json_file_name, 'w') as f: + json.dump(json_data, f) def getTotalLikes(self): if self.is_private: @@ -210,7 +236,7 @@ def getTotalLikes(self): a = None counter = 0 while True: - if (a == None): + if a is None: self.api.getUserFeed(self.target_id) a = self.api.LastJson['items'] only_id = self.api.LastJson @@ -229,12 +255,21 @@ def getTotalLikes(self): if not 'next_max_id' in only_id: break - if (self.writeFile): + if self.writeFile: file_name = "output/" + self.target + "_likes.txt" file = open(file_name, "w") file.write(str(like_counter) + " likes in " + str(counter) + " posts\n") file.close() + if self.jsonDump: + json_data = { + 'like_counter': like_counter, + 'posts': counter + } + json_file_name = "output/" + self.target + "_likes.json" + with open(json_file_name, 'w') as f: + json.dump(json_data, f) + pc.printout(str(like_counter), pc.MAGENTA) pc.printout(" likes in " + str(counter) + " posts\n") @@ -250,7 +285,7 @@ def getTotalComments(self): a = None counter = 0 while True: - if (a == None): + if a is None: self.api.getUserFeed(self.target_id) a = self.api.LastJson['items'] only_id = self.api.LastJson @@ -275,6 +310,15 @@ def getTotalComments(self): file.write(str(comment_counter) + " comments in " + str(counter) + " posts\n") file.close() + if self.jsonDump: + json_data = { + 'comment_counter': comment_counter, + 'posts': counter + } + json_file_name = "output/" + self.target + "_comments.json" + with open(json_file_name, 'w') as f: + json.dump(json_data, f) + pc.printout(str(comment_counter), pc.MAGENTA) pc.printout(" comments in " + str(counter) + " posts\n") @@ -332,15 +376,33 @@ def getPeopleTaggedByUser(self): pc.printout("\nWoohoo! We found " + str(len(ids)) + " (" + str(counter) + ") users\n", pc.GREEN) + json_data = {} + tagged_list = [] + for i in range(len(ids)): t.add_row([post[i], full_name[i], username[i], str(ids[i])]) + if self.jsonDump: + tag = { + 'post': post[i], + 'full_name': full_name[i], + 'username': username[i], + 'id': ids[i] + } + tagged_list.append(tag) + if self.writeFile: file_name = "output/" + self.target + "_tagged.txt" file = open(file_name, "w") file.write(str(t)) file.close() + if self.jsonDump: + json_data['tagged'] = tagged_list + json_file_name = "output/" + self.target + "_tagged.json" + with open(json_file_name, 'w') as f: + json.dump(json_data, f) + print(t) else: pc.printout("Sorry! No results found :-(\n", pc.RED) @@ -361,8 +423,20 @@ def getAddrs(self): pc.printout("\nWoohoo! We found " + str(len(addrs)) + " addresses\n", pc.GREEN) i = 1 + + json_data = {} + addrs_list = [] + for address, time in addrs: t.add_row([str(i), address, time]) + + if self.jsonDump: + addr = { + 'address': address, + 'time': time + } + addrs_list.append(addr) + i = i + 1 if self.writeFile: @@ -371,6 +445,12 @@ def getAddrs(self): file.write(str(t)) file.close() + if self.jsonDump: + json_data['address'] = addrs_list + json_file_name = "output/" + self.target + "_addrs.json" + with open(json_file_name, 'w') as f: + json.dump(json_data, f) + print(t) def getFollowers(self): @@ -386,15 +466,32 @@ def getFollowers(self): t.align["Username"] = "l" t.align["Full Name"] = "l" + json_data = {} + followers_list = [] + for i in followers: t.add_row([str(i['pk']), i['username'], i['full_name']]) + if self.jsonDump: + follower = { + 'id': i['pk'], + 'username': i['username'], + 'full_name': i['full_name'] + } + followers_list.append(follower) + if self.writeFile: file_name = "output/" + self.target + "_followers.txt" file = open(file_name, "w") file.write(str(t)) file.close() + if self.jsonDump: + json_data['followers'] = followers_list + json_file_name = "output/" + self.target + "_followers.json" + with open(json_file_name, 'w') as f: + json.dump(json_data, f) + print(t) def getFollowings(self): @@ -410,15 +507,32 @@ def getFollowings(self): t.align["Username"] = "l" t.align["Full Name"] = "l" + json_data = {} + followings_list = [] + for i in followings: t.add_row([str(i['pk']), i['username'], i['full_name']]) + if self.jsonDump: + follow = { + 'id': i['pk'], + 'username': i['username'], + 'full_name': i['full_name'] + } + followings_list.append(follow) + if self.writeFile: file_name = "output/" + self.target + "_followings.txt" file = open(file_name, "w") file.write(str(t)) file.close() + if self.jsonDump: + json_data['followings'] = followings_list + json_file_name = "output/" + self.target + "_followings.json" + with open(json_file_name, 'w') as f: + json.dump(json_data, f) + print(t) def getUser(self, username): @@ -468,6 +582,20 @@ def getUserInfo(self): pc.printout("[VERIFIED ACCOUNT] ", pc.CYAN) pc.printout(str(data['is_verified']) + '\n') + if self.jsonDump: + user = { + 'id': data['id'], + 'full_name': data['full_name'], + 'biography': data['biography'], + 'edge_followed_by': data['edge_followed_by']['count'], + 'edge_follow': data['edge_follow']['count'], + 'is_business_account': data['is_business_account'], + 'is_verified': data['is_verified'] + } + json_file_name = "output/" + self.target + "_info.json" + with open(json_file_name, 'w') as f: + json.dump(user, f) + except urllib.error.HTTPError as err: if err.code == 404: print("Oops... " + str(self.target) + " non exist, please enter a valid username.") @@ -491,9 +619,20 @@ def getPhotoDescription(self): t.align["Photo"] = "l" t.align["Description"] = "l" + json_data = {} + descriptions_list = [] + for i in dd: node = i.get('node') - t.add_row([str(count), node.get('accessibility_caption')]) + descr = node.get('accessibility_caption') + t.add_row([str(count), descr]) + + if self.jsonDump: + description = { + 'description': descr + } + descriptions_list.append(description) + count += 1 if self.writeFile: @@ -502,6 +641,12 @@ def getPhotoDescription(self): file.write(str(t)) file.close() + if self.jsonDump: + json_data['descriptions'] = descriptions_list + json_file_name = "output/" + self.target + "_descriptions.json" + with open(json_file_name, 'w') as f: + json.dump(json_data, f) + print(t) else: pc.printout("Sorry! No results found :-(\n", pc.RED) @@ -513,13 +658,13 @@ def getUserPhoto(self): limit = -1 pc.printout("How many photos you want to download (default all): ", pc.YELLOW) - l = input() + user_input = input() try: - if l == "": + if user_input == "": pc.printout("Downloading all photos avaible...\n") else: - limit = int(l) - pc.printout("Downloading " + l + " photos...\n") + limit = int(user_input) + pc.printout("Downloading " + user_input + " photos...\n") except ValueError: pc.printout("Wrong value entered\n", pc.RED) @@ -639,7 +784,7 @@ def getCaptions(self): return def getMediaType(self): - if (self.is_private): + if self.is_private: pc.printout("Impossible to execute command: user has private profile\n", pc.RED) return @@ -697,6 +842,15 @@ def getMediaType(self): pc.printout("\nWoohoo! We found " + str(photo_counter) + " photos and " + str(video_counter) \ + " video posted by target\n", pc.GREEN) + if self.jsonDump: + json_data = { + "photos": photo_counter, + "videos": video_counter + } + json_file_name = "output/" + self.target + "_mediatype.json" + with open(json_file_name, 'w') as f: + json.dump(json_data, f) + else: pc.printout("Sorry! No results found :-(\n", pc.RED) @@ -705,28 +859,28 @@ def getMediaType(self): def getUserPropic(self): try: content = urllib.request.urlopen("https://www.instagram.com/" + str(self.target) + "/?__a=1") - except urllib.error.HTTPError as err: - if err.code == 404: - print("Oops... " + str(self.target) + " non exist, please enter a valid username.") - sys.exit(2) - data = json.load(content) + data = json.load(content) - URL = "" + URL = "" - uurl = data["graphql"]["user"] - if "profile_pic_url_hd" in uurl: - URL = data["graphql"]["user"]["profile_pic_url_hd"] - else: - URL = data["graphql"]["user"]["profile_pic_url"] + uurl = data["graphql"]["user"] + if "profile_pic_url_hd" in uurl: + URL = data["graphql"]["user"]["profile_pic_url_hd"] + else: + URL = data["graphql"]["user"]["profile_pic_url"] - if URL != "": - end = "output/" + self.target + "_propic.jpg" - urllib.request.urlretrieve(URL, end) - pc.printout("Target propic saved in output folder\n", pc.GREEN) + if URL != "": + end = "output/" + self.target + "_propic.jpg" + urllib.request.urlretrieve(URL, end) + pc.printout("Target propic saved in output folder\n", pc.GREEN) - else: - pc.printout("Sorry! No results found :-(\n", pc.RED) + else: + pc.printout("Sorry! No results found :-(\n", pc.RED) + except urllib.error.HTTPError as err: + if err.code == 404: + print("Oops... " + str(self.target) + " non exist, please enter a valid username.") + sys.exit(2) def getUserStories(self): if self.is_private: @@ -766,3 +920,15 @@ def changeTarget(self): self.setTarget(line) return + + def setJsonDump(self, flag): + if flag: + pc.printout("Export to JSON: ") + pc.printout("enabled", pc.GREEN) + pc.printout("\n") + else: + pc.printout("Export to JSON: ") + pc.printout("disabled", pc.RED) + pc.printout("\n") + + self.jsonDump = flag diff --git a/printcolors.py b/src/printcolors.py similarity index 59% rename from printcolors.py rename to src/printcolors.py index 41e3dade..953e1ca6 100644 --- a/printcolors.py +++ b/src/printcolors.py @@ -2,8 +2,9 @@ BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8) + def has_colours(stream): - if not (hasattr(stream, "isatty") and stream.isatty()): + if not (hasattr(stream, "isatty") and stream.isatty): return False try: import curses @@ -11,11 +12,14 @@ def has_colours(stream): return curses.tigetnum("colors") > 2 except: return False + + has_colours = has_colours(sys.stdout) + def printout(text, colour=WHITE): - if has_colours: - seq = "\x1b[1;%dm" % (30+colour) + text + "\x1b[0m" - sys.stdout.write(seq) - else: - sys.stdout.write(text) + if has_colours: + seq = "\x1b[1;%dm" % (30 + colour) + text + "\x1b[0m" + sys.stdout.write(seq) + else: + sys.stdout.write(text)