diff --git a/.img/banner.png b/.img/banner.png
new file mode 100644
index 00000000..e915a9a7
Binary files /dev/null and b/.img/banner.png differ
diff --git a/README.md b/README.md
index 9172cf49..ef744130 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![](https://img.shields.io/badge/version-0.7-green)](https://github.com/Datalux/Osintgram/releases/tag/0.7)
+[![](https://img.shields.io/badge/version-0.8-green)](https://github.com/Datalux/Osintgram/releases/tag/0.8)
[![](https://img.shields.io/badge/license-GPLv3-blue)](https://img.shields.io/badge/license-GPLv3-blue)
[![](https://img.shields.io/badge/language-Python3-red)](https://img.shields.io/badge/language-Python3-red)
@@ -27,15 +27,16 @@ Osintgram offers an interactive shell to perform analysis on Instagram account o
- tagged Get list of users tagged by target
- target Set new target
- wcommented Get a list of user who commented target's photos
+- wtagged Get a list of user who tagged target
```
-You can find detailed commands usage [here](commands.md).
+You can find detailed commands usage [here](doc/COMMANDS.md).
-[**Latest version**](https://github.com/Datalux/Osintgram/releases/tag/0.7) |
-[CHANGELOG](CHANGELOG.md)
+[**Latest version**](https://github.com/Datalux/Osintgram/releases/tag/0.8) |
+[CHANGELOG](doc/CHANGELOG.md)
## Tools
-
+
@@ -72,4 +73,4 @@ Run `git pull` in Osintgram directory
You can propose a feature request opening an issue or a pull request.
## External library
-Instagram API: https://github.com/ping/instagram_private_api
\ No newline at end of file
+Instagram API: https://gDOCithub.com/ping/instagram_private_api
diff --git a/cmd.png b/cmd.png
deleted file mode 100644
index d6c46e58..00000000
Binary files a/cmd.png and /dev/null differ
diff --git a/CHANGELOG.md b/doc/CHANGELOG.md
similarity index 82%
rename from CHANGELOG.md
rename to doc/CHANGELOG.md
index 11e9c9e4..fb0cfff4 100644
--- a/CHANGELOG.md
+++ b/doc/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## [0.8](https://github.com/Datalux/Osintgram/releases/tag/0.8)
+
+**Enhancements**
+- Added `wtagged` command (#38)
+- Access private profiles if you following targets (#37)
+- Added more info in `info` command (#36)
+
+**Bug fixes**
+- Minor bug fix in `addrs` commands (9b9086a)
+
+
## [0.7](https://github.com/Datalux/Osintgram/releases/tag/0.7)
**Enhancements**
diff --git a/commands.md b/doc/COMMANDS.md
similarity index 92%
rename from commands.md
rename to doc/COMMANDS.md
index 48d54c75..2ca46eba 100644
--- a/commands.md
+++ b/doc/COMMANDS.md
@@ -15,6 +15,7 @@
- stories Download user's stories
- tagged Get list of users tagged by target
- wcommented Get a list of user who commented target's photos
+- wtagged Get a list of user who tagged target
```
### addrs
@@ -56,6 +57,9 @@ Show target info like:
- is business account?
- business catagory (if target has business account)
- is verified?
+- business email (if available)
+- HD profile picture url
+- connected Facebook page (if available)
### JSON
Can set preference to export commands output as JSON in output folder. It save output in `_.JSON` file.
@@ -97,5 +101,7 @@ Return a list of users tagged by target with ID, username and full name
## wcommented
Return a list of users who commented target's photos sorted by number of comments
+## wtagged
+Return a list of users who tagged target sorted by number of photos
diff --git a/doc/doc.pdf b/doc/doc.pdf
deleted file mode 100644
index 5c99b724..00000000
Binary files a/doc/doc.pdf and /dev/null differ
diff --git a/main.py b/main.py
index 942c1888..73b7d50b 100644
--- a/main.py
+++ b/main.py
@@ -16,7 +16,7 @@ def printlogo():
pc.printout("\_______ /____ >__|___| /__| \___ /|__| (____ /__|_| /\n", pc.YELLOW)
pc.printout(" \/ \/ \/ /_____/ \/ \/ \n", pc.YELLOW)
print('\n')
- pc.printout("Version 0.7 - Developed by Giuseppe Criscione - 2019\n\n", pc.YELLOW)
+ pc.printout("Version 0.8 - 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")
@@ -40,6 +40,8 @@ def cmdlist():
print("Get target followers")
pc.printout("followings\t")
print("Get users followed by target")
+ pc.printout("fwersemail\t")
+ print("Get email of users followed by target")
pc.printout("hashtags\t")
print("Get hashtags used by target")
pc.printout("info\t\t")
@@ -62,6 +64,8 @@ def cmdlist():
print("Set new target")
pc.printout("wcommented\t")
print("Get a list of user who commented target's photos")
+ pc.printout("wtagged\t\t")
+ print("Get a list of user who tagged target")
def signal_handler(sig, frame):
@@ -102,6 +106,8 @@ def signal_handler(sig, frame):
api.get_followers()
elif cmd == "followings":
api.get_followings()
+ elif cmd == 'fwersemail':
+ api.get_fwersemail()
elif cmd == "hashtags":
api.get_hashtags()
elif cmd == "info":
@@ -124,6 +130,8 @@ def signal_handler(sig, frame):
api.change_target()
elif cmd == "wcommented":
api.get_people_who_commented()
+ elif cmd == "wtagged":
+ api.get_people_who_tagged()
elif cmd == "FILE=y":
api.set_write_file(True)
elif cmd == "FILE=n":
diff --git a/src/Osintgram.py b/src/Osintgram.py
index bc8a17ca..a870dcd6 100644
--- a/src/Osintgram.py
+++ b/src/Osintgram.py
@@ -21,6 +21,7 @@ class Osintgram:
user_id = None
target_id = None
is_private = True
+ following = False
target = ""
writeFile = False
jsonDump = False
@@ -39,6 +40,7 @@ def setTarget(self, target):
user = self.get_user(target)
self.target_id = user['id']
self.is_private = user['is_private']
+ self.following = self.check_following()
self.__printTargetBanner__()
def __getUsername__(self):
@@ -94,9 +96,15 @@ def __printTargetBanner__(self):
pc.printout(self.api.username, pc.CYAN)
pc.printout(". Target: ", pc.GREEN)
pc.printout(str(self.target), pc.CYAN)
- pc.printout(" [" + str(self.target_id) + "] ")
+ pc.printout(" [" + str(self.target_id) + "]")
if self.is_private:
- pc.printout("[PRIVATE PROFILE]", pc.RED)
+ pc.printout(" [PRIVATE PROFILE]", pc.BLUE)
+ if self.following:
+ pc.printout(" [FOLLOWING]", pc.GREEN)
+ else:
+ pc.printout(" [NOT FOLLOWING]", pc.RED)
+
+
print('\n')
def change_target(self):
@@ -106,8 +114,7 @@ def change_target(self):
return
def get_addrs(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for target localizations...\n")
@@ -117,7 +124,7 @@ def get_addrs(self):
locations = {}
for post in data:
- if post['location'] is not None:
+ if 'location' in post and post['location'] is not None:
lat = post['location']['lat']
lng = post['location']['lng']
locations[str(lat) + ', ' + str(lng)] = post.get('taken_at')
@@ -173,8 +180,7 @@ def get_addrs(self):
pc.printout("Sorry! No results found :-(\n", pc.RED)
def get_captions(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for target captions...\n")
@@ -232,8 +238,7 @@ def get_captions(self):
return
def get_total_comments(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for target total comments...\n")
@@ -266,8 +271,7 @@ def get_total_comments(self):
pc.printout(" comments in " + str(posts) + " posts\n")
def get_followers(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for target followers...\n")
@@ -319,8 +323,7 @@ def get_followers(self):
print(t)
def get_followings(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for target followings...\n")
@@ -372,8 +375,7 @@ def get_followings(self):
print(t)
def get_hashtags(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for target hashtags...\n")
@@ -449,9 +451,9 @@ def get_user_info(self):
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("[FOLLOWED] ", pc.BLUE)
pc.printout(str(data['edge_followed_by']['count']) + '\n')
- pc.printout("[FOLLOW] ", pc.BLUE)
+ pc.printout("[FOLLOW] ", pc.GREEN)
pc.printout(str(data['edge_follow']['count']) + '\n')
pc.printout("[BUSINESS ACCOUNT] ", pc.RED)
pc.printout(str(data['is_business_account']) + '\n')
@@ -460,6 +462,14 @@ def get_user_info(self):
pc.printout(str(data['business_category_name']) + '\n')
pc.printout("[VERIFIED ACCOUNT] ", pc.CYAN)
pc.printout(str(data['is_verified']) + '\n')
+ if data['business_email']:
+ pc.printout("[BUSINESS EMAIL] ", pc.BLUE)
+ pc.printout(str(data['business_email']) + '\n')
+ pc.printout("[HD PROFILE PIC] ", pc.GREEN)
+ pc.printout(str(data['profile_pic_url_hd']) + '\n')
+ if data['connected_fb_page']:
+ pc.printout("[FB PAGE] ", pc.RED)
+ pc.printout(str(data['business_email']) + '\n')
if self.jsonDump:
user = {
@@ -469,8 +479,14 @@ def get_user_info(self):
'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']
+ 'is_verified': data['is_verified'],
+ 'profile_pic_url_hd': data['profile_pic_url_hd']
}
+ if data['business_email']:
+ user['business_email'] = data['business_email']
+ if data['connected_fb_page']:
+ user['connected_fb_page'] = data['connected_fb_page']
+
json_file_name = "output/" + self.target + "_info.json"
with open(json_file_name, 'w') as f:
json.dump(user, f)
@@ -481,8 +497,7 @@ def get_user_info(self):
sys.exit(2)
def get_total_likes(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for target total likes...\n")
@@ -515,8 +530,7 @@ def get_total_likes(self):
pc.printout(" likes in " + str(posts) + " posts\n")
def get_media_type(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for target captions...\n")
@@ -564,8 +578,7 @@ def get_media_type(self):
pc.printout("Sorry! No results found :-(\n", pc.RED)
def get_people_who_commented(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for users who commented...\n")
@@ -622,9 +635,76 @@ def get_people_who_commented(self):
else:
pc.printout("Sorry! No results found :-(\n", pc.RED)
+ def get_people_who_tagged(self):
+ if self.check_private_profile():
+ return
+
+ pc.printout("Searching for users who tagged target...\n")
+
+ posts = []
+
+ result = self.api.usertag_feed(self.target_id)
+ posts.extend(result.get('items', []))
+
+ next_max_id = result.get('next_max_id')
+ while next_max_id:
+ results = self.api.user_feed(str(self.target_id), max_id=next_max_id)
+ posts.extend(results.get('items', []))
+ next_max_id = results.get('next_max_id')
+
+ if len(posts) > 0:
+ pc.printout("\nWoohoo! We found " + str(len(posts)) + " photos\n", pc.GREEN)
+
+ users = []
+
+ for post in posts:
+ if not any(u['id'] == post['user']['pk'] for u in users):
+ user = {
+ 'id': post['user']['pk'],
+ 'username': post['user']['username'],
+ 'full_name': post['user']['full_name'],
+ 'counter': 1
+ }
+ users.append(user)
+ else:
+ for user in users:
+ if user['id'] == post['user']['pk']:
+ user['counter'] += 1
+ break
+
+ ssort = sorted(users, key=lambda value: value['counter'], reverse=True)
+
+ json_data = {}
+
+ t = PrettyTable()
+
+ t.field_names = ['Photos', 'ID', 'Username', 'Full Name']
+ t.align["Photos"] = "l"
+ t.align["ID"] = "l"
+ t.align["Username"] = "l"
+ t.align["Full Name"] = "l"
+
+ for u in ssort:
+ t.add_row([str(u['counter']), u['id'], u['username'], u['full_name']])
+
+ print(t)
+
+ if self.writeFile:
+ file_name = "output/" + self.target + "_users_who_tagged.txt"
+ file = open(file_name, "w")
+ file.write(str(t))
+ file.close()
+
+ if self.jsonDump:
+ json_data['users_who_tagged'] = ssort
+ json_file_name = "output/" + self.target + "_users_who_tagged.json"
+ with open(json_file_name, 'w') as f:
+ json.dump(json_data, f)
+ else:
+ pc.printout("Sorry! No results found :-(\n", pc.RED)
+
def get_photo_description(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
content = urllib.request.urlopen("https://www.instagram.com/" + str(self.target) + "/?__a=1")
@@ -673,8 +753,7 @@ def get_photo_description(self):
pc.printout("Sorry! No results found :-(\n", pc.RED)
def get_user_photo(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
limit = -1
@@ -764,8 +843,7 @@ def get_user_propic(self):
sys.exit(2)
def get_user_stories(self):
- if self.is_private:
- pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ if self.check_private_profile():
return
pc.printout("Searching for target stories...\n")
@@ -968,3 +1046,79 @@ def onlogin_callback(self, api, new_settings_file):
with open(new_settings_file, 'w') as outfile:
json.dump(cache_settings, outfile, default=self.to_json)
#print('SAVED: {0!s}'.format(new_settings_file))
+
+ def check_following(self):
+ endpoint = 'users/{user_id!s}/full_detail_info/'.format(**{'user_id': self.target_id})
+ return self.api._call_api(endpoint)['user_detail']['user']['friendship_status']['following']
+
+ def check_private_profile(self):
+ if self.is_private and not self.following:
+ pc.printout("Impossible to execute command: user has private profile\n", pc.RED)
+ return True
+ return False
+
+ def get_fwersemail(self):
+ if self.check_private_profile():
+ return
+
+ pc.printout("Searching for emails of target followers... this can take a few minutes\n")
+
+ followers = []
+
+ rank_token = AppClient.generate_uuid()
+ data = self.api.user_followers(str(self.target_id), rank_token=rank_token)
+
+ for user in data['users']:
+ u = {
+ 'id': user['pk'],
+ 'username': user['username'],
+ 'full_name': user['full_name']
+ }
+ followers.append(u)
+
+ results = []
+
+ for follow in followers:
+ req = urllib.request.urlopen("https://www.instagram.com/" + str(follow['username']) + "/?__a=1")
+ data = json.load(req)['graphql']['user']
+ if data['business_email']:
+ follow['email'] = data['business_email']
+ results.append(follow)
+
+ if len(results) > 0:
+
+ t = PrettyTable(['ID', 'Username', 'Full Name', 'Email'])
+ t.align["ID"] = "l"
+ t.align["Username"] = "l"
+ t.align["Full Name"] = "l"
+ t.align["Email"] = "l"
+
+ json_data = {}
+
+ for node in results:
+ t.add_row([str(node['id']), node['username'], node['full_name'], node['email']])
+
+ 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'] = results
+ json_file_name = "output/" + self.target + "_followers.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)
+
+
+
+
+
+
+
+
+