def execute(self, delay): user = self.tweet.user res = self.make_request(constants.FOLLOW_URL, error_delay=delay) if res.status_code != 200: logger.error(f'failed to follow {user.username}') else: logger.info(f'followed: {user.username}')
def execute(self, delay): time.sleep(delay) res = self.make_request(url=constants.LIKE_URL, error_delay=delay) if res.status_code != 200: logger.error(f'failed to like: {self.tweet}') else: logger.info(f'liked: {self.tweet}')
def execute(self): while True: actions = self._queue.get() if actions is _sentinel: self._queue.put(_sentinel) self._queue.task_done() break if not isinstance(actions, collections.Iterable): actions = (actions, ) for action in actions: if not isinstance(action, Action): logger.error(f'expected object of Action type, got {type(action)}') continue action.execute(self._delay) self._queue.task_done()
def make_request(self, url, method='post', error_delay=5, tries=10, allow_redirects=False): with self.get_session() as session: while tries > 0: try: request = getattr(session, method.lower()) res = request( url = url, data = self.payload, allow_redirects = allow_redirects ) return res except Exception as ex: logger.error(ex) # TODO: remove this time.sleep(error_delay) tries -= 1
def get_session(self): username = os.environ['username'] session = create_session(username) cookies = requests.utils.dict_from_cookiejar(session.cookies) if 'ct0' not in cookies: logger.error(f'{username}\'s session has expired. Log in again') clear(silent=True) os._exit(1) # TODO: a better way to do this? session.headers['User-Agent'] = ua_provider.fetch() session.headers['Authorization'] = constants.BEARER session.headers['X-Twitter-Auth-Type'] = 'OAuth2Session' session.headers['X-Twitter-Active-User'] = '******' session.headers['Origin'] = constants.BASE_URL session.headers['x-csrf-token'] = cookies['ct0'] return session
def _make_request(self, query, limit=None): params = { 'vertical': 'default', 'src': 'typd', 'include_available_features': '1', 'include_entities': '1', 'q': query } if bool(random.getrandbits(1)): params['f'] = 'tweets' # this will fetch the latest if limit is not None: params['max_position'] = limit tries = self._error_tries with create_session(os.environ['username']) as session: # set headers session.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01' session.headers['Accept-Language'] = 'en-US,en;q=0.5' session.headers['Referer'] = constants.SEARCH_URL session.headers['X-Requested-With'] = 'XMLHttpRequest' session.headers['X-Twitter-Active-User'] = '******' while tries > 0: try: session.headers['User-Agent'] = ua_provider.fetch() res = session.get(constants.TIMELINE_SEARCH_URL, params=params) data = res.json() # check if we have what we need data['inner']['items_html'] return data['inner'] except Exception as e: logger.error(f'{self._error_tries - tries }-search request has failed:\n{e}') time.sleep(self._error_delay) tries -= 1 logger.error(f'failed to make the search request: {query}') exit()
def login(username, password, tries=10, delay=2): with create_session(username) as session: res = session.get(constants.LOGIN_URL) soup = BeautifulSoup(res.text,"html.parser") token = soup.select_one("[name='authenticity_token']")['value'] payload = { 'session[username_or_email]':username, 'session[password]': password, 'authenticity_token':token, 'ui_metrics': constants.UI_METRICS, 'authenticity_token':token, 'remember_me':1 } session.headers['Origin'] = constants.BASE_URL session.headers['Referer'] = constants.LOGIN_URL session.headers['Upgrade-Insecure-Requests'] = '1' time.sleep(5) # pause a bit while tries > 0: try: session.headers['User-Agent'] = ua_provider.fetch() res = session.post(constants.SESSIONS_URL, data=payload, allow_redirects=False) res.raise_for_status() if 'location' in res.headers: url = res.headers['location'] if 'locked' in url: logger.error('Too many attempts. Your account has been locked (60 mins).') exit() elif 'error' in url: raise InvalidCredentials if 'auth_token' in res.cookies.get_dict(): typing.cast(FileCookieJar, session.cookies).save() logger.info(f'You have signed in as {username}') return except Exception as ex: if isinstance(ex, InvalidCredentials): raise logger.error(f'Error while signing in:\n{ex}') pass time.sleep(delay) tries -= 1 # Twitter won't provide auth_token in cookies or ban logger.error( '''Failed to sign in. Your IP address (or account) may have been banned (yikes). Try logging in through your browser. If you can't log in, then you've been banned.''' ) exit()
def main(): if sys.version_info[0] < 3: logger.error('Python 3 or a more recent version is required.') exit() parser = argparse.ArgumentParser() parser.add_argument( '-a', '--agents', help='File containing user-agents', dest='agents_file', default=f'{default_config_path}/user-agents.txt' ) parser.add_argument( '-i', '--invalidate', help='Invalidate all saved sessions', dest='invalidate', action='store_true' ) parser.add_argument( '-v', '--version', help='Version of the bot', dest='version', action='store_true' ) parser.add_argument( '-c', '--config', help='Configuration file', dest='config', default=f'{default_config_path}/config.json' ) parser.add_argument( '-e', '--executor-count', help='How many executors should we have running', dest='executor_count', default=2 ) args = parser.parse_args() if args.version: logger.info(f'tweebot version: {__version__}') exit() if args.invalidate: _base.clear() if args.agents_file: ua_provider.load(args.agents_file) if not args.config: logger.error('You need to provide the path to the config.json file') exit() config = {} try: with open(args.config, encoding='UTF-8') as fp: config = json.loads(fp.read()) config['searchers']; config['handlers'] # quick check except Exception as ex: exit(f'Failed to read config.json .\n {ex}') if not 'executors' in config: if not args.executor_count: logger.error( '''You will need to provide configurations for the executor object. Check the docs for more info.''' ) exit() config['executors'] = [{ 'count': args.executor_count, 'request-delay': 2 }] while True: username = input('Twitter username: '******'Twitter password: '******'Invalid credentials.Try again') continue os.environ['username'] = username break tweet_queue = queue.Queue() action_queue = queue.Queue() for params in config['searchers']: searcher = _get_searchers(tweet_queue, params) _spin_searchers(searcher['query'], searcher['searchers']) for params in config['handlers']: handler = _get_handlers(tweet_queue, action_queue, params) _spin_handlers(handler) for params in config['executors']: executors = _get_executors(action_queue, **params) _spin_executors(executors) tweet_queue.join(); action_queue.join()