class Osintgram:
    api = None
    geolocator = Nominatim()
    user_id = None
    target_id = None
    is_private = True
    target = ""
    writeFile = False

    def __init__(self, target):
        u = self.__getUsername__()
        p = self.__getPassword__()
        self.api = InstagramAPI(u, p)
        print("\nAttempt to login...")
        self.api.login()
        self.setTarget(target)

    def setTarget(self, target):
        self.target = target
        user = self.getUser(target)
        self.target_id = user['id']
        self.is_private = user['is_private']
        self.__printTargetBanner__()

    def __getUsername__(self):
        u = open("config/username.conf", "r").read()
        u = u.replace("\n", "")
        return u

    def __getPassword__(self):
        p = open("config/pw.conf", "r").read()
        p = p.replace("\n", "")
        return p

    def __getAdressesTimes__(self, id):
        only_id = {}
        photos = []
        a = None
        while True:
            if (a == None):
                self.api.getUserFeed(id)
                a = self.api.LastJson['items']
                only_id = self.api.LastJson
            else:
                self.api.getUserFeed(id, only_id['next_max_id'])
                only_id = self.api.LastJson
                a = self.api.LastJson['items']

            photos.append(a)

            if not 'next_max_id' in only_id:
                break

        locations = {}

        for i in photos:
            for j in i:
                if 'lat' in j.keys():
                    lat = j.get('lat')
                    lng = j.get('lng')

                    locations[str(lat) + ', ' + str(lng)] = j.get('taken_at')

        address = {}
        for k, v in locations.items():
            details = self.geolocator.reverse(k)
            unix_timestamp = datetime.datetime.fromtimestamp(v)
            address[details.address] = unix_timestamp.strftime(
                '%Y-%m-%d %H:%M:%S')

        sort_addresses = sorted(address.items(),
                                key=lambda p: p[1],
                                reverse=True)

        return sort_addresses

    def __printTargetBanner__(self):
        pc.printout("\nLogged as ", pc.GREEN)
        pc.printout(self.api.username, pc.CYAN)
        pc.printout(" (" + str(self.api.username_id) + ") ")
        pc.printout("target: ", pc.GREEN)
        pc.printout(str(self.target), pc.CYAN)
        pc.printout(" (private: " + str(self.is_private) + ")")
        print('\n')

    def setWriteFile(self, bool):
        if (bool):
            pc.printout("Write to file: ")
            pc.printout("enabled", pc.GREEN)
            pc.printout("\n")
        else:
            pc.printout("Write to file: ")
            pc.printout("disabled", pc.RED)
            pc.printout("\n")

        self.writeFile = bool

    def __getUserFollowigs__(self, id):
        following = []
        next_max_id = True
        while next_max_id:
            # first iteration hack
            if next_max_id is True:
                next_max_id = ''
            _ = self.api.getUserFollowings(id, maxid=next_max_id)
            following.extend(self.api.LastJson.get('users', []))
            next_max_id = self.api.LastJson.get('next_max_id', '')

        len(following)
        unique_following = {f['pk']: f for f in following}
        len(unique_following)
        return following

    def __getTotalFollowers__(self, user_id):
        followers = []
        next_max_id = True
        while next_max_id:
            # first iteration hack
            if next_max_id is True:
                next_max_id = ''

            _ = self.api.getUserFollowers(user_id, maxid=next_max_id)
            followers.extend(self.api.LastJson.get('users', []))
            next_max_id = self.api.LastJson.get('next_max_id', '')

        return followers

    def getHashtags(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        pc.printout("Searching for target hashtags...\n")

        text = []
        only_id = {}
        a = None
        hashtags = []
        counter = 1
        while True:
            if (a == None):
                self.api.getUserFeed(self.target_id)
                a = self.api.LastJson['items']
                only_id = self.api.LastJson
                with open('data.json', 'w') as outfile:
                    json.dump(only_id, outfile)

            else:
                self.api.getUserFeed(self.target_id, only_id['next_max_id'])
                only_id = self.api.LastJson
                a = self.api.LastJson['items']

            try:
                for i in a:
                    c = i.get('caption', {}).get('text')
                    text.append(c)
                    counter = counter + 1
            except AttributeError:
                pass

            if not 'next_max_id' in only_id:
                break

        hashtag_counter = {}

        for i in text:
            for j in i.split():
                if j.startswith('#'):
                    hashtags.append(j.encode('UTF-8'))

        for i in hashtags:
            if i in hashtag_counter:
                hashtag_counter[i] += 1
            else:
                hashtag_counter[i] = 1

        sortE = sorted(hashtag_counter.items(),
                       key=lambda value: value[1],
                       reverse=True)

        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')))

    def getTotalLikes(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        pc.printout("Searching for target total likes...\n")

        like_counter = 0
        only_id = {}
        a = None
        counter = 0
        while True:
            if (a == None):
                self.api.getUserFeed(self.target_id)
                a = self.api.LastJson['items']
                only_id = self.api.LastJson
            else:
                self.api.getUserFeed(self.target_id, only_id['next_max_id'])
                only_id = self.api.LastJson
                a = self.api.LastJson['items']
            try:
                for i in a:
                    c = int(i.get('like_count'))
                    like_counter += c
                    counter = counter + 1
            except AttributeError:
                pass

            if not 'next_max_id' in only_id:
                break

        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()

        pc.printout(str(like_counter), pc.MAGENTA)
        pc.printout(" likes in " + str(counter) + " posts\n")

    def getTotalComments(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        pc.printout("Searching for target total comments...\n")

        comment_counter = 0
        only_id = {}
        a = None
        counter = 0
        while True:
            if (a == None):
                self.api.getUserFeed(self.target_id)
                a = self.api.LastJson['items']
                only_id = self.api.LastJson
            else:
                self.api.getUserFeed(self.target_id, only_id['next_max_id'])
                only_id = self.api.LastJson
                a = self.api.LastJson['items']
            try:
                for i in a:
                    c = int(i.get('comment_count'))
                    comment_counter += c
                    counter = counter + 1
            except AttributeError:
                pass

            if not 'next_max_id' in only_id:
                break

        if (self.writeFile):
            file_name = "output/" + self.target + "_comments.txt"
            file = open(file_name, "w")
            file.write(
                str(comment_counter) + " comments in " + str(counter) +
                " posts\n")
            file.close()

        pc.printout(str(comment_counter), pc.MAGENTA)
        pc.printout(" comments in " + str(counter) + " posts\n")

    def getPeopleTaggedByUser(self):
        pc.printout("Searching for users tagged by target...\n")

        ids = []
        username = []
        full_name = []
        post = []
        only_id = {}
        a = None
        counter = 1
        while True:
            if (a == None):
                self.api.getUserFeed(self.target_id)
                a = self.api.LastJson['items']
                only_id = self.api.LastJson

            else:
                self.api.getUserFeed(self.target_id, only_id['next_max_id'])
                only_id = self.api.LastJson
                a = self.api.LastJson['items']

            try:
                for i in a:
                    if "usertags" in i:
                        c = i.get('usertags').get('in')
                        for cc in c:
                            if cc.get('user').get('pk') not in ids:
                                ids.append(cc.get('user').get('pk'))
                                username.append(cc.get('user').get('username'))
                                full_name.append(
                                    cc.get('user').get('full_name'))
                                post.append(1)
                            else:
                                index = ids.index(cc.get('user').get('pk'))
                                post[index] += 1
                            counter = counter + 1
            except AttributeError as ae:
                pc.printout("\nERROR: an error occurred: ", pc.RED)
                print(ae)
                print("")
                pass

            if not 'next_max_id' in only_id:
                break

        if len(ids) > 0:
            t = PrettyTable()

            t.field_names = ['Posts', 'Full Name', 'Username', 'ID']
            t.align["Posts"] = "l"
            t.align["Full Name"] = "l"
            t.align["Username"] = "******"
            t.align["ID"] = "l"

            pc.printout(
                "\nWoohoo! We found " + str(len(ids)) + " (" + str(counter) +
                ") users\n", pc.GREEN)

            for i in range(len(ids)):
                t.add_row([post[i], full_name[i], username[i], str(ids[i])])

            if (self.writeFile):
                file_name = "output/" + self.target + "_tagged.txt"
                file = open(file_name, "w")
                file.write(str(t))
                file.close()

            print(t)
        else:
            pc.printout("Sorry! No results found :-(\n", pc.RED)

    def getAddrs(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        pc.printout(
            "Searching for target address... this may take a few minutes...\n")
        addrs = self.__getAdressesTimes__(self.target_id)
        t = PrettyTable()

        t.field_names = ['Post', 'Address', 'time']
        t.align["Post"] = "l"
        t.align["Address"] = "l"
        t.align["Time"] = "l"
        pc.printout("\nWoohoo! We found " + str(len(addrs)) + " addresses\n",
                    pc.GREEN)

        i = 1
        for address, time in addrs:
            t.add_row([str(i), address, time])
            i = i + 1

        if (self.writeFile):
            file_name = "output/" + self.target + "_addrs.txt"
            file = open(file_name, "w")
            file.write(str(t))
            file.close()

        print(t)

    def getFollowers(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        pc.printout("Searching for target followers...\n")

        followers = self.__getTotalFollowers__(self.target_id)
        t = PrettyTable(['ID', 'Username', 'Full Name'])
        t.align["ID"] = "l"
        t.align["Username"] = "******"
        t.align["Full Name"] = "l"

        for i in followers:
            t.add_row([str(i['pk']), i['username'], i['full_name']])

        if (self.writeFile):
            file_name = "output/" + self.target + "_followers.txt"
            file = open(file_name, "w")
            file.write(str(t))
            file.close()

        print(t)

    def getFollowings(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        pc.printout("Searching for target followings...\n")

        followings = self.__getUserFollowigs__(self.target_id)
        t = PrettyTable(['ID', 'Username', 'Full Name'])
        t.align["ID"] = "l"
        t.align["Username"] = "******"
        t.align["Full Name"] = "l"

        for i in followings:
            t.add_row([str(i['pk']), i['username'], i['full_name']])

        if (self.writeFile):
            file_name = "output/" + self.target + "_followings.txt"
            file = open(file_name, "w")
            file.write(str(t))
            file.close()

        print(t)

    def getUser(self, username):
        try:
            content = urllib.request.urlopen("https://www.instagram.com/" +
                                             username + "/?__a=1")
        except urllib.error.HTTPError as err:
            if (err.code == 404):
                print("Oops... " + username +
                      " non exist, please enter a valid username.")
                sys.exit(2)

        data = json.load(content)

        if (self.writeFile):
            file_name = "output/" + self.target + "_user_id.txt"
            file = open(file_name, "w")
            file.write(str(data['graphql']['user']['id']))
            file.close()

        user = dict()
        user['id'] = data['graphql']['user']['id']
        user['is_private'] = data['graphql']['user']['is_private']

        return user

    def getUserInfo(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 = data['graphql']['user']

        pc.printout("[ID] ", pc.GREEN)
        pc.printout(str(data['id']) + '\n')
        pc.printout("[FULL NAME] ", pc.RED)
        pc.printout(str(data['full_name']) + '\n')
        pc.printout("[BIOGRAPHY] ", pc.CYAN)
        pc.printout(str(data['biography']) + '\n')
        pc.printout("[FOLLOWED] ", pc.GREEN)
        pc.printout(str(data['edge_followed_by']['count']) + '\n')
        pc.printout("[FOLLOW] ", pc.BLUE)
        pc.printout(str(data['edge_follow']['count']) + '\n')
        pc.printout("[BUSINESS ACCOUNT] ", pc.RED)
        pc.printout(str(data['is_business_account']) + '\n')
        if data['is_business_account'] == True:
            pc.printout("[BUSINESS CATEGORY] ")
            pc.printout(str(data['business_category_name']) + '\n')
        pc.printout("[VERIFIED ACCOUNT] ", pc.CYAN)
        pc.printout(str(data['is_verified']) + '\n')

    def getPhotoDescription(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        content = self.api.SendRequest2(self.target + '/?__a=1')
        data = self.api.LastJson
        dd = data['graphql']['user']['edge_owner_to_timeline_media']['edges']

        if len(dd) > 0:
            pc.printout(
                "\nWoohoo! We found " + str(len(dd)) + " descriptions\n",
                pc.GREEN)

            count = 1

            t = PrettyTable(['Photo', 'Description'])
            t.align["Photo"] = "l"
            t.align["Description"] = "l"

            for i in dd:
                node = i.get('node')
                t.add_row([str(count), node.get('accessibility_caption')])
                count += 1

            if (self.writeFile):
                file_name = "output/" + self.target + "_photodes.txt"
                file = open(file_name, "w")
                file.write(str(t))
                file.close()

            print(t)
        else:
            pc.printout("Sorry! No results found :-(\n", pc.RED)

    def getUserPhoto(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        limit = -1
        pc.printout("How many photos you want to download (default all): ",
                    pc.YELLOW)
        l = input()
        try:
            if l == "":
                pc.printout("Downloading all photos avaible...\n")
            else:
                limit = int(l)
                pc.printout("Downloading " + l + " photos...\n")

        except ValueError:
            pc.printout("Wrong value entered\n", pc.RED)
            return

        a = None
        counter = 0
        while True:
            if (a == None):
                self.api.getUserFeed(self.target_id)
                a = self.api.LastJson['items']
                only_id = self.api.LastJson

            else:
                self.api.getUserFeed(self.target_id, only_id['next_max_id'])
                only_id = self.api.LastJson
                a = self.api.LastJson['items']

            try:
                for item in a:
                    if counter == limit:
                        break
                    if "image_versions2" in item:
                        counter = counter + 1
                        url = item["image_versions2"]["candidates"][0]["url"]
                        photo_id = item["id"]
                        end = "output/" + self.target + "_" + photo_id + ".jpg"
                        urllib.request.urlretrieve(url, end)
                        sys.stdout.write("\rDownloaded %i" % counter)
                        sys.stdout.flush()
                    else:
                        carousel = item["carousel_media"]
                        for i in carousel:
                            if counter == limit:
                                break
                            counter = counter + 1
                            url = i["image_versions2"]["candidates"][0]["url"]
                            photo_id = i["id"]
                            end = "output/" + self.target + "_" + photo_id + ".jpg"
                            urllib.request.urlretrieve(url, end)
                            sys.stdout.write("\rDownloaded %i" % counter)
                            sys.stdout.flush()

            except AttributeError:
                pass

            except KeyError:
                pass

            if not 'next_max_id' in only_id:
                break

        sys.stdout.write(" photos")
        sys.stdout.flush()

        pc.printout(
            "\nWoohoo! We downloaded " + str(counter) +
            " photos (saved in output/ folder) \n", pc.GREEN)

    def getCaptions(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        pc.printout("Searching for target captions...\n")

        a = None
        counter = 0
        captions = []
        while True:
            if (a == None):
                self.api.getUserFeed(self.target_id)
                a = self.api.LastJson['items']
                only_id = self.api.LastJson

            else:
                self.api.getUserFeed(self.target_id, only_id['next_max_id'])
                only_id = self.api.LastJson
                a = self.api.LastJson['items']

            try:
                for item in a:
                    if "caption" in item:
                        if item["caption"] != None:
                            text = item["caption"]["text"]
                            captions.append(text)
                            counter = counter + 1
                            sys.stdout.write("\rFound %i" % counter)
                            sys.stdout.flush()

            except AttributeError:
                pass

            except KeyError:
                pass

            if not 'next_max_id' in only_id:
                break

        sys.stdout.write(" captions")
        sys.stdout.flush()

        if counter > 0:
            pc.printout("\nWoohoo! We found " + str(counter) + " captions\n",
                        pc.GREEN)

            if (self.writeFile):
                file_name = "output/" + self.target + "_captions.txt"
                file = open(file_name, "w")
                for s in captions:
                    file.write(s + "\n")
                file.close()

            for s in captions:
                print(s + "\n")

        else:
            pc.printout("Sorry! No results found :-(\n", pc.RED)

        return

    def getMediaType(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        pc.printout("Searching for target captions...\n")

        a = None
        counter = 0
        photo_counter = 0
        video_counter = 0

        while True:
            if (a == None):
                self.api.getUserFeed(self.target_id)
                a = self.api.LastJson['items']
                only_id = self.api.LastJson

            else:
                self.api.getUserFeed(self.target_id, only_id['next_max_id'])
                only_id = self.api.LastJson
                a = self.api.LastJson['items']

            try:
                for item in a:
                    if "media_type" in item:
                        if item["media_type"] == 1:
                            photo_counter = photo_counter + 1
                        elif item["media_type"] == 2:
                            video_counter = video_counter + 1

                        counter = counter + 1
                        sys.stdout.write("\rChecked %i" % counter)
                        sys.stdout.flush()

            except AttributeError:
                pass

            except KeyError:
                pass

            if not 'next_max_id' in only_id:
                break

        sys.stdout.write(" posts")
        sys.stdout.flush()

        if counter > 0:

            if (self.writeFile):
                file_name = "output/" + self.target + "_mediatype.txt"
                file = open(file_name, "w")
                file.write(str(photo_counter) + " photos and " + str(video_counter) \
                        + " video posted by target\n")
                file.close()


            pc.printout("\nWoohoo! We found " + str(photo_counter) + " photos and " + str(video_counter) \
                        + " video posted by target\n", pc.GREEN)

        else:
            pc.printout("Sorry! No results found :-(\n", pc.RED)

        return

    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)

        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)

        else:
            pc.printout("Sorry! No results found :-(\n", pc.RED)

    def getUserStories(self):
        if (self.is_private):
            pc.printout(
                "Impossible to execute command: user has private profile\n",
                pc.RED)
            return

        pc.printout("Searching for target stories...\n")

        endpoint = 'feed/user/{id!s}/story/'.format(**{'id': self.target_id})
        content = self.api.SendRequest(endpoint)
        data = self.api.LastJson
        counter = 0

        if data['reel'] != None:  # no stories avaibile
            for i in data['reel']['items']:
                story_id = i["id"]
                if i["media_type"] == 1:  # it's a photo
                    url = i['image_versions2']['candidates'][0]['url']
                    end = "output/" + self.target + "_" + story_id + ".jpg"
                    urllib.request.urlretrieve(url, end)
                    counter += 1

                elif i["media_type"] == 2:  # it's a gif or video
                    url = i['video_versions'][0]['url']
                    end = "output/" + self.target + "_" + story_id + ".mp4"
                    urllib.request.urlretrieve(url, end)
                    counter += 1

        if counter > 0:
            pc.printout(
                str(counter) + " target stories saved in output folder\n",
                pc.GREEN)
        else:
            pc.printout("Sorry! No results found :-(\n", pc.RED)

    def changeTarget(self):
        pc.printout("Insert new target username: ", pc.YELLOW)
        l = input()
        self.setTarget(l)

        return
예제 #2
0
class Osintgram:
    api = None
    geolocator = Nominatim()
    user_id = None
    target = ""

    def __init__(self, target):
        self.target = target
        u = self.__getUsername__()
        p = self.__getPassword__()
        self.api = InstagramAPI(u, p)
        print("\nAttempt to login...\n")
        self.api.login()
        pc.printout("Logged as ", pc.GREEN)
        pc.printout(self.api.username, pc.CYAN)
        pc.printout(" (" + str(self.api.username_id) + ") ")
        pc.printout("target: ", pc.GREEN)
        pc.printout(str(self.target), pc.CYAN)
        print('\n')

    def __getUsername__(self):
        u = open("config/username.conf", "r").read()
        u = u.replace("\n", "")
        return u
    
    def __getPassword__(self):
        p = open("config/pw.conf", "r").read()
        p = p.replace("\n", "")
        return p

    def __getAdressesTimes__(self, id):
        only_id = {} #var only for max_next_id parameter | pagination
        photos = [] # only photos
        a = None #helper
        while True:
            if (a == None):
                self.api.getUserFeed(id)
                a = self.api.LastJson['items']#photos 00, 01, 02...
                only_id = self.api.LastJson #all LastJson with max_id param
            else:
                self.api.getUserFeed(id, only_id['next_max_id']) #passing parameter max_id
                only_id = self.api.LastJson
                a = self.api.LastJson['items']
                
            photos.append(a)

            if not 'next_max_id' in only_id:
                break


        locations = {}

        for i in photos: #extract location from photos, related
            for j in i:
                if 'lat' in j.keys():
                    lat = j.get('lat')
                    lng = j.get('lng')

                    locations[str(lat) + ', ' + str(lng)] = j.get('taken_at')

        address = {}
        for k,v in locations.items():
            details = self.geolocator.reverse(k) #locate for key
            unix_timestamp = datetime.datetime.fromtimestamp(v) # read timestamp as a value
            address[details.address] = unix_timestamp.strftime('%Y-%m-%d %H:%M:%S')


        sort_addresses = sorted(address.items(), key=lambda p: p[1], reverse=True)  #sorting

        return sort_addresses 


    def __getUserFollowigs__(self, id):
        following = []
        next_max_id = True
        while next_max_id:
            # first iteration hack
            if next_max_id is True:
                next_max_id = ''
            _ = self.api.getUserFollowings(id, maxid=next_max_id)
            following.extend(self.api.LastJson.get('users', []))
            next_max_id = self.api.LastJson.get('next_max_id', '')

        len(following)
        unique_following = {
            f['pk']: f
            for f in following
        }
        len(unique_following)
        return following

    def __getTotalFollowers__(self, user_id):
        followers = []
        next_max_id = True
        while next_max_id:
            # first iteration hack
            if next_max_id is True:
                next_max_id = ''

            _ = self.api.getUserFollowers(user_id, maxid=next_max_id)
            followers.extend(self.api.LastJson.get('users', []))
            next_max_id = self.api.LastJson.get('next_max_id', '')

        return followers

        
    def getHashtags(self, id):
        pc.printout("Searching for target hashtags...\n")

        text = []
        only_id = {}
        a = None #helper
        hashtags = []
        counter = 1
        while True:
            if (a == None):
                self.api.getUserFeed(id)
                a = self.api.LastJson['items']#photos 00, 01, 02...
                only_id = self.api.LastJson #all LastJson with max_id param
                with open('data.json', 'w') as outfile:
                    json.dump(only_id, outfile)
                
            else:
                self.api.getUserFeed(id, only_id['next_max_id']) #passing parameter max_id
                only_id = self.api.LastJson
                a = self.api.LastJson['items']

            try:
                for i in a:
                    c = i.get('caption', {}).get('text')
                    text.append(c)
                    #print str(counter) + ' ' + c
                    counter = counter +1
            except AttributeError:
                pass

            if not 'next_max_id' in only_id:
                break

        hashtag_counter = {}

        for i in text:
            for j in i.split():
                if j.startswith('#'):
                    hashtags.append(j.encode('UTF-8'))

        for i in hashtags:
            if i in hashtag_counter:
                hashtag_counter[i] += 1
            else:
                hashtag_counter[i] = 1

        sortE = sorted(hashtag_counter.items(), key=lambda value: value[1], reverse=True)

        for k,v in sortE:
            print( str(v) + ". " + str(k.decode('utf-8')))

    def getTotalLikes(self, id):
        pc.printout("Searching for target total likes...\n")

        like_counter = 0
        only_id = {}
        a = None #helper
        counter = 0
        while True:
            if (a == None):
                self.api.getUserFeed(id)
                a = self.api.LastJson['items']#photos 00, 01, 02...
                only_id = self.api.LastJson #all LastJson with max_id param
            else:
                self.api.getUserFeed(id, only_id['next_max_id']) #passing parameter max_id
                only_id = self.api.LastJson
                a = self.api.LastJson['items']
            try:
                for i in a:
                    c = int(i.get('like_count'))
                    like_counter += c
                    counter = counter +1
            except AttributeError:
                pass

            if not 'next_max_id' in only_id:
                break
        pc.printout(str(like_counter), pc.MAGENTA)
        pc.printout(" likes in " + str(counter) + " posts\n")
    
    def getTotalComments(self, id):
        pc.printout("Searching for target total comments...\n")

        comment_counter = 0
        only_id = {}
        a = None #helper
        counter = 0
        while True:
            if (a == None):
                self.api.getUserFeed(id)
                a = self.api.LastJson['items']#photos 00, 01, 02...
                only_id = self.api.LastJson #all LastJson with max_id param
            else:
                self.api.getUserFeed(id, only_id['next_max_id']) #passing parameter max_id
                only_id = self.api.LastJson
                a = self.api.LastJson['items']
            try:
                for i in a:
                    c = int(i.get('comment_count'))
                    comment_counter += c
                    counter = counter +1
            except AttributeError:
                pass

            if not 'next_max_id' in only_id:
                break
        pc.printout(str(comment_counter), pc.MAGENTA)
        pc.printout(" comments in " + str(counter) + " posts\n")

    def getPeopleTaggedByUser(self, id):
        pc.printout("Searching for users tagged by target...\n")
        
        ids = []
        username = []
        full_name = []
        post = []
        only_id = {}
        a = None #helper
        counter = 1
        while True:
            if (a == None):
                self.api.getUserFeed(id)
                a = self.api.LastJson['items']#photos 00, 01, 02...
                only_id = self.api.LastJson #all LastJson with max_id param

                
            else:
                self.api.getUserFeed(id, only_id['next_max_id']) #passing parameter max_id
                only_id = self.api.LastJson
                a = self.api.LastJson['items']

            try:
                for i in a:
                    c = i.get('usertags').get('in')
                    for cc in c:
                        if cc.get('user').get('pk') not in ids:
                            ids.append(cc.get('user').get('pk'))
                            username.append(cc.get('user').get('username'))
                            full_name.append(cc.get('user').get('full_name'))
                            post.append(1)
                        else:
                            index = ids.index(cc.get('user').get('pk'))
                            post[index] += 1
                        counter = counter +1
            except AttributeError:
                pass

            if not 'next_max_id' in only_id:
                break

        if len(ids) > 0:
            t = PrettyTable()

            t.field_names = ['Posts', 'Full Name', 'Username', 'ID']
            t.align["Posts"] = "l"
            t.align["Full Name"] = "l"
            t.align["Username"] = "******"
            t.align["ID"] = "l"
            
            pc.printout("\nWoohoo! We found " + str(len(ids)) + " (" + str(counter) + ") users\n", pc.GREEN)

            for i in range(len(ids)):
                t.add_row([post[i], full_name[i], username[i], str(ids[i])])

            print(t)
        else:
            pc.printout("Sorry! No results found :-(\n", pc.RED)



    def getAddrs(self, id):
        pc.printout("Searching for target address... this may take a few minutes...\n")
        addrs = self.__getAdressesTimes__(id)
        t = PrettyTable()

        t.field_names = ['Post', 'Address', 'time']
        t.align["Post"] = "l"
        t.align["Address"] = "l"
        t.align["Time"] = "l"
        pc.printout("\nWoohoo! We found " + str(len(addrs)) + " addresses\n", pc.GREEN)

        i = 1
        for address, time in addrs:
            t.add_row([str(i), address, time])
            i = i + 1
        print(t)

    def getFollowers(self, id):
        pc.printout("Searching for target followers...\n")

        followers = self.__getTotalFollowers__(id)
        t = PrettyTable(['ID', 'Username', 'Full Name'])
        t.align["ID"] = "l"
        t.align["Username"] = "******"
        t.align["Full Name"] = "l"
        
        for i in followers:
            t.add_row([str(i['pk']), i['username'], i['full_name']])
        print(t)

    def getFollowings(self, id):
        pc.printout("Searching for target followings...\n")

        followings = self.__getUserFollowigs__(id)
        t = PrettyTable(['ID', 'Username', 'Full Name'])
        t.align["ID"] = "l"
        t.align["Username"] = "******"
        t.align["Full Name"] = "l"
        
        for i in followings:
            t.add_row([str(i['pk']), i['username'], i['full_name']])
        print(t)

    def getUserID(self, username):
        try:
            content = urllib.request.urlopen("https://www.instagram.com/" + username + "/?__a=1" )
        except urllib.error.HTTPError as err: 
            if(err.code == 404):
                print("Oops... " + username + " non exist, please enter a valid username.")
                sys.exit(2)

        data = json.load(content)
        return data['graphql']['user']['id']

    def getUserInfo(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 = data['graphql']['user']

        pc.printout("[ID] ", pc.GREEN)
        pc.printout(str(data['id']) + '\n')
        pc.printout("[FULL NAME] ", pc.RED)
        pc.printout(str(data['full_name']) + '\n')
        pc.printout("[BIOGRAPHY] ", pc.CYAN)
        pc.printout(str(data['biography']) + '\n')
        pc.printout("[FOLLOWED] ", pc.GREEN)
        pc.printout(str(data['edge_followed_by']['count']) + '\n')
        pc.printout("[FOLLOW] ", pc.BLUE)
        pc.printout(str(data['edge_follow']['count']) + '\n')
        pc.printout("[BUSINESS ACCOUNT] ", pc.RED)
        pc.printout(str(data['is_business_account']) + '\n')
        if data['is_business_account'] == True:
            pc.printout("[BUSINESS CATEGORY] ")
            pc.printout(str(data['business_category_name']) + '\n')
        pc.printout("[VERIFIED ACCOUNT] ", pc.CYAN)
        pc.printout(str(data['is_verified']) + '\n')


    def getPhotoDescription(self):
        content = self.api.SendRequest2(self.target + '/?__a=1')
        data = self.api.LastJson
        dd = data['graphql']['user']['edge_owner_to_timeline_media']['edges']

        if len(dd) > 0:
            pc.printout("\nWoohoo! We found " + str(len(dd)) + " descriptions\n", pc.GREEN)

            count = 1

            t = PrettyTable(['Photo', 'Description'])
            t.align["Photo"] = "l"
            t.align["Description"] = "l"
            
            for i in dd:
                node = i.get('node')
                t.add_row([str(count), node.get('accessibility_caption')])
                count += 1
            print(t)
        else:
            pc.printout("Sorry! No results found :-(\n", pc.RED)