Commit 66faee2d authored by Cody Zacharias's avatar Cody Zacharias

Update

parent d7681f0b
......@@ -2,7 +2,6 @@ language: python
# Python Version
python:
- 3.5
- 3.6
# Linux Only. Travis doesn't support Python for osx
......
......@@ -23,7 +23,6 @@ Some of the benefits of using Twint vs Twitter API:
## Installing
- **Git**: `git clone https://github.com/twintproject/twint.git`
- **Pip**: `pip3 install twint`
- **With MySQL**: `git clone -b mysql --single-branch https://github.com/twintproject/twint.git twint-mysql`
## Basic Examples and Combos.
A few simple examples to help you understand the basics:
......@@ -76,7 +75,7 @@ twint.run.Search(c)
- SQLite
- Mysql (DB collation utf8mb4)
- Elasticsearch
- MySQL (See MySQL Branch)
### Elasticsearch Setup
Details on setting up Elasticsearch with Twint is located in the [wiki](https://github.com/twintproject/twint/wiki/Elasticsearch).
......
......@@ -116,6 +116,8 @@ def initialize(args):
c.Index_tweets = args.index_tweets
c.Index_follow = args.index_follow
c.Index_users = args.index_users
c.Debug = args.debug
c.Resume = args.resume
return c
def options():
......@@ -172,6 +174,8 @@ def options():
ap.add_argument("-it", "--index-tweets", help="Custom Elasticsearch Index name for Tweets.")
ap.add_argument("-if", "--index-follow", help="Custom Elasticsearch Index name for Follows.")
ap.add_argument("-iu", "--index-users", help="Custom Elasticsearch Index name for Users.")
ap.add_argument("--debug", help="Store information in debug logs", action="store_true")
ap.add_argument("--resume", help="Resume from Tweet ID.")
args = ap.parse_args()
return args
......@@ -219,4 +223,9 @@ def main():
twint.run.Search(c)
if __name__ == "__main__":
version = ".".join(str(v) for v in sys.version_info[:2])
if float(version) < 3.6:
print("[-] TWINT requires Python version 3.6+.")
sys.exit(0)
main()
......@@ -7,7 +7,7 @@ import sys
# Package meta-data
NAME = 'twint'
DESCRIPTION = 'An advanced Twitter scraping & OSINT tool.'
URL = 'https://github.com/haccer/twint'
URL = 'https://github.com/twintproject/twint'
EMAIL = 'codyzacharias@pm.me'
AUTHOR = 'Cody Zacharias'
REQUIRES_PYTHON = '>=3.5.0'
......@@ -15,7 +15,8 @@ VERSION = None
# Packages required
REQUIRED = [
'aiohttp', 'aiodns', 'beautifulsoup4', 'cchardet', 'elasticsearch'
'aiohttp', 'aiodns', 'beautifulsoup4', 'cchardet',
'elasticsearch', 'pysocks', 'pandas'
]
here = os.path.abspath(os.path.dirname(__file__))
......
VERSION = (1, 1, 3, 5) #mysql support
VERSION = (1, 1, 4)
__version__ = '.'.join(map(str, VERSION))
......@@ -21,10 +21,7 @@ class Config:
Limit = None
Count = None
Stats = False
hostname = None #mysql
Database = None
DB_user = None #mysql
DB_pwd = None #mysql
To = None
All = None
Debug = False
......@@ -41,7 +38,8 @@ class Config:
Store_pandas = False
Pandas_type = None
Pandas = False
Search_name = "-" #for identify a records in mysql with the search it provides from. it cannot be null for DB requirements. a tweet must be in several search so the PK are tweet ID and search_name
Index_tweets = "twint"
Index_follow = "twintGraph"
Index_users = "twintUser"
\ No newline at end of file
Index_users = "twintUser"
Debug = False
Resume = None
......@@ -17,7 +17,7 @@ def Set(Until, Since):
d._since = datetime.datetime.strptime(Since, "%Y-%m-%d").date()
d._since_def_user = True
else:
d._since = datetime.datetime.strptime("2006-03-21", "%Y-%m-%d").date() # the 1st Tweet
d._since = datetime.datetime.strptime("2006-03-21", "%Y-%m-%d").date()
d._since_def_user = False
return d
from . import feed, get, db, output, verbose
class Favorites:
def __init__(self, config):
self.init = -1
self.feed = [-1]
self.count = 0
self.config = config
self.conn = db.Conn(config.Database)
self.config.Favorites = True
verbose.Elastic(config)
async def Feed(self):
response = await get.RequestUrl(self.config, self.init)
self.feed = []
try:
self.feed, self.init = feed.Mobile(response)
except:
pass
async def main(self):
if self.config.User_id is not None:
self.config.Username = await get.Username(self.config.User_id)
while True:
if len(self.feed) > 0:
await self.Feed()
self.count += await get.Multi(self.feed, self.config, self.conn)
else:
break
if get.Limit(self.config.Limit, self.count):
break
verbose.Count(self.config, self.count)
from . import feed, get, db, output, verbose
class Follow:
def __init__(self, config):
self.init = -1
self.feed = [-1]
self.count = 0
self.config = config
self.conn = db.Conn(config.Database)
verbose.Elastic(config)
async def Feed(self):
response = await get.RequestUrl(self.config, self.init)
self.feed = []
try:
self.feed, self.init = feed.Follow(response)
except:
pass
async def follow(self):
await self.Feed()
if self.config.User_full:
self.count += await get.Multi(self.feed, self.config, self.conn)
else:
for user in self.feed:
self.count += 1
username = user.find("a")["name"]
await output.Username(username, self.config, self.conn)
async def main(self):
if self.config.User_id is not None:
self.config.Username = await get.Username(self.config.User_id)
while True:
if len(self.feed) > 0:
await self.follow()
else:
break
if get.Limit(self.config.Limit, self.count):
break
verbose.Count(self.config, self.count)
......@@ -17,21 +17,20 @@ def Tweet(config, t):
output = output.replace("{user_rt}", t.user_rt)
output = output.replace("{mentions}", str(t.mentions))
else:
output = "{} {} {} {} ".format(t.id, t.datestamp,
t.timestamp, t.timezone)
output = f"{t.id} {t.datestamp} {t.timestamp} {t.timezone} "
if config.Profile and t.username.lower() != config.Username:
output += "RT "
output += "<{}> {}".format(t.username, t.tweet)
output += f"<{t.username}> {t.tweet}"
if config.Show_hashtags:
output += " {}".format(",".join(t.hashtags))
hashtags = ",".join(t.hashtags)
output += f" {hashtags}"
if config.Stats:
output += " | {} replies {} retweets {} likes".format(t.replies,
t.retweets, t.likes)
output += f" | {t.replies} replies {t.retweets} retweets {t.likes} likes"
if config.Location:
output += " | Location {}".format(t.location)
output += f" | Location {t.location}"
return output
......@@ -54,12 +53,12 @@ def User(_format, u):
output += output.replace("{verified}", u.is_verified)
output += output.replace("{avatar}", u.avatar)
else:
output = "{0.id} | {0.name} | @{0.username} | Private: ".format(u)
output += "{0.is_private} | Verified: {0.is_verified} |".format(u)
output += " Bio: {0.bio} | Location: {0.location} | Url: ".format(u)
output += "{0.url} | Joined: {0.join_date} {0.join_time} ".format(u)
output += "| Tweets: {0.tweets} | Following: {0.following}".format(u)
output += " | Followers: {0.followers} | Likes: {0.likes} ".format(u)
output += "| Media: {0.media_count} | Avatar: {0.avatar}".format(u)
output = f"{u.id} | {u.name} | @{u.username} | Private: "
output += f"{u.is_private} | Verified: {u.is_verified} |"
output += f" Bio: {u.bio} | Location: {u.location} | Url: "
output += f"{u.url} | Joined: {u.join_date} {u.join_time} "
output += f"| Tweets: {u.tweets} | Following: {u.following}"
output += f" | Followers: {u.followers} | Likes: {u.likes} "
output += f"| Media: {u.media_count} | Avatar: {u.avatar}"
return output
......@@ -26,6 +26,9 @@ async def RequestUrl(config, init):
_url = await url.Favorites(config.Username, init)
response = await MobileRequest(_url)
if config.Debug:
print(_url, file=open("twint-request_urls.log", "a", encoding="utf-8"))
return response
async def MobileRequest(url):
......@@ -45,7 +48,7 @@ async def Response(session, url):
return await response.text()
async def Username(_id):
url = "https://twitter.com/intent/user?user_id={}&lang=en".format(_id)
url = f"https://twitter.com/intent/user?user_id={_id}&lang=en"
r = Request(url)
soup = BeautifulSoup(r, "html.parser")
......@@ -84,13 +87,13 @@ async def Multi(feed, config, conn):
count += 1
if config.Favorites or config.Profile_full:
link = tweet.find("a")["href"]
url = "https://twitter.com{}&lang=en".format(link)
url = f"https://twitter.com{link}&lang=en"
elif config.User_full:
username = tweet.find("a")["name"]
url = "http://twitter.com/{}?lang=en".format(username)
url = f"http://twitter.com/{username}?lang=en"
else:
link = tweet.find("a", "tweet-timestamp js-permalink js-nav js-tooltip")["href"]
url = "https://twitter.com{}?lang=en".format(link)
url = f"https://twitter.com{link}?lang=en"
if config.User_full:
futures.append(loop.run_in_executor(executor, await User(url,
......
from datetime import datetime
from . import db, elasticsearch, format, write, Pandas
from . import format
from .tweet import Tweet
from .user import User
from datetime import datetime
from .storage import db, elasticsearch, write, panda
tweets_object = []
......@@ -53,17 +52,19 @@ async def Tweets(tw, location, config, conn):
tweet = Tweet(tw, location, config)
if datecheck(tweet.datestamp, config):
output = format.Tweet(config, tweet)
if config.Database:
db.tweets(conn, tweet, config)
if config.Elasticsearch:
elasticsearch.Tweet(tweet, config)
_output(tweet, output, config)
async def Users(u, config, conn):
user = User(u)
output = format.User(config.Format, user)
if config.Database:
db.user(conn, config.Username, config.Followers, user)
......
from . import db, get, feed, output, verbose
class Profile:
def __init__(self, config):
self.init = -1
self.feed = [-1]
self.count = 0
self.config = config
self.conn = db.Conn(config.Database)
self.config.Profile = True
verbose.Elastic(config)
async def Feed(self):
response = await get.RequestUrl(self.config, self.init)
self.feed = []
try:
if self.config.Profile_full:
self.feed, self.init = feed.Mobile(response)
else:
self.feed, self.init = feed.profile(response)
except:
pass
async def tweets(self):
await self.Feed()
if self.config.Profile_full:
self.count += await get.Multi(self.feed, self.config, self.conn)
else:
for tweet in self.feed:
self.count += 1
await output.Tweets(tweet, "", self.config, self.conn)
async def main(self):
if self.config.User_id is not None:
self.config.Username = await get.Username(self.config.User_id)
while True:
if len(self.feed) > 0:
await self.tweets()
else:
break
if get.Limit(self.config.Limit, self.count):
break
verbose.Count(self.config, self.count)
from . import favorites, follow, profile, search
from . import datelock, feed, get, output, verbose
from asyncio import get_event_loop
from datetime import timedelta
from .storage import db
def run(x):
get_event_loop().run_until_complete(x)
class Twint:
def __init__(self, config):
if config.Resume is not None and config.TwitterSearch:
self.init = f"TWEET-{config.Resume}-0"
else:
self.init = -1
self.feed = [-1]
self.count = 0
self.config = config
self.conn = db.Conn(config.Database)
self.d = datelock.Set(self.config.Until, self.config.Since)
verbose.Elastic(config.Elasticsearch)
if not self.config.Timedelta:
if (self.d._until - self.d._since).days > 30:
self.config.Timedelta = 30
else:
self.config.Timedelta = (self.d._until - self.d._since).days
async def Feed(self):
response = await get.RequestUrl(self.config, self.init)
if self.config.Debug:
print(response, file=open("twint-last-request.log", "w", encoding="utf-8"))
self.feed = []
try:
if self.config.Favorites:
self.feed, self.init = feed.Mobile(response)
elif self.config.Followers or self.config.Following:
self.feed, self.init = feed.Follow(response)
elif self.config.Profile:
if self.config.Profile_full:
self.feed, self.init = feed.Mobile(response)
else:
self.feed, self.init = feed.profile(response)
elif self.config.TwitterSearch:
self.feed, self.init = feed.Json(response)
except:
pass
async def follow(self):
await self.Feed()
if self.config.User_full:
self.count += await get.Multi(self.feed, self.config, self.conn)
else:
for user in self.feed:
self.count += 1
username = user.find("a"["name"])
await output.Username(username, self.config, self.conn)
async def favorite(self):
await self.Feed()
self.count += await get.Multi(self.feed, self.config, self.conn)
async def profile(self):
await self.Feed()
if self.config.Profile_full:
self.count += await get.Multi(self.feed, self.config, self.conn)
else:
for tweet in self.feed:
self.count += 1
await output.Tweets(tweet, "", self.config, self.conn)
async def tweets(self):
await self.Feed()
if self.config.Location:
self.count += await get.Multi(self.feed, self.config, self.conn)
else:
for tweet in self.feed:
self.count += 1
await output.Tweets(tweet, "", self.config, self.conn)
async def main(self):
if self.config.User_id is not None:
self.config.Username = await get.Username(self.config.User_id)
if self.config.TwitterSearch and self.config.Since and self.config.Until:
while self.d._since < self.d._until:
self.config.Since = str(self.d._until - _days)
self.config.Until = str(self.d._until)
if len(self.feed) > 0:
await self.tweets()
else:
self.d._until = self.d._until - _days
self.feed = [-1]
if get.Limit(self.config.Limit, self.count):
self.d._until = self.d._until - _days
self.feed = [-1]
else:
while True:
if len(self.feed) > 0:
if self.config.Followers or self.config.Following:
await self.follow()
elif self.config.Favorites:
await self.favorite()
elif self.config.Profile:
await self.profile()
elif self.config.TwitterSearch:
await self.tweets()
else:
break
if get.Limit(self.config.Limit, self.count):
break
if self.config.Count:
verbose.Count(self.count, self.config.Username)
def run(config):
get_event_loop().run_until_complete(Twint(config).main())
def Favorites(config):
config.Favorites = True
if config.Username:
config.search_name="Favourites"+str(config.Username) #to identify to which user is related to
else:
config.search_name="Favourites"+str(config.User_id) #to identify to which user is related to
run(favorites.Favorites(config).main())
run(config)
def Followers(config):
config.Followers = True
run(follow.Follow(config).main())
config.Follwers = True
run(config)
def Following(config):
config.Following = True
run(follow.Follow(config).main())
run(config)
def Profile(config):
config.Profile = True
run(profile.Profile(config).main())
run(config)
def Search(config):
config.TwitterSearch = True
run(search.Search(config).main())
run(config)
from . import datelock, db, get, feed, output, verbose
from datetime import timedelta
class Search:
def __init__(self, config):
self.init = -1
self.feed = [-1]
self.count = 0
self.config = config
self.conn = db.Conn(config.Database)
self.d = datelock.Set(self.config.Until, self.config.Since)
self.config.TwitterSearch = True
verbose.Elastic(config)
if not self.config.Timedelta:
if (self.d._until - self.d._since).days > 30:
self.config.Timedelta = 30
else:
self.config.Timedelta = (self.d._until - self.d._since).days
async def Feed(self):
response = await get.RequestUrl(self.config, self.init)
self.feed = []
try:
self.feed, self.init = feed.Json(response)
except:
pass
async def tweets(self):
await self.Feed()
if self.config.Location:
self.count += await get.Multi(self.feed, self.config, self.conn)
else:
for tweet in self.feed:
self.count += 1
await output.Tweets(tweet, "", self.config, self.conn)
async def main(self):
if self.config.User_id is not None:
self.config.Username = await get.Username(self.config.User_id)
if self.config.Since and self.config.Until:
_days = timedelta(days=int(self.config.Timedelta))
while self.d._since < self.d._until:
self.config.Since = str(self.d._until - _days)
self.config.Until = str(self.d._until)
if len(self.feed) > 0:
await self.tweets()
else:
self.d._until = self.d._until - _days
self.feed = [-1]
if get.Limit(self.config.Limit, self.count):
self.d._until = self.d._until - _days
self.feed = [-1]
else:
while True:
if len(self.feed) > 0:
await self.tweets()
else:
break
if get.Limit(self.config.Limit, self.count):
break
verbose.Count(self.config, self.count)
......@@ -2,10 +2,10 @@ from datetime import datetime
import sqlite3
import sys
def Conn(Database):
if Database:
print("[+] Inserting into Database: " + str(Database))
conn = init(Database)
def Conn(database):
if database:
print("[+] Inserting into Database: " + str(database))
conn = init(database)
if isinstance(conn, str):
print(str)
sys.exit(1)
......@@ -143,7 +143,8 @@ def follow(conn, Username, Followers, User):
date_time = str(datetime.now())
cursor = conn.cursor()
entry = (User, date_time, Username,)
query = 'INSERT INTO {} VALUES(?,?,?)'.format(fTable(Followers))
table = fTable(Followers)
query = f"INSERT INTO {table} VALUES(?,?,?)"
cursor.execute(query, entry)
conn.commit()
except sqlite3.IntegrityError:
......@@ -171,7 +172,8 @@ def user(conn, Username, Followers, User):
User.avatar,
date_time,
Username,)
query = 'INSERT INTO {} VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'.format(uTable(Followers))
table = uTable(Followers)
query = f"INSERT INTO {table} VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
cursor.execute(query, entry)
conn.commit()
except sqlite3.IntegrityError:
......
## TODO - Fix Weekday situation
from elasticsearch import Elasticsearch, helpers
from time import strftime, localtime
import contextlib
......@@ -47,7 +48,7 @@ def Tweet(Tweet, config):
nReplies = 0
nRetweets = 0
dt = "{} {}".format(Tweet.datestamp, Tweet.timestamp)
dt = f"{Tweet.datestamp} {Tweet.timestamp}"
j_data = {
"_index": config.Index_tweets,
......
import warnings
from .elasticsearch import *
from time import strftime, localtime
import pandas as pd
from .elasticsearch import *
import warnings
_blocks = []
def update(Tweet, session):
day = weekday(strftime("%A", localtime(Tweet.datetime)))
dt = "{} {}".format(Tweet.datestamp, Tweet.timestamp)
dt = f"{Tweet.datestamp} {Tweet.timestamp}"
_data = {
"id": Tweet.id,
......
......@@ -24,9 +24,9 @@ def getTweet(tw, mentions):
try:
text = getText(tw)
for i in range(len(mentions)):
mention = "@{}".format(mentions[i])
mention = f"@{mentions[i]}"
if mention not in text:
text = "{} {}".format(mention, text)
text = f"{mention} {text}"
except:
text = getText(tw)
......@@ -36,7 +36,7 @@ def getHashtags(text):
return re.findall(r'(?i)\#\w+', text, flags=re.UNICODE)
def getStat(tw, _type):
st = "ProfileTweet-action--{} u-hiddenVisually".format(_type)
st = f"ProfileTweet-action--{_type} u-hiddenVisually"
return tw.find("span", st).find("span")["data-tweet-stat-count"]
def getRetweet(profile, username, user):
......@@ -61,7 +61,7 @@ def Tweet(tw, location, config):
t.username = tw.find("span", "username").text.replace("@", "")
t.timezone = strftime("%Z", localtime())
for img in tw.findAll("img", "Emoji Emoji--forText"):
img.replaceWith("<{}>".format(img['aria-label']))
img.replaceWith(img["alt"])
t.mentions = getMentions(tw)
t.tweet = getTweet(tw, t.mentions)
t.location = location
......@@ -69,7 +69,7 @@ def Tweet(tw, location, config):
t.replies = getStat(tw, "reply")
t.retweets = getStat(tw, "retweet")
t.likes = getStat(tw, "favorite")
t.link = "https://twitter.com/{0.username}/status/{0.id}".format(t)
t.link = f"https://twitter.com/{t.username}/status/{t.id}"
t.retweet = getRetweet(config.Profile, t.username, config.Username)
t.user_rt = getUser_rt(config.Profile, t.username, config.Username)
return t
......@@ -2,69 +2,69 @@ mobile = "https://mobile.twitter.com"
base = "https://twitter.com/i"
async def Favorites(username, init):
url = "{}/{}/favorites?lang=en".format(mobile, username)
url = f"{mobile}/{username}/favorites?lang=en"
if init != -1:
url += "&max_id={}".format(init)
url += f"&max_id={init}"
return url
async def Followers(username, init):
url = "{}/{}/followers?lang=en".format(mobile, username)
url = f"{mobile}/{username}/followers?lang=en"
if init != -1:
url += "&cursor={}".format(init)
url += f"&cursor={init}"
return url
async def Following(username, init):
url = "{}/{}/following?lang=en".format(mobile, username)
url = f"{mobile}/{username}/following?lang=en"
if init != -1:
url += "&cursor={}".format(init)
url += f"&cursor={init}"
return url
async def MobileProfile(username, init):
url = "{}/{}?lang=en".format(mobile, username)
url = f"{mobile}/{username}?lang=en"
if init != -1:
url += "&max_id={}".format(init)
url += f"&max_id={init}"
return url
async def Profile(username, init):
url = "{}/profiles/show/{}/timeline/tweets?include_".format(base, username)
url = f"{base}/profiles/show/{username}/timeline/tweets?include_"
url += "available_features=1&lang=en&include_entities=1"
url += "&include_new_items_bar=true"
if init != -1:
url += "&max_position={}".format(init)
url += f"&max_position={init}"
return url
async def Search(config, init):
url = "{}/search/timeline?f=tweets&vertical=default&lang=en".format(base)
url = f"{base}/search/timeline?f=tweets&vertical=default&lang=en"
url += "&include_available_features=1&include_entities=1&"
url += "reset_error_state=false&src=typd&qf=off&max_position={}&q=".format(init)
url += f"reset_error_state=false&src=typd&qf=off&max_position={init}&q="
if config.Lang:
url = url.replace("lang=en", "l={0.Lang}&lang=en".format(config))
url = url.replace("lang=en", f"l={config.Lang}&lang=en")
if config.Username:
url += "from%3A{0.Username}".format(config)
url += f"from%3A{config.Username}"
if config.Geo:
config.Geo = config.Geo.replace(" ", "")
url += "geocode%3A{0.Geo}".format(config)
url += f"geocode%3A{config.Geo}"
if config.Search:
config.Search = config.Search.replace(" ", "%20")
config.Search = config.Search.replace("#", "%23")
url += "%20{0.Search}".format(config)
url += f"%20{config.Search}"
if config.Year:
url += "%20until%3A{0.Year}-1-1".format(config)
url += f"%20until%3A{config.Year}-1-1"
if config.Since:
url += "%20since%3A{0.Since}".format(config)
url += f"%20since%3A{config.Since}"
if config.Until:
url += "%20until%3A{0.Until}".format(config)
url += f"%20until%3A{config.Until}"
if config.Fruit:
url += "%20myspace.com%20OR%20last.fm%20OR"
url += "%20mail%20OR%20email%20OR%20gmail%20OR%20e-mail"
......@@ -73,12 +73,12 @@ async def Search(config, init):
if config.Verified:
url += "%20filter%3Averified"
if config.To:
url += "%20to%3A{0.To}".format(config)
url += f"%20to%3A{config.To}"
if config.All:
url += "%20to%3A{0.All}%20OR%20from%3A{0.All}%20OR%20@{0.All}".format(config)
url += f"%20to%3A{config.All}%20OR%20from%3A{config.All}%20OR%20@{config.All}"
if config.Near:
config.Near = config.Near.replace(" ", "%20")
config.Near = config.Near.replace(",", "%2C")
url += "%20near%3A%22{0.Near}%22".format(config)
url += f"%20near%3A%22{config.Near}%22"
return url
......@@ -43,7 +43,7 @@ def join(ur):
return jd.split(" - ")
def stat(ur, _type):
_class = "ProfileNav-item ProfileNav-item--{}".format(_type)
_class = f"ProfileNav-item ProfileNav-item--{_type}"
stat = ur.find("li", _class)
return stat.find("span", "ProfileNav-value")["data-count"]
......@@ -71,7 +71,7 @@ def verified(ur):
def User(ur):
u = user()
for img in ur.findAll("img", "Emoji Emoji--forText"):
img.replaceWith("<{}>".format(img['aria-label']))
img.replaceWith(img["alt"])
u.id = inf(ur, "id")
u.name = inf(ur, "name")
u.username = inf(ur, "username")
......
def Count(config, count):
if config.Count:
msg = "[+] Finished: Successfully collected "
if config.Followers:
msg += "all {0} users who follow @{1.Username}".format(count, config)
elif config.Following:
msg += "all {0} users who @{1.Username} follows".format(count, config)
elif config.Favorites:
msg += "{0} Tweets that @{1.Username} liked".format(count, config)
else:
msg += "{0} Tweets".format(count)
if config.Username:
msg += " from @{0.Username}".format(config)
msg += "."
print(msg)
def Count(count, username):
msg = "[+] Finished: Successfully collected "
if config.Followers:
msg += f"all {count} users who follow @{username}"
elif config.Following:
msg += f"all {count} users who @{username} follows"
elif config.Favorites:
msg += f"{count} Tweets that @{username} liked"
else:
msg += f"{count} Tweets"
if config.Username:
msg += f" from @{username}"
msg += "."
print(msg)
def Elastic(config):
if config.Elasticsearch:
print("[+] Indexing to Elasticsearch @ " + str(config.Elasticsearch))
def Elastic(elasticsearch):
if elasticsearch:
print("[+] Indexing to Elasticsearch @ " + str(elasticsearch))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment