def __init__(self): kwargs = authentication.botometer.copy() kwargs["wait_on_rate_limit"] = True self.botometer = Botometer(**kwargs) self.status = BotometerStatus.PENDING self._probability = None self.user_id = None
def botometer(follower): kwargs = authentication.botometer.copy() kwargs["wait_on_rate_limit"] = True api = Botometer(**kwargs) try: result = api.check_account(follower) except NoTimelineError: return 0.5 # user with no post, let's toss a coin return result.get("cap", {}).get("universal")
class BotometerResult: """Holds Botometer result and avoids repeating the request to their API""" def __init__(self): kwargs = authentication.botometer.copy() kwargs["wait_on_rate_limit"] = True self.botometer = Botometer(**kwargs) self.status = BotometerStatus.PENDING self._probability = None self.user_id = None def _get_result(self): try: result = self.botometer.check_account(self.user_id) except NoTimelineError: self.status = BotometerStatus.UNAVAILABLE else: self._probability = result.get("cap", {}).get("universal") self.status = BotometerStatus.READY @property def probability(self): if not self.user_id: raise RuntimeError("Cannot use Botometer without an account ID") if self.status is BotometerStatus.PENDING: self._get_result() return self.probability if self.status is BotometerStatus.UNAVAILABLE: return 0.0 # let's assume it's not a bot return self._probability
class BotometerResult: """Holds Botometer result and avoids repeating the request to their API""" def __init__(self, user_id): kwargs = authentication.botometer.copy() kwargs["wait_on_rate_limit"] = True self.botometer = Botometer(**kwargs) self.status = BotometerStatus.PENDING self._probability = None self.user_id = user_id def run(self): self.status = BotometerStatus.RUNNING try: result = self.botometer.check_account(self.user_id) except NoTimelineError: self.status = BotometerStatus.UNAVAILABLE self._probability = 0.0 # let's assume it's not a bot else: self.status = BotometerStatus.READY self._probability = result.get("cap", {}).get("universal") @property def probability(self): if self._probability is not None: return self._probability if self.status is BotometerStatus.PENDING: self.run() return self._probability
def create_botometer(mashape_key, twitter_api_auth): try: bom = Botometer(wait_on_rate_limit=True, mashape_key=mashape_key, **twitter_api_auth) except tweepy.TweepError: error(config_complete_path, 'Failed to connect to Botometer API') return bom
def create_botometer(mashape_key, twitter_api_auth): try: # 8HK07BkyjOmshRCv6uHzqpJm73eSp1TUxNVjsnKYKn25VJG2rL bom = Botometer( wait_on_rate_limit=True, mashape_key="bd3376f8eemsh4ffa96f56d33b33p16f69cjsn802fbb18ba09", **twitter_api_auth) except tweepy.TweepError: error(config_complete_path, 'Failed to connect to Botometer API') return bom
def set_up_botometer(self) -> Botometer: botometer_api: Botometer = object.__new__(Botometer) try: botometer_api: Botometer = Botometer(wait_on_ratelimit=True, rapidapi_key=self.api_key, **self.twitter_app_auth) except Exception as e: logger.error(e) return botometer_api
class User(models.User): """A wrapper for Tweepy native User model, including custom methods to check idle accounts and bots""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) authentication = Authentication() self.botometer = Botometer(wait_on_ratelimit=True, **authentication.botometer) self._botometer_result = None @classmethod def parse(cls, api, data): """This is how Tweepy instantiate User models from the API result""" return super(User, cls).parse(api, data) def last_status_before(self, **kwargs): """Takes any kwarg compatible with Python's `timedelta` and says whether the user's last tweet is older than the `timedelta` defined by these kwargs""" if not getattr(self, "status", None): return False return self.status.created_at < datetime.now() - timedelta(**kwargs) @property def botometer_result(self): if self._botometer_result: return self._botometer_result result = self.botometer.check_account(self.id) self._botometer_result = result.get("cap", {}).get("universal") return self.botometer_result def is_bot(self, threshold=0.75): if self.protected or not self.botometer_result: return False return self.botometer_result > threshold
mashape_key = "e7b7a5ab38msh5ddc881afcc3bdcp101997jsn03924e682235" twitter_app_auth = { 'consumer_key': C_KEY, 'consumer_secret': C_SECRET, 'access_token': A_TOKEN, 'access_token_secret': A_TOKEN_SECRET, } auth = tweepy.OAuthHandler(C_KEY, C_SECRET) auth.set_access_token(A_TOKEN, A_TOKEN_SECRET) api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True, compression=True) botometer = Botometer(wait_on_ratelimit=True, mashape_key=mashape_key, **twitter_app_auth) # User is exactly the user object from the request. # Scores contains the overall classification results. # The english score uses all six categories of features # The universal score omits sentiment and content features, both of which are English-specific. # Categories gives subscores for each of the six feature classes. # Content, sentiment = English specific features # Language independent features = Friend, network, temporal, user def get_bom_scores(): accounts = [] scores = {}
botometer_key = apis.botometer_api() twitter_app_auth = { 'consumer_key': twitter_api['consumer_key'], 'consumer_secret': twitter_api['consumer_secret'], 'access_token': twitter_api['access_token'], 'access_token_secret': twitter_api['access_secret'], } ''' Botometer implementation from https://github.com/IUNetSci/botometer-python Details at https://rapidapi.com/OSoMe/api/Botometer%20Pro/details ''' bom = Botometer(wait_on_ratelimit=True, rapidapi_key=botometer_key, **twitter_app_auth) # Check a single account by screen name or id def get_user_account(user, id=True): if id: user = int(user) return bom.check_account(user) def get_accounts(users, folder, id=True): collected = fx.get_fnames(folder)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) authentication = Authentication() self.botometer = Botometer(wait_on_ratelimit=True, **authentication.botometer) self._botometer_result = None
def get_friends_bot_likelihood_scores(api: botometer.Botometer, friends: list) -> list: """Get bot likelihood scores for Twitter friends. https://github.com/IUNetSci/botometer-python/blob/master/botometer/__init__.py#L140 Args: api (botometer.Botometer): A botometer.Botometer object authenticated to the Botometer and Twitter API. friends (list): A list containing a Twitter account's friends (represented as IDs). Returns: list: A list containing the bot likelihood scores for each Twitter friend. """ loguru.logger.info( "Getting Twitter friends bot likelihood scores from Botometer.") # Initialise list containing each friend's bot likelihood score # List contains dictionaries with the bot likelihood scores for each friend friends_bot_likelihood_scores = [] try: # Get all friends bot likelihood scores from the Botometer API # Retry 3 times for each friend if an exception occurs for friend_id, results in api.check_accounts_in(accounts=friends, full_user_object=False, retries=3): # A TweepyError or NoTimelineError can occur when Botometer checks a friend # https://github.com/IUNetSci/botometer-python/blob/master/botometer/__init__.py#L153 # When these occur the result is a dictionary containing an error message: # {"error": err_msg} # Check first if this type of result has been returned error_msg = results.get("error", None) if error_msg: # Error message has been returned as the result # Log a warning message loguru.logger.warning( f"Botometer returned the following error for friend with ID: {friend_id}.\n{error_msg}" ) # Got a successful response for this friend from the Botometer API else: # Example JSON response: https://github.com/IUNetSci/botometer-python#botometer-v4 # Drop cap and raw_scores keys and values from the dictionary # As they are not required and to save memory results.pop("cap") results.pop("raw_scores") # Get friend's Twitter username (screen name) friend_username = results["user"]["user_data"]["screen_name"] loguru.logger.success( f"Got bot likelihood results from Botometer for friend: @{friend_username}, {friend_id}" ) # Add friend's bot likelihood results to the list loguru.logger.debug( f"Adding bot likelihood results for friend: @{friend_username}, {friend_id} to the list." ) friends_bot_likelihood_scores.append(results) # Check if the list has one or more results if bool(friends_bot_likelihood_scores): # The list contains at least one or more results loguru.logger.debug( "The friends bot likelihood scores list has one or more results." ) return friends_bot_likelihood_scores else: # The list contains no results, log a terminating error loguru.logger.exception( "Failed to get any friends bot likelihood results.") # The `check_accounts_in` method can raise the following exceptions once all retires have been exhausted: # requests: ConnectionError, HTTPError, Timeout ## https://github.com/IUNetSci/botometer-python/blob/master/botometer/__init__.py#L159 # Standard Python Exception ## https://github.com/IUNetSci/botometer-python/blob/master/botometer/__init__.py#L164 # If one of these occur, the application should return the friend bot likelihood scores it has collected # up to the point of failure. As long as it has not failed on the first attempt (as the list would be empty) except ( botometer.ConnectionError, botometer.HTTPError, botometer.Timeout, Exception, ) as err: loguru.logger.warning( f"An exception occurred and all retries to Botometer have been exhausted.\n{err}" ) # Check if the list has one or more results if bool(friends_bot_likelihood_scores): # The list contains at least one or more results loguru.logger.debug( "The friends bot likelihood scores list has one or more results." ) return friends_bot_likelihood_scores else: # The list contains no results, log a terminating error loguru.logger.exception( f"Failed to get any friends bot likelihood results.\n{err}")