sergey-scat / unicaps

A unified Python API for CAPTCHA solving services.
Apache License 2.0
218 stars 18 forks source link

Pass base64 image directly to service #24

Open khoben opened 6 months ago

khoben commented 6 months ago

How to pass base64 string image to the service (rucaptcha/2captcha) without re-decoding? Due to type checking and a fixed set of captcha types, it is not possible to simply replace class types.

khoben commented 6 months ago

Temporary hack:

class Base64String:
    """String mimics to bytes decoding"""

    def __init__(self, base64: str) -> None:
        self.base64 = base64

    def decode(self, *args, **kwargs) -> str:
        return self.base64

@dataclass
class ImageBase64StringCaptcha(ImageCaptcha):
    """ImageCaptcha: pass base64 string image directly"""

    image: str

    def __post_init__(self):
        pass

    def get_image_bytes(self) -> bytes:
        return base64.b64decode(self.image[self.image.find(",") + 1 :])

    def get_image_base64(self) -> Base64String:
        return Base64String(self.image)

    def get_image_type(self) -> str:
        return "base64"

    @classmethod
    def get_type(cls) -> CaptchaType:
        """Return CaptchaType"""

        return ImageCaptcha.get_type()

    @classmethod
    def get_solution_class(cls) -> BaseCaptchaSolution:
        """Return appropriate solution class"""

        return ImageCaptcha.get_solution_class()
async def solve_image_base64_captcha(
    service: AsyncCaptchaSolver, image: str, **kwargs
) -> AsyncSolvedCaptcha:
    r"""Solves image CAPTCHA.

    :param service: AsyncCaptchaSolver
    :param image: str object containing base64 image with CAPTCHA
    :param char_type: (optional) Character type.
    :param is_phrase: (optional) Boolean. True if CAPTCHA contains more than one word.
    :param is_case_sensitive: (optional) Boolean.
    :param is_math: (optional) Boolean. True if CAPTCHA requires calculation.
    :param min_len: (optional) Integer. Minimum length of the CAPTCHA's text.
    :param max_len: (optional) Integer. Maximum length of the CAPTCHA's text.
    :param alphabet: (optional) Alphabet used in the CAPTCHA.
    :param language: (optional) Language.
    :param comment: (optional) String. Text instructions for worker.
    :return: :class:`AsyncSolvedCaptcha <AsyncSolvedCaptcha>` object
    :rtype: unicaps.AsyncSolvedCaptcha
    """

    return await service._solve_captcha_async(
        ImageBase64StringCaptcha, image, **kwargs
    )

async def main():
    async with AsyncCaptchaSolver(CaptchaSolvingService.TWOCAPTCHA, API_KEY) as solver:
        solved = await solve_image_base64_captcha(
            solver,
            BASE64_STRING_IMAGE,
            is_phrase=False,
            is_case_sensitive=True
        )
        print(f'CAPTCHA text: {solved.solution.text}')
        await solved.report_good()

if __name__ == '__main__':
    asyncio.run(main())