| skipped 5 lines |
6 | 6 | | from geopy.geocoders import Nominatim |
7 | 7 | | from prettytable import PrettyTable |
8 | 8 | | |
9 | | - | import printcolors as pc |
10 | | - | from InstagramAPI import InstagramAPI |
| 9 | + | from src import printcolors as pc |
| 10 | + | from src.InstagramAPI import InstagramAPI |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | class Osintgram: |
| skipped 4 lines |
18 | 18 | | is_private = True |
19 | 19 | | target = "" |
20 | 20 | | writeFile = False |
| 21 | + | jsonDump = False |
21 | 22 | | |
22 | 23 | | def __init__(self, target): |
23 | 24 | | u = self.__getUsername__() |
| skipped 11 lines |
35 | 36 | | self.__printTargetBanner__() |
36 | 37 | | |
37 | 38 | | def __getUsername__(self): |
38 | | - | u = open("config/username.conf", "r").read() |
39 | | - | u = u.replace("\n", "") |
40 | | - | return u |
| 39 | + | try: |
| 40 | + | u = open("config/username.conf", "r").read() |
| 41 | + | u = u.replace("\n", "") |
| 42 | + | return u |
| 43 | + | except FileNotFoundError: |
| 44 | + | pc.printout("Error: file \"config/username.conf\" not found!", pc.RED) |
| 45 | + | pc.printout("\n") |
| 46 | + | sys.exit(0) |
41 | 47 | | |
42 | 48 | | def __getPassword__(self): |
43 | | - | p = open("config/pw.conf", "r").read() |
44 | | - | p = p.replace("\n", "") |
45 | | - | return p |
| 49 | + | try: |
| 50 | + | p = open("config/pw.conf", "r").read() |
| 51 | + | p = p.replace("\n", "") |
| 52 | + | return p |
| 53 | + | except FileNotFoundError: |
| 54 | + | pc.printout("Error: file \"config/pw.conf\" not found!", pc.RED) |
| 55 | + | pc.printout("\n") |
| 56 | + | sys.exit(0) |
46 | 57 | | |
47 | | - | def __getAdressesTimes__(self, id): |
| 58 | + | def __getAdressesTimes__(self, user_id): |
48 | 59 | | only_id = {} |
49 | 60 | | photos = [] |
50 | 61 | | a = None |
51 | 62 | | while True: |
52 | 63 | | if a is None: |
53 | | - | self.api.getUserFeed(id) |
| 64 | + | self.api.getUserFeed(user_id) |
54 | 65 | | a = self.api.LastJson['items'] |
55 | 66 | | only_id = self.api.LastJson |
56 | 67 | | else: |
57 | | - | self.api.getUserFeed(id, only_id['next_max_id']) |
| 68 | + | self.api.getUserFeed(user_id, only_id['next_max_id']) |
58 | 69 | | only_id = self.api.LastJson |
59 | 70 | | a = self.api.LastJson['items'] |
60 | 71 | | |
| skipped 127 lines |
188 | 199 | | |
189 | 200 | | sortE = sorted(hashtag_counter.items(), key=lambda value: value[1], reverse=True) |
190 | 201 | | |
| 202 | + | file = None |
| 203 | + | json_data = {} |
| 204 | + | hashtags_list = [] |
| 205 | + | |
191 | 206 | | if self.writeFile: |
192 | 207 | | file_name = "output/" + self.target + "_hashtags.txt" |
193 | 208 | | file = open(file_name, "w") |
194 | | - | for k, v in sortE: |
195 | | - | file.write(str(v) + ". " + str(k.decode('utf-8')) + "\n") |
| 209 | + | |
| 210 | + | for k, v in sortE: |
| 211 | + | hashtag = str(k.decode('utf-8')) |
| 212 | + | print(str(v) + ". " + hashtag) |
| 213 | + | if self.writeFile: |
| 214 | + | file.write(str(v) + ". " + hashtag + "\n") |
| 215 | + | if self.jsonDump: |
| 216 | + | hashtags_list.append(hashtag) |
| 217 | + | |
| 218 | + | if file is not None: |
196 | 219 | | file.close() |
197 | 220 | | |
198 | | - | for k, v in sortE: |
199 | | - | print(str(v) + ". " + str(k.decode('utf-8'))) |
| 221 | + | if self.jsonDump: |
| 222 | + | json_data['hashtags'] = hashtags_list |
| 223 | + | json_file_name = "output/" + self.target + "_hashtags.json" |
| 224 | + | with open(json_file_name, 'w') as f: |
| 225 | + | json.dump(json_data, f) |
200 | 226 | | |
201 | 227 | | def getTotalLikes(self): |
202 | 228 | | if self.is_private: |
| skipped 7 lines |
210 | 236 | | a = None |
211 | 237 | | counter = 0 |
212 | 238 | | while True: |
213 | | - | if (a == None): |
| 239 | + | if a is None: |
214 | 240 | | self.api.getUserFeed(self.target_id) |
215 | 241 | | a = self.api.LastJson['items'] |
216 | 242 | | only_id = self.api.LastJson |
| skipped 12 lines |
229 | 255 | | if not 'next_max_id' in only_id: |
230 | 256 | | break |
231 | 257 | | |
232 | | - | if (self.writeFile): |
| 258 | + | if self.writeFile: |
233 | 259 | | file_name = "output/" + self.target + "_likes.txt" |
234 | 260 | | file = open(file_name, "w") |
235 | 261 | | file.write(str(like_counter) + " likes in " + str(counter) + " posts\n") |
236 | 262 | | file.close() |
237 | 263 | | |
| 264 | + | if self.jsonDump: |
| 265 | + | json_data = { |
| 266 | + | 'like_counter': like_counter, |
| 267 | + | 'posts': counter |
| 268 | + | } |
| 269 | + | json_file_name = "output/" + self.target + "_likes.json" |
| 270 | + | with open(json_file_name, 'w') as f: |
| 271 | + | json.dump(json_data, f) |
| 272 | + | |
238 | 273 | | pc.printout(str(like_counter), pc.MAGENTA) |
239 | 274 | | pc.printout(" likes in " + str(counter) + " posts\n") |
240 | 275 | | |
| skipped 9 lines |
250 | 285 | | a = None |
251 | 286 | | counter = 0 |
252 | 287 | | while True: |
253 | | - | if (a == None): |
| 288 | + | if a is None: |
254 | 289 | | self.api.getUserFeed(self.target_id) |
255 | 290 | | a = self.api.LastJson['items'] |
256 | 291 | | only_id = self.api.LastJson |
| skipped 18 lines |
275 | 310 | | file.write(str(comment_counter) + " comments in " + str(counter) + " posts\n") |
276 | 311 | | file.close() |
277 | 312 | | |
| 313 | + | if self.jsonDump: |
| 314 | + | json_data = { |
| 315 | + | 'comment_counter': comment_counter, |
| 316 | + | 'posts': counter |
| 317 | + | } |
| 318 | + | json_file_name = "output/" + self.target + "_comments.json" |
| 319 | + | with open(json_file_name, 'w') as f: |
| 320 | + | json.dump(json_data, f) |
| 321 | + | |
278 | 322 | | pc.printout(str(comment_counter), pc.MAGENTA) |
279 | 323 | | pc.printout(" comments in " + str(counter) + " posts\n") |
280 | 324 | | |
| skipped 51 lines |
332 | 376 | | |
333 | 377 | | pc.printout("\nWoohoo! We found " + str(len(ids)) + " (" + str(counter) + ") users\n", pc.GREEN) |
334 | 378 | | |
| 379 | + | json_data = {} |
| 380 | + | tagged_list = [] |
| 381 | + | |
335 | 382 | | for i in range(len(ids)): |
336 | 383 | | t.add_row([post[i], full_name[i], username[i], str(ids[i])]) |
337 | 384 | | |
| 385 | + | if self.jsonDump: |
| 386 | + | tag = { |
| 387 | + | 'post': post[i], |
| 388 | + | 'full_name': full_name[i], |
| 389 | + | 'username': username[i], |
| 390 | + | 'id': ids[i] |
| 391 | + | } |
| 392 | + | tagged_list.append(tag) |
| 393 | + | |
338 | 394 | | if self.writeFile: |
339 | 395 | | file_name = "output/" + self.target + "_tagged.txt" |
340 | 396 | | file = open(file_name, "w") |
341 | 397 | | file.write(str(t)) |
342 | 398 | | file.close() |
343 | 399 | | |
| 400 | + | if self.jsonDump: |
| 401 | + | json_data['tagged'] = tagged_list |
| 402 | + | json_file_name = "output/" + self.target + "_tagged.json" |
| 403 | + | with open(json_file_name, 'w') as f: |
| 404 | + | json.dump(json_data, f) |
| 405 | + | |
344 | 406 | | print(t) |
345 | 407 | | else: |
346 | 408 | | pc.printout("Sorry! No results found :-(\n", pc.RED) |
| skipped 14 lines |
361 | 423 | | pc.printout("\nWoohoo! We found " + str(len(addrs)) + " addresses\n", pc.GREEN) |
362 | 424 | | |
363 | 425 | | i = 1 |
| 426 | + | |
| 427 | + | json_data = {} |
| 428 | + | addrs_list = [] |
| 429 | + | |
364 | 430 | | for address, time in addrs: |
365 | 431 | | t.add_row([str(i), address, time]) |
| 432 | + | |
| 433 | + | if self.jsonDump: |
| 434 | + | addr = { |
| 435 | + | 'address': address, |
| 436 | + | 'time': time |
| 437 | + | } |
| 438 | + | addrs_list.append(addr) |
| 439 | + | |
366 | 440 | | i = i + 1 |
367 | 441 | | |
368 | 442 | | if self.writeFile: |
| skipped 1 lines |
370 | 444 | | file = open(file_name, "w") |
371 | 445 | | file.write(str(t)) |
372 | 446 | | file.close() |
| 447 | + | |
| 448 | + | if self.jsonDump: |
| 449 | + | json_data['address'] = addrs_list |
| 450 | + | json_file_name = "output/" + self.target + "_addrs.json" |
| 451 | + | with open(json_file_name, 'w') as f: |
| 452 | + | json.dump(json_data, f) |
373 | 453 | | |
374 | 454 | | print(t) |
375 | 455 | | |
| skipped 10 lines |
386 | 466 | | t.align["Username"] = "l" |
387 | 467 | | t.align["Full Name"] = "l" |
388 | 468 | | |
| 469 | + | json_data = {} |
| 470 | + | followers_list = [] |
| 471 | + | |
389 | 472 | | for i in followers: |
390 | 473 | | t.add_row([str(i['pk']), i['username'], i['full_name']]) |
391 | 474 | | |
| 475 | + | if self.jsonDump: |
| 476 | + | follower = { |
| 477 | + | 'id': i['pk'], |
| 478 | + | 'username': i['username'], |
| 479 | + | 'full_name': i['full_name'] |
| 480 | + | } |
| 481 | + | followers_list.append(follower) |
| 482 | + | |
392 | 483 | | if self.writeFile: |
393 | 484 | | file_name = "output/" + self.target + "_followers.txt" |
394 | 485 | | file = open(file_name, "w") |
395 | 486 | | file.write(str(t)) |
396 | 487 | | file.close() |
397 | 488 | | |
| 489 | + | if self.jsonDump: |
| 490 | + | json_data['followers'] = followers_list |
| 491 | + | json_file_name = "output/" + self.target + "_followers.json" |
| 492 | + | with open(json_file_name, 'w') as f: |
| 493 | + | json.dump(json_data, f) |
| 494 | + | |
398 | 495 | | print(t) |
399 | 496 | | |
400 | 497 | | def getFollowings(self): |
| skipped 9 lines |
410 | 507 | | t.align["Username"] = "l" |
411 | 508 | | t.align["Full Name"] = "l" |
412 | 509 | | |
| 510 | + | json_data = {} |
| 511 | + | followings_list = [] |
| 512 | + | |
413 | 513 | | for i in followings: |
414 | 514 | | t.add_row([str(i['pk']), i['username'], i['full_name']]) |
415 | 515 | | |
| 516 | + | if self.jsonDump: |
| 517 | + | follow = { |
| 518 | + | 'id': i['pk'], |
| 519 | + | 'username': i['username'], |
| 520 | + | 'full_name': i['full_name'] |
| 521 | + | } |
| 522 | + | followings_list.append(follow) |
| 523 | + | |
416 | 524 | | if self.writeFile: |
417 | 525 | | file_name = "output/" + self.target + "_followings.txt" |
418 | 526 | | file = open(file_name, "w") |
419 | 527 | | file.write(str(t)) |
420 | 528 | | file.close() |
| 529 | + | |
| 530 | + | if self.jsonDump: |
| 531 | + | json_data['followings'] = followings_list |
| 532 | + | json_file_name = "output/" + self.target + "_followings.json" |
| 533 | + | with open(json_file_name, 'w') as f: |
| 534 | + | json.dump(json_data, f) |
421 | 535 | | |
422 | 536 | | print(t) |
423 | 537 | | |
| skipped 44 lines |
468 | 582 | | pc.printout("[VERIFIED ACCOUNT] ", pc.CYAN) |
469 | 583 | | pc.printout(str(data['is_verified']) + '\n') |
470 | 584 | | |
| 585 | + | if self.jsonDump: |
| 586 | + | user = { |
| 587 | + | 'id': data['id'], |
| 588 | + | 'full_name': data['full_name'], |
| 589 | + | 'biography': data['biography'], |
| 590 | + | 'edge_followed_by': data['edge_followed_by']['count'], |
| 591 | + | 'edge_follow': data['edge_follow']['count'], |
| 592 | + | 'is_business_account': data['is_business_account'], |
| 593 | + | 'is_verified': data['is_verified'] |
| 594 | + | } |
| 595 | + | json_file_name = "output/" + self.target + "_info.json" |
| 596 | + | with open(json_file_name, 'w') as f: |
| 597 | + | json.dump(user, f) |
| 598 | + | |
471 | 599 | | except urllib.error.HTTPError as err: |
472 | 600 | | if err.code == 404: |
473 | 601 | | print("Oops... " + str(self.target) + " non exist, please enter a valid username.") |
| skipped 17 lines |
491 | 619 | | t.align["Photo"] = "l" |
492 | 620 | | t.align["Description"] = "l" |
493 | 621 | | |
| 622 | + | json_data = {} |
| 623 | + | descriptions_list = [] |
| 624 | + | |
494 | 625 | | for i in dd: |
495 | 626 | | node = i.get('node') |
496 | | - | t.add_row([str(count), node.get('accessibility_caption')]) |
| 627 | + | descr = node.get('accessibility_caption') |
| 628 | + | t.add_row([str(count), descr]) |
| 629 | + | |
| 630 | + | if self.jsonDump: |
| 631 | + | description = { |
| 632 | + | 'description': descr |
| 633 | + | } |
| 634 | + | descriptions_list.append(description) |
| 635 | + | |
497 | 636 | | count += 1 |
498 | 637 | | |
499 | 638 | | if self.writeFile: |
| skipped 2 lines |
502 | 641 | | file.write(str(t)) |
503 | 642 | | file.close() |
504 | 643 | | |
| 644 | + | if self.jsonDump: |
| 645 | + | json_data['descriptions'] = descriptions_list |
| 646 | + | json_file_name = "output/" + self.target + "_descriptions.json" |
| 647 | + | with open(json_file_name, 'w') as f: |
| 648 | + | json.dump(json_data, f) |
| 649 | + | |
505 | 650 | | print(t) |
506 | 651 | | else: |
507 | 652 | | pc.printout("Sorry! No results found :-(\n", pc.RED) |
| skipped 5 lines |
513 | 658 | | |
514 | 659 | | limit = -1 |
515 | 660 | | pc.printout("How many photos you want to download (default all): ", pc.YELLOW) |
516 | | - | l = input() |
| 661 | + | user_input = input() |
517 | 662 | | try: |
518 | | - | if l == "": |
| 663 | + | if user_input == "": |
519 | 664 | | pc.printout("Downloading all photos avaible...\n") |
520 | 665 | | else: |
521 | | - | limit = int(l) |
522 | | - | pc.printout("Downloading " + l + " photos...\n") |
| 666 | + | limit = int(user_input) |
| 667 | + | pc.printout("Downloading " + user_input + " photos...\n") |
523 | 668 | | |
524 | 669 | | except ValueError: |
525 | 670 | | pc.printout("Wrong value entered\n", pc.RED) |
| skipped 113 lines |
639 | 784 | | return |
640 | 785 | | |
641 | 786 | | def getMediaType(self): |
642 | | - | if (self.is_private): |
| 787 | + | if self.is_private: |
643 | 788 | | pc.printout("Impossible to execute command: user has private profile\n", pc.RED) |
644 | 789 | | return |
645 | 790 | | |
| skipped 51 lines |
697 | 842 | | pc.printout("\nWoohoo! We found " + str(photo_counter) + " photos and " + str(video_counter) \ |
698 | 843 | | + " video posted by target\n", pc.GREEN) |
699 | 844 | | |
| 845 | + | if self.jsonDump: |
| 846 | + | json_data = { |
| 847 | + | "photos": photo_counter, |
| 848 | + | "videos": video_counter |
| 849 | + | } |
| 850 | + | json_file_name = "output/" + self.target + "_mediatype.json" |
| 851 | + | with open(json_file_name, 'w') as f: |
| 852 | + | json.dump(json_data, f) |
| 853 | + | |
700 | 854 | | else: |
701 | 855 | | pc.printout("Sorry! No results found :-(\n", pc.RED) |
702 | 856 | | |
| skipped 2 lines |
705 | 859 | | def getUserPropic(self): |
706 | 860 | | try: |
707 | 861 | | content = urllib.request.urlopen("https://www.instagram.com/" + str(self.target) + "/?__a=1") |
708 | | - | except urllib.error.HTTPError as err: |
709 | | - | if err.code == 404: |
710 | | - | print("Oops... " + str(self.target) + " non exist, please enter a valid username.") |
711 | | - | sys.exit(2) |
712 | 862 | | |
713 | | - | data = json.load(content) |
| 863 | + | data = json.load(content) |
714 | 864 | | |
715 | | - | URL = "" |
| 865 | + | URL = "" |
716 | 866 | | |
717 | | - | uurl = data["graphql"]["user"] |
718 | | - | if "profile_pic_url_hd" in uurl: |
719 | | - | URL = data["graphql"]["user"]["profile_pic_url_hd"] |
720 | | - | else: |
721 | | - | URL = data["graphql"]["user"]["profile_pic_url"] |
| 867 | + | uurl = data["graphql"]["user"] |
| 868 | + | if "profile_pic_url_hd" in uurl: |
| 869 | + | URL = data["graphql"]["user"]["profile_pic_url_hd"] |
| 870 | + | else: |
| 871 | + | URL = data["graphql"]["user"]["profile_pic_url"] |
722 | 872 | | |
723 | | - | if URL != "": |
724 | | - | end = "output/" + self.target + "_propic.jpg" |
725 | | - | urllib.request.urlretrieve(URL, end) |
726 | | - | pc.printout("Target propic saved in output folder\n", pc.GREEN) |
| 873 | + | if URL != "": |
| 874 | + | end = "output/" + self.target + "_propic.jpg" |
| 875 | + | urllib.request.urlretrieve(URL, end) |
| 876 | + | pc.printout("Target propic saved in output folder\n", pc.GREEN) |
727 | 877 | | |
728 | | - | else: |
729 | | - | pc.printout("Sorry! No results found :-(\n", pc.RED) |
| 878 | + | else: |
| 879 | + | pc.printout("Sorry! No results found :-(\n", pc.RED) |
| 880 | + | except urllib.error.HTTPError as err: |
| 881 | + | if err.code == 404: |
| 882 | + | print("Oops... " + str(self.target) + " non exist, please enter a valid username.") |
| 883 | + | sys.exit(2) |
730 | 884 | | |
731 | 885 | | def getUserStories(self): |
732 | 886 | | if self.is_private: |
| skipped 34 lines |
767 | 921 | | |
768 | 922 | | return |
769 | 923 | | |
| 924 | + | def setJsonDump(self, flag): |
| 925 | + | if flag: |
| 926 | + | pc.printout("Export to JSON: ") |
| 927 | + | pc.printout("enabled", pc.GREEN) |
| 928 | + | pc.printout("\n") |
| 929 | + | else: |
| 930 | + | pc.printout("Export to JSON: ") |
| 931 | + | pc.printout("disabled", pc.RED) |
| 932 | + | pc.printout("\n") |
| 933 | + | |
| 934 | + | self.jsonDump = flag |
| 935 | + | |