예제 #1
0
 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}')
예제 #2
0
  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}')
예제 #3
0
def clear(silent=False):
  cache = _get_cache_fs()
  dir = cache.getsyspath('/')
  for the_file in os.listdir(dir):
    file_path = os.path.join(dir, the_file)
    try:
      if os.path.isfile(file_path):
        os.unlink(file_path)
    except Exception as e:
      pass
    else:
      if not silent:
        logger.info('All stored data has been erased')
예제 #4
0
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()
예제 #5
0
def _is_logged(username):
  session, expired = create_session(username), False
  if session is not None:
    for cookie in session.cookies:
      if cookie.is_expired():
        expired = True
        break
      if cookie.name == 'auth_token':
        logger.info(f'You have signed in as {username}')
        return True
  if expired:
    # remove cookies for that user
    file = _get_cache_fs().getsyspath(
      f'{username}-{constants.COOKIES_FILE}'
    )
    os.remove(file)
    logger.warning(f'{username}\'s session has expired. Please sign in.')
  else:
    logger.warning(f'No sessions found for {username}.')
  return False
예제 #6
0
 def _finish(self, query, tweet_count):
   self._queue.put(_sentinel)
   time.sleep(3) # some executor may be still working
   logger.info(f'{query} --- Total tweets found:{tweet_count}')
예제 #7
0
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()