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

Update

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