| skipped 4 lines |
5 | 5 | | import os |
6 | 6 | | import codecs |
7 | 7 | | |
| 8 | + | import requests |
| 9 | + | |
8 | 10 | | from geopy.geocoders import Nominatim |
9 | 11 | | from instagram_private_api import Client as AppClient |
10 | 12 | | from instagram_private_api import ClientCookieExpiredError, ClientLoginRequiredError, ClientError |
| skipped 92 lines |
103 | 105 | | pc.printout(" [FOLLOWING]", pc.GREEN) |
104 | 106 | | else: |
105 | 107 | | pc.printout(" [NOT FOLLOWING]", pc.RED) |
106 | | - | |
107 | 108 | | |
108 | 109 | | print('\n') |
109 | 110 | | |
| skipped 330 lines |
440 | 441 | | pc.printout("Sorry! No results found :-(\n", pc.RED) |
441 | 442 | | |
442 | 443 | | def get_user_info(self): |
443 | | - | try: |
444 | | - | content = urllib.request.urlopen("https://www.instagram.com/" + str(self.target) + "/?__a=1") |
445 | | - | data = json.load(content) |
446 | | - | data = data['graphql']['user'] |
| 444 | + | content = requests.get("https://www.instagram.com/" + str(self.target) + "/?__a=1") |
| 445 | + | |
| 446 | + | if content.status_code == 404: |
| 447 | + | print("Oops... " + str(self.target) + " non exist, please enter a valid username.") |
| 448 | + | sys.exit(2) |
| 449 | + | |
| 450 | + | data = content.json() |
| 451 | + | data = data['graphql']['user'] |
| 452 | + | |
| 453 | + | pc.printout("[ID] ", pc.GREEN) |
| 454 | + | pc.printout(str(data['id']) + '\n') |
| 455 | + | pc.printout("[FULL NAME] ", pc.RED) |
| 456 | + | pc.printout(str(data['full_name']) + '\n') |
| 457 | + | pc.printout("[BIOGRAPHY] ", pc.CYAN) |
| 458 | + | pc.printout(str(data['biography']) + '\n') |
| 459 | + | pc.printout("[FOLLOWED] ", pc.BLUE) |
| 460 | + | pc.printout(str(data['edge_followed_by']['count']) + '\n') |
| 461 | + | pc.printout("[FOLLOW] ", pc.GREEN) |
| 462 | + | pc.printout(str(data['edge_follow']['count']) + '\n') |
| 463 | + | pc.printout("[BUSINESS ACCOUNT] ", pc.RED) |
| 464 | + | pc.printout(str(data['is_business_account']) + '\n') |
| 465 | + | if data['is_business_account']: |
| 466 | + | pc.printout("[BUSINESS CATEGORY] ") |
| 467 | + | pc.printout(str(data['business_category_name']) + '\n') |
| 468 | + | pc.printout("[VERIFIED ACCOUNT] ", pc.CYAN) |
| 469 | + | pc.printout(str(data['is_verified']) + '\n') |
| 470 | + | if data['business_email']: |
| 471 | + | pc.printout("[BUSINESS EMAIL] ", pc.BLUE) |
| 472 | + | pc.printout(str(data['business_email']) + '\n') |
| 473 | + | pc.printout("[HD PROFILE PIC] ", pc.GREEN) |
| 474 | + | pc.printout(str(data['profile_pic_url_hd']) + '\n') |
| 475 | + | if data['connected_fb_page']: |
| 476 | + | pc.printout("[FB PAGE] ", pc.RED) |
| 477 | + | pc.printout(str(data['business_email']) + '\n') |
447 | 478 | | |
448 | | - | pc.printout("[ID] ", pc.GREEN) |
449 | | - | pc.printout(str(data['id']) + '\n') |
450 | | - | pc.printout("[FULL NAME] ", pc.RED) |
451 | | - | pc.printout(str(data['full_name']) + '\n') |
452 | | - | pc.printout("[BIOGRAPHY] ", pc.CYAN) |
453 | | - | pc.printout(str(data['biography']) + '\n') |
454 | | - | pc.printout("[FOLLOWED] ", pc.BLUE) |
455 | | - | pc.printout(str(data['edge_followed_by']['count']) + '\n') |
456 | | - | pc.printout("[FOLLOW] ", pc.GREEN) |
457 | | - | pc.printout(str(data['edge_follow']['count']) + '\n') |
458 | | - | pc.printout("[BUSINESS ACCOUNT] ", pc.RED) |
459 | | - | pc.printout(str(data['is_business_account']) + '\n') |
460 | | - | if data['is_business_account']: |
461 | | - | pc.printout("[BUSINESS CATEGORY] ") |
462 | | - | pc.printout(str(data['business_category_name']) + '\n') |
463 | | - | pc.printout("[VERIFIED ACCOUNT] ", pc.CYAN) |
464 | | - | pc.printout(str(data['is_verified']) + '\n') |
| 479 | + | if self.jsonDump: |
| 480 | + | user = { |
| 481 | + | 'id': data['id'], |
| 482 | + | 'full_name': data['full_name'], |
| 483 | + | 'biography': data['biography'], |
| 484 | + | 'edge_followed_by': data['edge_followed_by']['count'], |
| 485 | + | 'edge_follow': data['edge_follow']['count'], |
| 486 | + | 'is_business_account': data['is_business_account'], |
| 487 | + | 'is_verified': data['is_verified'], |
| 488 | + | 'profile_pic_url_hd': data['profile_pic_url_hd'] |
| 489 | + | } |
465 | 490 | | if data['business_email']: |
466 | | - | pc.printout("[BUSINESS EMAIL] ", pc.BLUE) |
467 | | - | pc.printout(str(data['business_email']) + '\n') |
468 | | - | pc.printout("[HD PROFILE PIC] ", pc.GREEN) |
469 | | - | pc.printout(str(data['profile_pic_url_hd']) + '\n') |
| 491 | + | user['business_email'] = data['business_email'] |
470 | 492 | | if data['connected_fb_page']: |
471 | | - | pc.printout("[FB PAGE] ", pc.RED) |
472 | | - | pc.printout(str(data['business_email']) + '\n') |
473 | | - | |
474 | | - | if self.jsonDump: |
475 | | - | user = { |
476 | | - | 'id': data['id'], |
477 | | - | 'full_name': data['full_name'], |
478 | | - | 'biography': data['biography'], |
479 | | - | 'edge_followed_by': data['edge_followed_by']['count'], |
480 | | - | 'edge_follow': data['edge_follow']['count'], |
481 | | - | 'is_business_account': data['is_business_account'], |
482 | | - | 'is_verified': data['is_verified'], |
483 | | - | 'profile_pic_url_hd': data['profile_pic_url_hd'] |
484 | | - | } |
485 | | - | if data['business_email']: |
486 | | - | user['business_email'] = data['business_email'] |
487 | | - | if data['connected_fb_page']: |
488 | | - | user['connected_fb_page'] = data['connected_fb_page'] |
489 | | - | |
490 | | - | json_file_name = "output/" + self.target + "_info.json" |
491 | | - | with open(json_file_name, 'w') as f: |
492 | | - | json.dump(user, f) |
| 493 | + | user['connected_fb_page'] = data['connected_fb_page'] |
493 | 494 | | |
494 | | - | except urllib.error.HTTPError as err: |
495 | | - | if err.code == 404: |
496 | | - | print("Oops... " + str(self.target) + " non exist, please enter a valid username.") |
497 | | - | sys.exit(2) |
| 495 | + | json_file_name = "output/" + self.target + "_info.json" |
| 496 | + | with open(json_file_name, 'w') as f: |
| 497 | + | json.dump(user, f) |
498 | 498 | | |
499 | 499 | | def get_total_likes(self): |
500 | 500 | | if self.check_private_profile(): |
| skipped 157 lines |
658 | 658 | | users = [] |
659 | 659 | | |
660 | 660 | | for post in posts: |
661 | | - | if not any(u['id'] == post['user']['pk'] for u in users): |
662 | | - | user = { |
663 | | - | 'id': post['user']['pk'], |
664 | | - | 'username': post['user']['username'], |
665 | | - | 'full_name': post['user']['full_name'], |
666 | | - | 'counter': 1 |
667 | | - | } |
668 | | - | users.append(user) |
669 | | - | else: |
670 | | - | for user in users: |
671 | | - | if user['id'] == post['user']['pk']: |
672 | | - | user['counter'] += 1 |
673 | | - | break |
| 661 | + | if not any(u['id'] == post['user']['pk'] for u in users): |
| 662 | + | user = { |
| 663 | + | 'id': post['user']['pk'], |
| 664 | + | 'username': post['user']['username'], |
| 665 | + | 'full_name': post['user']['full_name'], |
| 666 | + | 'counter': 1 |
| 667 | + | } |
| 668 | + | users.append(user) |
| 669 | + | else: |
| 670 | + | for user in users: |
| 671 | + | if user['id'] == post['user']['pk']: |
| 672 | + | user['counter'] += 1 |
| 673 | + | break |
674 | 674 | | |
675 | 675 | | ssort = sorted(users, key=lambda value: value['counter'], reverse=True) |
676 | 676 | | |
| skipped 30 lines |
707 | 707 | | if self.check_private_profile(): |
708 | 708 | | return |
709 | 709 | | |
710 | | - | content = urllib.request.urlopen("https://www.instagram.com/" + str(self.target) + "/?__a=1") |
711 | | - | data = json.load(content) |
| 710 | + | content = requests.get("https://www.instagram.com/" + str(self.target) + "/?__a=1") |
| 711 | + | data = content.json() |
| 712 | + | |
712 | 713 | | dd = data['graphql']['user']['edge_owner_to_timeline_media']['edges'] |
713 | 714 | | |
714 | 715 | | if len(dd) > 0: |
| skipped 104 lines |
819 | 820 | | pc.printout("\nWoohoo! We downloaded " + str(counter) + " photos (saved in output/ folder) \n", pc.GREEN) |
820 | 821 | | |
821 | 822 | | def get_user_propic(self): |
822 | | - | try: |
823 | | - | content = urllib.request.urlopen("https://www.instagram.com/" + str(self.target) + "/?__a=1") |
| 823 | + | content = requests.get("https://www.instagram.com/" + str(self.target) + "/?__a=1") |
824 | 824 | | |
825 | | - | data = json.load(content) |
| 825 | + | if content.status_code == 404: |
| 826 | + | print("Oops... " + str(self.target) + " non exist, please enter a valid username.") |
| 827 | + | sys.exit(2) |
| 828 | + | |
| 829 | + | data = content.json() |
826 | 830 | | |
827 | | - | uurl = data["graphql"]["user"] |
828 | | - | if "profile_pic_url_hd" in uurl: |
829 | | - | URL = data["graphql"]["user"]["profile_pic_url_hd"] |
830 | | - | else: |
831 | | - | URL = data["graphql"]["user"]["profile_pic_url"] |
| 831 | + | uurl = data["graphql"]["user"] |
| 832 | + | if "profile_pic_url_hd" in uurl: |
| 833 | + | URL = data["graphql"]["user"]["profile_pic_url_hd"] |
| 834 | + | else: |
| 835 | + | URL = data["graphql"]["user"]["profile_pic_url"] |
832 | 836 | | |
833 | | - | if URL != "": |
834 | | - | end = "output/" + self.target + "_propic.jpg" |
835 | | - | urllib.request.urlretrieve(URL, end) |
836 | | - | pc.printout("Target propic saved in output folder\n", pc.GREEN) |
| 837 | + | if URL != "": |
| 838 | + | end = "output/" + self.target + "_propic.jpg" |
| 839 | + | urllib.request.urlretrieve(URL, end) |
| 840 | + | pc.printout("Target propic saved in output folder\n", pc.GREEN) |
837 | 841 | | |
838 | | - | else: |
839 | | - | pc.printout("Sorry! No results found :-(\n", pc.RED) |
840 | | - | except urllib.error.HTTPError as err: |
841 | | - | if err.code == 404: |
842 | | - | print("Oops... " + str(self.target) + " non exist, please enter a valid username.") |
843 | | - | sys.exit(2) |
| 842 | + | else: |
| 843 | + | pc.printout("Sorry! No results found :-(\n", pc.RED) |
844 | 844 | | |
845 | 845 | | def get_user_stories(self): |
846 | 846 | | if self.check_private_profile(): |
| skipped 1 lines |
848 | 848 | | |
849 | 849 | | pc.printout("Searching for target stories...\n") |
850 | 850 | | |
851 | | - | endpoint = 'feed/user/{id!s}/story/'.format(**{'id': self.target_id}) |
852 | | - | content = urllib.request.urlopen("https://www.instagram.com/" + endpoint) |
853 | | - | data = json.load(content) |
| 851 | + | data = self.api.user_reel_media(str(self.target_id)) |
| 852 | + | |
854 | 853 | | counter = 0 |
855 | 854 | | |
856 | | - | if data['reel'] is not None: # no stories avaibile |
857 | | - | for i in data['reel']['items']: |
| 855 | + | if data['items'] is not None: # no stories avaibile |
| 856 | + | counter = data['media_count'] |
| 857 | + | for i in data['items']: |
858 | 858 | | story_id = i["id"] |
859 | 859 | | if i["media_type"] == 1: # it's a photo |
860 | 860 | | url = i['image_versions2']['candidates'][0]['url'] |
861 | 861 | | end = "output/" + self.target + "_" + story_id + ".jpg" |
862 | 862 | | urllib.request.urlretrieve(url, end) |
863 | | - | counter += 1 |
864 | 863 | | |
865 | 864 | | elif i["media_type"] == 2: # it's a gif or video |
866 | 865 | | url = i['video_versions'][0]['url'] |
867 | 866 | | end = "output/" + self.target + "_" + story_id + ".mp4" |
868 | 867 | | urllib.request.urlretrieve(url, end) |
869 | | - | counter += 1 |
870 | 868 | | |
871 | 869 | | if counter > 0: |
872 | 870 | | pc.printout(str(counter) + " target stories saved in output folder\n", pc.GREEN) |
| skipped 74 lines |
947 | 945 | | pc.printout("Sorry! No results found :-(\n", pc.RED) |
948 | 946 | | |
949 | 947 | | def get_user(self, username): |
950 | | - | try: |
951 | | - | content = urllib.request.urlopen("https://www.instagram.com/" + username + "/?__a=1") |
952 | | - | data = json.load(content) |
953 | | - | if self.writeFile: |
954 | | - | file_name = "output/" + self.target + "_user_id.txt" |
955 | | - | file = open(file_name, "w") |
956 | | - | file.write(str(data['graphql']['user']['id'])) |
957 | | - | file.close() |
| 948 | + | content = requests.get("https://www.instagram.com/" + username + "/?__a=1") |
958 | 949 | | |
959 | | - | user = dict() |
960 | | - | user['id'] = data['graphql']['user']['id'] |
961 | | - | user['is_private'] = data['graphql']['user']['is_private'] |
| 950 | + | if content.status_code == 404: |
| 951 | + | print("Oops... " + str(self.target) + " non exist, please enter a valid username.") |
| 952 | + | sys.exit(2) |
962 | 953 | | |
963 | | - | return user |
| 954 | + | data = content.json() |
964 | 955 | | |
965 | | - | except urllib.error.HTTPError as err: |
966 | | - | if err.code == 404: |
967 | | - | print("Oops... " + username + " non exist, please enter a valid username.") |
968 | | - | sys.exit(2) |
| 956 | + | if self.writeFile: |
| 957 | + | file_name = "output/" + self.target + "_user_id.txt" |
| 958 | + | file = open(file_name, "w") |
| 959 | + | file.write(str(data['graphql']['user']['id'])) |
| 960 | + | file.close() |
969 | 961 | | |
970 | | - | return None |
| 962 | + | user = dict() |
| 963 | + | user['id'] = data['graphql']['user']['id'] |
| 964 | + | user['is_private'] = data['graphql']['user']['is_private'] |
| 965 | + | |
| 966 | + | return user |
971 | 967 | | |
972 | 968 | | def set_write_file(self, flag): |
973 | 969 | | if flag: |
| skipped 33 lines |
1007 | 1003 | | else: |
1008 | 1004 | | with open(settings_file) as file_data: |
1009 | 1005 | | cached_settings = json.load(file_data, object_hook=self.from_json) |
1010 | | - | #print('Reusing settings: {0!s}'.format(settings_file)) |
| 1006 | + | # print('Reusing settings: {0!s}'.format(settings_file)) |
1011 | 1007 | | |
1012 | 1008 | | # reuse auth settings |
1013 | 1009 | | self.api = AppClient( |
| skipped 10 lines |
1024 | 1020 | | on_login=lambda x: self.onlogin_callback(x, settings_file)) |
1025 | 1021 | | |
1026 | 1022 | | except ClientError as e: |
1027 | | - | #pc.printout('ClientError {0!s} (Code: {1:d}, Response: {2!s})'.format(e.msg, e.code, e.error_response), pc.RED) |
| 1023 | + | # pc.printout('ClientError {0!s} (Code: {1:d}, Response: {2!s})'.format(e.msg, e.code, e.error_response), pc.RED) |
1028 | 1024 | | error = json.loads(e.error_response) |
1029 | 1025 | | pc.printout(error['message'], pc.RED) |
1030 | 1026 | | pc.printout("\n") |
| skipped 14 lines |
1045 | 1041 | | cache_settings = api.settings |
1046 | 1042 | | with open(new_settings_file, 'w') as outfile: |
1047 | 1043 | | json.dump(cache_settings, outfile, default=self.to_json) |
1048 | | - | #print('SAVED: {0!s}'.format(new_settings_file)) |
| 1044 | + | # print('SAVED: {0!s}'.format(new_settings_file)) |
1049 | 1045 | | |
1050 | 1046 | | def check_following(self): |
1051 | 1047 | | endpoint = 'users/{user_id!s}/full_detail_info/'.format(**{'user_id': self.target_id}) |
| skipped 2 lines |
1054 | 1050 | | def check_private_profile(self): |
1055 | 1051 | | if self.is_private and not self.following: |
1056 | 1052 | | pc.printout("Impossible to execute command: user has private profile\n", pc.RED) |
| 1053 | + | send = input("Do you want send a follow request? [Y/N]: ") |
| 1054 | + | if send.lower() == "y": |
| 1055 | + | self.api.friendships_create(self.target_id) |
| 1056 | + | print("Sent a follow request to target. Use this command after target accepting the request.") |
| 1057 | + | |
1057 | 1058 | | return True |
1058 | 1059 | | return False |
1059 | 1060 | | |
| skipped 19 lines |
1079 | 1080 | | results = [] |
1080 | 1081 | | |
1081 | 1082 | | for follow in followers: |
1082 | | - | req = urllib.request.urlopen("https://www.instagram.com/" + str(follow['username']) + "/?__a=1") |
1083 | | - | data = json.load(req)['graphql']['user'] |
| 1083 | + | content = requests.get("https://www.instagram.com/" + str(follow['username']) + "/?__a=1") |
| 1084 | + | data = content.json() |
| 1085 | + | data = data['graphql']['user'] |
1084 | 1086 | | if data['business_email']: |
1085 | 1087 | | follow['email'] = data['business_email'] |
1086 | 1088 | | results.append(follow) |
| skipped 12 lines |
1099 | 1101 | | t.add_row([str(node['id']), node['username'], node['full_name'], node['email']]) |
1100 | 1102 | | |
1101 | 1103 | | if self.writeFile: |
1102 | | - | file_name = "output/" + self.target + "_followers.txt" |
| 1104 | + | file_name = "output/" + self.target + "_fwersemail.txt" |
1103 | 1105 | | file = open(file_name, "w") |
1104 | 1106 | | file.write(str(t)) |
1105 | 1107 | | file.close() |
1106 | 1108 | | |
1107 | 1109 | | if self.jsonDump: |
1108 | | - | json_data['followers'] = results |
1109 | | - | json_file_name = "output/" + self.target + "_followers.json" |
| 1110 | + | json_data['followers_email'] = results |
| 1111 | + | json_file_name = "output/" + self.target + "_fwersemail.json" |
1110 | 1112 | | with open(json_file_name, 'w') as f: |
1111 | 1113 | | json.dump(json_data, f) |
1112 | 1114 | | |
| skipped 1 lines |
1114 | 1116 | | else: |
1115 | 1117 | | pc.printout("Sorry! No results found :-(\n", pc.RED) |
1116 | 1118 | | |
| 1119 | + | def get_fwingsemail(self): |
| 1120 | + | if self.check_private_profile(): |
| 1121 | + | return |
1117 | 1122 | | |
| 1123 | + | pc.printout("Searching for emails of users followed by target... this can take a few minutes\n") |
1118 | 1124 | | |
| 1125 | + | followings = [] |
1119 | 1126 | | |
| 1127 | + | rank_token = AppClient.generate_uuid() |
| 1128 | + | data = self.api.user_following(str(self.target_id), rank_token=rank_token) |
1120 | 1129 | | |
| 1130 | + | for user in data['users']: |
| 1131 | + | u = { |
| 1132 | + | 'id': user['pk'], |
| 1133 | + | 'username': user['username'], |
| 1134 | + | 'full_name': user['full_name'] |
| 1135 | + | } |
| 1136 | + | followings.append(u) |
1121 | 1137 | | |
| 1138 | + | results = [] |
1122 | 1139 | | |
| 1140 | + | for follow in followings: |
| 1141 | + | content = requests.get("https://www.instagram.com/" + str(follow['username']) + "/?__a=1") |
| 1142 | + | data = content.json() |
| 1143 | + | data = data['graphql']['user'] |
| 1144 | + | if data['business_email']: |
| 1145 | + | follow['email'] = data['business_email'] |
| 1146 | + | results.append(follow) |
1123 | 1147 | | |
| 1148 | + | if len(results) > 0: |
1124 | 1149 | | |
| 1150 | + | t = PrettyTable(['ID', 'Username', 'Full Name', 'Email']) |
| 1151 | + | t.align["ID"] = "l" |
| 1152 | + | t.align["Username"] = "l" |
| 1153 | + | t.align["Full Name"] = "l" |
| 1154 | + | t.align["Email"] = "l" |
| 1155 | + | |
| 1156 | + | json_data = {} |
| 1157 | + | |
| 1158 | + | for node in results: |
| 1159 | + | t.add_row([str(node['id']), node['username'], node['full_name'], node['email']]) |
| 1160 | + | |
| 1161 | + | if self.writeFile: |
| 1162 | + | file_name = "output/" + self.target + "_fwingsemail.txt" |
| 1163 | + | file = open(file_name, "w") |
| 1164 | + | file.write(str(t)) |
| 1165 | + | file.close() |
| 1166 | + | |
| 1167 | + | if self.jsonDump: |
| 1168 | + | json_data['followings_email'] = results |
| 1169 | + | json_file_name = "output/" + self.target + "_fwingsemail.json" |
| 1170 | + | with open(json_file_name, 'w') as f: |
| 1171 | + | json.dump(json_data, f) |
| 1172 | + | |
| 1173 | + | print(t) |
| 1174 | + | else: |
| 1175 | + | pc.printout("Sorry! No results found :-(\n", pc.RED) |
1125 | 1176 | | |