예제 #1
0
    async def manual_login(self):
        client = await Client.create(headless=False)
        page = await client.new_page()

        await client.stealth(page)

        await client.goto("/login", page)
        await page.waitForSelector(".profile", options={"timeout": 0})
        await page.hover(".profile")

        await page.waitFor(".profile-actions > li:first-child")
        # going to "View profile" page
        await page.click(".profile-actions > li:first-child")
        await page.waitForSelector(".share-title", options={"timeout": 0})

        username = await page.Jeval(".share-title", pageFunction="element => element.textContent")
        username = username.strip()

        sub_title = await page.Jeval(
            ".share-sub-title",
            pageFunction="element => element.textContent",
        )

        logger.info(f"🔑 Logged as @{username} aka {sub_title}")

        cookies = await page.cookies()

        loaders.write(
            f"{settings.HOME_DIR}/settings.toml",
            {**BASE_SETTINGS, **{"COOKIES": json.dumps(cookies), "USERNAME": username}},
            env="default",
        )

        await client.browser.close()
예제 #2
0
    async def trending(self,
                       amount: int = 50,
                       lang: str = "en") -> List[FeedItem]:
        logger.info("📈 Getting trending items")
        items = await Trending(client=self.client).feed(amount=amount,
                                                        lang=lang)

        logger.info(f"📹 Found {len(items)} videos")
        _trending = FeedItems(__root__=items)

        return _trending.__root__
예제 #3
0
    async def user_feed(self,
                        username: str,
                        amount: int = 50) -> List[FeedItem]:
        username = f"@{username.lstrip('@')}"
        logger.info(f"📈 Getting {username} feed")
        items = await User(client=self.client).feed(username=username,
                                                    amount=amount)

        logger.info(f"📹 Found {len(items)} videos")
        feed = FeedItems(__root__=items)

        return feed.__root__
예제 #4
0
    async def __aexit__(
        self,
        exc_type: typing.Type[BaseException] = None,
        exc_value: BaseException = None,
        traceback: TracebackType = None,
    ) -> None:
        logger.debug("🤔Trying to close browser..")

        await self.client.browser.close()

        logger.debug("✋ Browser successfully closed")
        logger.info(
            "✋ TikTokPy finished working. Session lasted: {}",
            humanize.naturaldelta(datetime.now() - self.started_at),
        )
예제 #5
0
파일: settings.py 프로젝트: z-kf/tiktokpy
def load_or_create_settings(path: Optional[str]):
    path = path or DEFAULT_PATH

    if not Path(path).exists():
        default_settings_path = str(Path.cwd() / Path(DEFAULT_PATH))
        logger.info(
            f'🔧 Settings in path directory not found "{Path(path).absolute()}". '
            f"I'll create default settings here: {default_settings_path}",
        )
        Path(path).parent.mkdir(parents=True, exist_ok=True)

        loaders.write(default_settings_path, BASE_SETTINGS, env="default")

    settings.load_file(path=path)

    logger.info("🔧 Settings successfully loaded")
예제 #6
0
    async def unlike(self, username: str, video_id: str):
        page: Page = await self.client.new_page(
            blocked_resources=["image", "media", "font"])
        logger.debug(f"ЁЯСе Unlike video id {video_id} of @{username}")

        like_info_queue: asyncio.Queue = asyncio.Queue(maxsize=1)
        video_info_queue: asyncio.Queue = asyncio.Queue(maxsize=1)

        page.on(
            "response",
            lambda res: asyncio.create_task(
                catch_response_info(res, video_info_queue, "/item/detail"), ),
        )

        page.on(
            "response",
            lambda res: asyncio.create_task(
                catch_response_info(res, like_info_queue, "/commit/item/digg"),
            ),
        )

        logger.info(
            f"ЁЯзн Going to @{username}'s video {video_id} page for unlike")

        await self.client.goto(
            f"/@{username}/video/{video_id}",
            page=page,
            options={"waitUntil": "networkidle0"},
        )

        video_info = await video_info_queue.get()

        if not video_info["itemInfo"]["itemStruct"]["digged"]:
            logger.info(f"ЁЯШП @{username}'s video {video_id} already unliked")
            return

        like_part = await page.J(".like-part")

        if like_part:
            await page.click(".like-part")
        else:
            await page.click(
                ".video-feed-container .lazyload-wrapper:first-child .bar-item-wrapper:first-child",
            )

        like_info = await like_info_queue.get()

        if like_info["status_code"] == 0:
            logger.info(f"ЁЯСО @{username}'s video {video_id} unliked")
        else:
            logger.warning(
                f"тЪая╕П  @{username}'s video {video_id} probably not unliked")

        await page.close()
예제 #7
0
    def __init__(self, settings_path: Optional[str] = None):
        self.started_at = datetime.now()

        init_logger()
        load_or_create_settings(path=settings_path)

        if settings.get("COOKIES") and settings.get("USERNAME"):
            logger.info(f"✅ Used cookies of @{settings.USERNAME}")
        else:
            logger.info("🛑 Cookies not found, anonymous mode")

        logger.info("🥳 TikTokPy initialized")
예제 #8
0
    async def unfollow(self, username: str):
        page: Page = await self.client.new_page(
            blocked_resources=["image", "media", "font"])
        logger.debug(f"👥 Unfollow {username}")

        unfollow_info_queue: asyncio.Queue = asyncio.Queue(maxsize=1)

        page.on(
            "response",
            lambda res: asyncio.create_task(
                catch_response_info(res, unfollow_info_queue,
                                    "/commit/follow/user"), ),
        )

        logger.info(f"🧭 Going to {username}'s page for unfollowing")

        await self.client.goto(
            f"/@{username.lstrip('@')}",
            page=page,
            options={"waitUntil": "networkidle0"},
        )

        try:
            follow_title: str = await page.Jeval(
                ".follow-button",
                pageFunction="element => element.textContent",
            )
        except ElementHandleError:
            print("ElementHandleError")
            return

        if follow_title.lower() != "following" and follow_title.lower(
        ) != "friends":
            logger.info(f"😏 {username} already unfollowed")
            return

        await page.click(".follow-button")

        unfollow_info = await unfollow_info_queue.get()

        if unfollow_info["status_code"] == 0:
            logger.info(f"➖ {username} unfollowed")
        else:
            logger.warning(f"⚠️  {username} probably not unfollowed")

        await page.close()
예제 #9
0
    async def follow(self, username: str):
        page: Page = await self.client.new_page(
            blocked_resources=["image", "media", "font"])
        logger.debug(f"ЁЯСе Follow {username}")

        follow_info_queue: asyncio.Queue = asyncio.Queue(maxsize=1)

        page.on(
            "response",
            lambda res: asyncio.create_task(
                catch_response_info(res, follow_info_queue,
                                    "/commit/follow/user"), ),
        )

        logger.info(f"ЁЯзн Going to {username}'s page for following")

        await self.client.goto(
            f"/@{username.lstrip('@')}",
            page=page,
            options={"waitUntil": "networkidle0"},
        )

        follow_title: str = await page.Jeval(
            ".follow-button",
            pageFunction="element => element.textContent",
        )

        if follow_title.lower() != "follow":
            logger.info(f"ЁЯШП {username} already followed")
            return

        await page.click(".follow-button")

        follow_info = await follow_info_queue.get()

        if follow_info["status_code"] == 0:
            logger.info(f"тЮХ {username} followed")
        else:
            logger.warning(f"тЪая╕П  {username} probably not followed")

        await page.close()
예제 #10
0
    async def unlike(self, username: str, video_id: str):
        page: Page = await self.client.new_page(
            blocked_resources=["image", "media", "font"])
        logger.debug(f"👥 Unlike video id {video_id} of @{username}")

        like_info_queue: asyncio.Queue = asyncio.Queue(maxsize=1)

        page.on(
            "response",
            lambda res: asyncio.create_task(
                catch_response_info(res, like_info_queue, "/commit/item/digg"),
            ),
        )

        logger.info(
            f"🧭 Going to @{username}'s video {video_id} page for unlike")

        await self.client.goto(
            f"/@{username}/video/{video_id}",
            page=page,
            options={"waitUntil": "networkidle0"},
        )

        like_selector = ".lazyload-wrapper:first-child .item-action-bar.vertical > .bar-item-wrapper:first-child"  # noqa: E501
        is_unliked = await page.J(f'{like_selector} svg[fill="currentColor"]')

        if is_unliked:
            logger.info(f"😏 @{username}'s video {video_id} already unliked")
            return

        await page.click(like_selector)

        like_info = await like_info_queue.get()

        if like_info["status_code"] == 0:
            logger.info(f"👎 @{username}'s video {video_id} unliked")
        else:
            logger.warning(
                f"⚠️  @{username}'s video {video_id} probably not unliked")

        await page.close()
예제 #11
0
    async def unlike(self, username: str, video_id: str):
        page: Page = await self.client.new_page(
            blocked_resources=["image", "media", "font"])
        logger.debug(f"ЁЯСе Unlike video id {video_id} of @{username}")

        like_info_queue: asyncio.Queue = asyncio.Queue(maxsize=1)

        page.on(
            "response",
            lambda res: asyncio.create_task(
                catch_response_info(res, like_info_queue, "/commit/item/digg"),
            ),
        )

        logger.info(
            f"ЁЯзн Going to @{username}'s video {video_id} page for unlike")

        await self.client.goto(
            f"/@{username}/video/{video_id}",
            page=page,
            options={"waitUntil": "networkidle0"},
        )

        like_element = await page.J("span.like")

        if "liked" not in like_element._remoteObject["description"]:
            logger.info(f"ЁЯШП @{username}'s video {video_id} already unliked")
            return

        await page.click(".like-part")

        like_info = await like_info_queue.get()

        if like_info["status_code"] == 0:
            logger.info(f"ЁЯСН @{username}'s video {video_id} unliked")
        else:
            logger.warning(
                f"тЪая╕П  @{username}'s video {video_id} probably not unliked")

        await page.close()
예제 #12
0
파일: user.py 프로젝트: nadirg/tiktokpy
    async def feed(self, username: str, amount: int):
        page: Page = await self.client.new_page(blocked_resources=["image", "media", "font"])
        logger.debug(f"ЁЯУи Request {username} feed")

        result: List[dict] = []
        user_info_queue: asyncio.Queue = asyncio.Queue(maxsize=1)

        page.on(
            "response", lambda res: asyncio.create_task(catch_response_and_store(res, result)),
        )

        page.on(
            "response",
            lambda res: asyncio.create_task(
                catch_response_info(res, user_info_queue, "/user/detail"),
            ),
        )
        _ = await self.client.goto(f"/{username}", page=page, options={"waitUntil": "networkidle0"})
        logger.debug(f"ЁЯУн Got {username} feed")

        await page.waitForSelector(".video-feed-item", options={"visible": True})

        user_info = await user_info_queue.get()
        user_video_count = user_info["userInfo"]["stats"]["videoCount"]

        if user_video_count < amount:
            logger.info(
                f"тЪая╕П  User {username} has only {user_video_count} videos. "
                f"Set amount from {amount} to {user_video_count}",
            )
            amount = user_video_count

        pbar = tqdm(total=amount, desc=f"ЁЯУИ Getting {username} feed")
        pbar.n = min(len(result), amount)
        pbar.refresh()

        attempts = 0
        last_result = len(result)

        while len(result) < amount:
            logger.debug("ЁЯЦ▒ Trying to scroll to last video item")
            await page.evaluate(
                """
                document.querySelector('.video-feed-item:last-child')
                    .scrollIntoView();
            """,
            )
            await page.waitFor(1_000)

            elements = await page.JJ(".video-feed-item")
            logger.debug(f"ЁЯФО Found {len(elements)} items for clear")

            pbar.n = min(len(result), amount)
            pbar.refresh()

            if last_result == len(result):
                attempts += 1
            else:
                attempts = 0

            if attempts > 10:
                pbar.clear()
                pbar.total = len(result)
                logger.info(
                    f"тЪая╕П  After 10 attempts found {len(result)} videos. "
                    f"Probably some videos are private",
                )
                break

            last_result = len(result)

            if len(elements) < 500:
                logger.debug("ЁЯФ╗ Too less for clearing page")
                continue

            await page.JJeval(
                ".video-feed-item:not(:last-child)",
                pageFunction="(elements) => elements.forEach(el => el.remove())",
            )
            logger.debug(f"ЁЯОЙ Cleaned {len(elements) - 1} items from page")
            await page.waitFor(30_000)

        await page.close()
        pbar.close()
        return result[:amount]
예제 #13
0
파일: user.py 프로젝트: z-kf/tiktokpy
    async def feed(self, username: str, amount: int):
        page: Page = await self.client.new_page(blocked_resources=["image", "media", "font"])
        logger.debug(f"📨 Request {username} feed")

        result: List[dict] = []

        page.on(
            "response",
            lambda res: asyncio.create_task(catch_response_and_store(res, result)),
        )

        _ = await self.client.goto(f"/{username}", page=page, options={"waitUntil": "networkidle0"})
        logger.debug(f"📭 Got {username} feed")

        await page.waitForSelector(".video-feed-item", options={"visible": True})

        pbar = tqdm(total=amount, desc=f"📈 Getting {username} feed")
        pbar.n = min(len(result), amount)
        pbar.refresh()

        attempts = 0
        last_result = len(result)

        while len(result) < amount:
            logger.debug("🖱 Trying to scroll to last video item")
            await page.evaluate(
                """
                document.querySelector('.video-feed-item:last-child')
                    .scrollIntoView();
            """,
            )
            await page.waitFor(1_000)

            elements = await page.JJ(".video-feed-item")
            logger.debug(f"🔎 Found {len(elements)} items for clear")

            pbar.n = min(len(result), amount)
            pbar.refresh()

            if last_result == len(result):
                attempts += 1
            else:
                attempts = 0

            if attempts > 10:
                pbar.clear()
                pbar.total = len(result)
                logger.info(
                    f"⚠️  After 10 attempts found {len(result)} videos. "
                    f"Probably some videos are private",
                )
                break

            last_result = len(result)

            if len(elements) < 500:
                logger.debug("🔻 Too less for clearing page")
                continue

            await page.JJeval(
                ".video-feed-item:not(:last-child)",
                pageFunction="(elements) => elements.forEach(el => el.remove())",
            )
            logger.debug(f"🎉 Cleaned {len(elements) - 1} items from page")
            await page.waitFor(30_000)

        await page.close()
        pbar.close()
        return result[:amount]