import os

from instauto.api.client import ApiClient
from instauto.api.actions import post as ps

if __name__ == '__main__':
    if os.path.isfile('./.instauto.save'):
        client = ApiClient.initiate_from_file('./.instauto.save')
    else:
        client = ApiClient(username=os.environ.get("INSTAUTO_USER")
                           or "your_username",
                           password=os.environ.get("INSTAUTO_PASS")
                           or "your_password")
        client.log_in()
        client.save_to_disk('./.instauto.save')

    post = ps.PostStory(path='./test_story.jpg', )
    resp = client.post_post(post, 80)
    print("Success: ", resp.ok)
示例#2
0
文件: bot.py 项目: returnWOW/instauto
class Bot:
    stop: bool = False
    input: Input
    _actions: List = []

    def __init__(self,
                 username: Optional[str] = None,
                 password: Optional[str] = None,
                 client: Optional[ApiClient] = None,
                 delay_between_action: float = 2.0,
                 delay_variance: float = 0.0) -> None:
        """Initiate a new `Bot` instance.

        Args:
            username: the username of the account
            password: the password of the account
            client: the `ApiClient` instance the Bot communicates with. If given, it will take precedence over credentials.
            delay_between_action: the amount of seconds to wait between actions (each like, follow, etc. is an action)
            delay_variance: the amount of variance to add to the delay. Delay will be random number between (delay - variance) - (delay + variance).
        """

        if client is not None:
            self._client = client
        elif username and password:
            self._initialize_client_from_credentials(username, password)
        else:
            raise Exception("Use either a username/password or an ApiClient")

        self.input = Input(self._client)
        self._actions = []
        self._delay = delay_between_action if (delay_between_action) else 0
        self._delay_variance = abs(delay_variance)

    def _initialize_client_from_credentials(self, username: str,
                                            password: str) -> None:
        instauto_save_path = f'.{username}.instauto.save'
        if os.path.isfile(instauto_save_path):
            self._client = ApiClient.initiate_from_file(instauto_save_path)
        else:
            self._client = ApiClient(username=username, password=password)
            self._client.log_in()
            self._client.save_to_disk(instauto_save_path)

    def like(self, chance: int, amount: int) -> "Bot":
        """Like posts of users retrieved with the Input pipeline.

        Args:
            chance: integer between 0 and 100, represents a percentage between 0 and 100%.
                Defines the chance of this action being called for an account. Set to
                25 to call on 1/4 of all accounts, 50 for 1/2 of all accounts, etc.
            amount:
                The amount of posts to like, if this action is being called for an account.
        """
        self._actions.append({
            'func': like_post,
            'chance': chance,
            'amount': amount,
            'args': ('POST_ID', )
        })
        return self

    def comment(self, chance: int, amount: int, comments: List[str]) -> "Bot":
        """Comment on posts of users retrieved with the Input pipeline.

        Args:
            chance: integer between 0 and 100, represents a percentage between 0 and 100%.
                Defines the chance of this action being called for an account. Set to
                25 to call on 1/4 of all accounts, 50 for 1/2 of all accounts, etc.
            amount:
                The amount of posts to comment on, if this action is being called for an account.
            comments:
                A random selected entry out of this list will be used as text to comment.
        """
        self._actions.append({
            'func': comment_post,
            'chance': chance,
            'amount': amount,
            'args': ('POST_ID', (random.choice, comments))
        })
        return self

    def follow(self, chance: int) -> "Bot":
        """Follow users retrieved with the Input pipeline.

        Args:
            chance: integer between 0 and 100, represents a percentage between 0 and 100%.
                Defines the chance of this action being called for an account. Set to
                25 to call on 1/4 of all accounts, 50 for 1/2 of all accounts, etc.
        """
        self._actions.append({
            'func': follow_user,
            'chance': chance,
            'args': ('ACCOUNT_ID', )
        })
        return self

    def start(self):
        """Start the bot.

        Once the bot is started, it will run until it went through all retrieved accounts,
        or if the `stop` attribute is set to `True`."""
        accounts = self.input.filtered_accounts
        while not self.stop:
            self._sleep_between_actions()
            account = accounts.pop(random.randint(0, len(accounts) - 1))
            for action in self._actions:
                if random.randint(0, 100) > action['chance']:
                    continue

                t = action['args'][0]
                if t == 'POST_ID':
                    posts = self._get_posts(account['username'])
                    for _ in range(action['amount']):
                        if not posts:
                            continue
                        post = posts.pop(random.randint(0, len(posts) - 1))
                        args = self._resolve_args(action['args'], post=post)
                        try:
                            action['func'](self._client, *args)
                        except Exception as e:
                            logger.warning("Caught exception: ", e)
                elif t == 'ACCOUNT_ID':
                    args = self._resolve_args(action['args'], account=account)
                    try:
                        action['func'](self._client, *args)
                    except Exception as e:
                        logger.warning("Caught exception: ", e)

    def _sleep_between_actions(self):
        min = (self._delay -
               self._delay_variance) if (self._delay -
                                         self._delay_variance) else 0
        max = self._delay + self._delay_variance
        sleeptime = round(random.uniform(min, max), 2)
        sleep(sleeptime)

    def _get_posts(self,
                   account_name: str,
                   force: bool = False) -> List[models.Post]:
        return self.input.get_posts(account_name, force)

    @staticmethod
    def _resolve_args(args: Tuple,
                      post: Optional[models.Post] = None,
                      account: Optional[models.User] = None) -> List:
        a = list()
        for arg in args:
            if isinstance(arg, tuple) and callable(arg[0]):
                a.append(arg[0](*arg[1::]))
            else:
                a.append(arg)
        for i, arg in enumerate(a.copy()):
            if arg == 'POST_ID' and post is not None:
                a[i] = post.pk
            elif arg == 'ACCOUNT_ID' and account is not None:
                a[i] = account.pk
        return a

    @classmethod
    def from_client(cls,
                    client: ApiClient,
                    delay_between_action: float = 2.0,
                    delay_variance: float = 0.0) -> "Bot":
        return cls("",
                   "",
                   client=client,
                   delay_between_action=delay_between_action,
                   delay_variance=delay_variance)