diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 11f2691..1d4365d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,44 @@ Changelog ========= +Unreleased +---------- + +Added +##### + +- Add context manager support to ``AnticaptchaClient`` (``__enter__``, ``__exit__``, ``close``) +- Add ``ANTICAPTCHA_API_KEY`` environment variable fallback for ``AnticaptchaClient`` +- Add ``Proxy`` frozen dataclass with ``parse_url()`` and ``to_kwargs()`` methods +- Add snake_case aliases: ``create_task``, ``create_task_smee``, ``get_balance``, ``get_app_stats`` +- Add ``py.typed`` marker and complete type annotations (`#124 `_) +- Add ``__repr__`` to ``Job``, ``AnticaptchaClient``, and ``BaseTask`` (`#123 `_) +- Add optional ``on_check`` callback to ``Job.join()`` (`#125 `_) +- ``ImageToTextTask`` now accepts file paths (``str``/``Path``), raw bytes, or file-like objects + +Changed +####### + +- **Breaking:** Minimum Python version increased from 2.7+ to 3.9+ +- Migrate from ``setup.py`` / ``setup.cfg`` to ``pyproject.toml`` (PEP 621) (`#122 `_) +- Switch README from RST to Markdown (`#126 `_) +- Switch test runner from nose2 to pytest +- Switch PyPI publishing to trusted publishing via GitHub Actions (`#114 `_) +- Fix ``RecaptchaV2EnterpriseTask`` missing proxyless base class inheritance +- Fix ``ImageToTextTask.serialize()`` sending ``None`` values +- Fix ``GeeTestTask`` incorrect inheritance +- Fix ``AntiGateTaskProxyless`` super() call +- Remove redundant cookies serialization in ``ProxyMixin`` +- Use Python 3 ``super()`` without arguments throughout codebase + +Removed +####### + +- Drop Python 2.7 and Python 3.4-3.8 support +- Remove ``six`` dependency (replaced with stdlib ``urllib.parse``) +- Remove ``compat.py`` module +- Remove legacy ``setup.py`` and ``setup.cfg`` + 1.0.0 - 2022-03-28 ------------------ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index fe881b9..51a77f3 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at naczelnik@jawnosc.tk. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at naczelnik@jawne.info.pl. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/Makefile b/Makefile index d85d900..acbb680 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ CHROMEDRIVER_VERSION=99.0.4844.17 -CHROMEDRIVER_DIR=${PWD}/geckodriver +CHROMEDRIVER_DIR=${PWD}/chromedriver -.PHONY: lint fmt build docs install test test_e2e gecko +.PHONY: lint fmt build docs install test test_e2e chromedriver build: - python setup.py sdist bdist_wheel + python -m build install: install_test install_docs install_pkg @@ -18,7 +18,7 @@ install_pkg: python -m pip install --upgrade pip wheel pip install . -gecko: +chromedriver: mkdir -p ${CHROMEDRIVER_DIR} wget -q -P ${CHROMEDRIVER_DIR} "http://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip" unzip ${CHROMEDRIVER_DIR}/chromedriver* -d ${CHROMEDRIVER_DIR} @@ -28,10 +28,10 @@ test: pytest test_e2e: - PATH=$$PWD/geckodriver:$$PATH pytest -m e2e --override-ini="addopts=" + PATH=$$PWD/chromedriver:$$PATH pytest -m e2e --override-ini="addopts=" clean: - rm -r build geckodriver + rm -r build chromedriver lint: docker run --rm -v /$$(pwd):/apps alpine/flake8 ./ diff --git a/README.md b/README.md index d664fb3..b91cb75 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ [![Build Status](https://github.com/ad-m/python-anticaptcha/workflows/Python%20package/badge.svg)](https://github.com/ad-m/python-anticaptcha/actions?workflow=Python+package) [![PyPI](https://img.shields.io/pypi/v/python-anticaptcha.svg)](https://pypi.org/project/python-anticaptcha/) [![Chat](https://badges.gitter.im/python-anticaptcha/Lobby.svg)](https://gitter.im/python-anticaptcha/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link) -[![Python compatibility](https://img.shields.io/pypi/pyversions/python-anticaptcha.svg)](https://github.com/ad-m/python-anticaptcha/blob/master/setup.py) +[![Python compatibility](https://img.shields.io/pypi/pyversions/python-anticaptcha.svg)](https://github.com/ad-m/python-anticaptcha/blob/master/pyproject.toml) -Client library for solve captchas with [Anticaptcha.com support](http://getcaptchasolution.com/i1hvnzdymd). +Client library for solving captchas with [Anticaptcha.com support](http://getcaptchasolution.com/i1hvnzdymd). The library requires Python >= 3.9. The library is cyclically and automatically tested for proper operation. We are constantly making the best efforts for its effective operation. @@ -22,7 +22,7 @@ pip install python-anticaptcha ## Usage -To use this library do you need [Anticaptcha.com](http://getcaptchasolution.com/p9bwplkicx) API key. +To use this library you need [Anticaptcha.com](http://getcaptchasolution.com/p9bwplkicx) API key. You can pass the key explicitly or set the `ANTICAPTCHA_API_KEY` environment variable: @@ -34,6 +34,14 @@ client = AnticaptchaClient("my-api-key") client = AnticaptchaClient() ``` +The client can be used as a context manager to ensure the underlying session is closed: + +```python +with AnticaptchaClient(api_key) as client: + job = client.create_task(task) + job.join() +``` + ### Solve recaptcha Example snippet for Recaptcha: @@ -52,12 +60,11 @@ job.join() print(job.get_solution_response()) ``` -The full integration example is available in file `examples/recaptcha.py`. +The full integration example is available in file `examples/recaptcha_request.py`. -If you only process few page many times to increase reliability, you can specify -whether the captcha is visible or not. This parameter is not required, as is the -system detects invisible sitekeys automatically, and needs several recursive -measures for automated training and analysis. For provide that pass +If you process the same page many times, to increase reliability you can specify +whether the captcha is visible or not. This parameter is not required, as the +system detects invisible sitekeys automatically. To provide that, pass `is_invisible` parameter to `NoCaptchaTaskProxylessTask` or `NoCaptchaTask` eg.: ```python @@ -82,9 +89,17 @@ Example snippet for text captcha: from python_anticaptcha import AnticaptchaClient, ImageToTextTask api_key = '174faff8fbc769e94a5862391ecfd010' -captcha_fp = open('examples/captcha_ms.jpeg', 'rb') client = AnticaptchaClient(api_key) -task = ImageToTextTask(captcha_fp) + +# From a file path: +task = ImageToTextTask('examples/captcha_ms.jpeg') + +# Or from raw bytes: +# task = ImageToTextTask(open('examples/captcha_ms.jpeg', 'rb').read()) + +# Or from a file object: +# task = ImageToTextTask(open('examples/captcha_ms.jpeg', 'rb')) + job = client.create_task(task) job.join() print(job.get_captcha_text()) @@ -111,6 +126,18 @@ job.join() print(job.get_token_response()) ``` +### Monitor solve progress + +You can pass an `on_check` callback to `job.join()` to monitor progress: + +```python +def progress(elapsed, status): + print(f"Elapsed: {elapsed}s, status: {status}") + +job = client.create_task(task) +job.join(on_check=progress) +``` + ### Report incorrect image Example snippet for reporting an incorrect image task: @@ -138,7 +165,7 @@ pip install mitmproxy mitmweb -p 9190 -b 0.0.0.0 --ignore '.' --socks ``` -Next to in your application use something like: +Then in your application use something like: ```python proxy = Proxy.parse_url("socks5://123.123.123.123:9190") diff --git a/docs/conf.py b/docs/conf.py index aa39c12..dfe5b67 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,7 +4,7 @@ # # This file does only contain a selection of the most common options. For a # full list see the documentation: -# http://www.sphinx-doc.org/en/stable/config +# https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- @@ -21,13 +21,12 @@ # -- Project information ----------------------------------------------------- project = u"python-anticaptcha" -copyright = u"2018, Adam Dobrawy" +copyright = u"2018-2026, Adam Dobrawy" author = u"Adam Dobrawy" -# The short X.Y version +# Version is managed by setuptools-scm; leave empty for Sphinx version = u"" -# The full version, including alpha/beta/rc tags -release = u"0.2.0" +release = u"" # -- General configuration --------------------------------------------------- @@ -84,10 +83,9 @@ html_theme = "alabaster" try: - import sphinx_rtd_theme + import sphinx_rtd_theme # noqa: F401 html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] except ImportError: pass diff --git a/docs/development.rst b/docs/development.rst index ac3094c..e3a1680 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -5,7 +5,7 @@ The project is open-source. Changes are managed through GitHub. Pull requests are particularly welcome. -All changes are automatically tested using TravisCI. +All changes are automatically tested using GitHub Actions. New release ----------- @@ -13,7 +13,6 @@ New release Follow these steps to publish the new release: * update changelog - use any text editor -* bump version - use ```bumpversion {major,minor,patch}``` -* build package - use ```python setup.py sdist bdist_wheel --universal``` -* upload release to PyPI - use ```twine upload dist/*``` -* push changes to GitHub - ```git push origin && git push --tags``` +* tag version - use ``git tag vX.Y.Z`` (versions are managed by ``setuptools-scm``) +* push changes to GitHub - ``git push origin && git push --tags`` +* PyPI upload is handled automatically via GitHub Actions using `trusted publishing `_ diff --git a/docs/index.rst b/docs/index.rst index 422a2e1..81a0ced 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,7 +6,7 @@ Welcome to python-anticaptcha's documentation! ============================================== -Client library for solve captchas with `Anticaptcha.com support`_. +Client library for solving captchas with `Anticaptcha.com support`_. The library requires Python >= 3.9. The library is cyclically and automatically tested for proper operation. We are constantly making the best efforts for its effective operation. diff --git a/docs/usage.rst b/docs/usage.rst index 664ed88..633b1f1 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -1,7 +1,7 @@ Usage ===== -To use this library do you need `Anticaptcha.com`_ API key. +To use this library you need `Anticaptcha.com`_ API key. You can pass the key explicitly or set the ``ANTICAPTCHA_API_KEY`` environment variable: @@ -13,6 +13,14 @@ You can pass the key explicitly or set the ``ANTICAPTCHA_API_KEY`` environment v # Or set ANTICAPTCHA_API_KEY environment variable client = AnticaptchaClient() +The client can be used as a context manager to ensure the underlying session is closed: + +.. code:: python + + with AnticaptchaClient(api_key) as client: + job = client.create_task(task) + job.join() + Solve recaptcha ############### @@ -32,12 +40,11 @@ Example snippet for Recaptcha: job.join() print(job.get_solution_response()) -The full integration example is available in file ``examples/recaptcha.py``. +The full integration example is available in file ``examples/recaptcha_request.py``. -If you only process few page many times to increase reliability, you can specify -whether the captcha is visible or not. This parameter is not required, as is the -system detects invisible sitekeys automatically, and needs several recursive -measures for automated training and analysis. For provide that pass +If you process the same page many times, to increase reliability you can specify +whether the captcha is visible or not. This parameter is not required, as the +system detects invisible sitekeys automatically. To provide that, pass ``is_invisible`` parameter to ``NoCaptchaTaskProxylessTask`` or ``NoCaptchaTask`` eg.: .. code:: python @@ -65,9 +72,17 @@ Example snippet for text captcha: from python_anticaptcha import AnticaptchaClient, ImageToTextTask api_key = '174faff8fbc769e94a5862391ecfd010' - captcha_fp = open('examples/captcha_ms.jpeg', 'rb') client = AnticaptchaClient(api_key) - task = ImageToTextTask(captcha_fp) + + # From a file path: + task = ImageToTextTask('examples/captcha_ms.jpeg') + + # Or from raw bytes: + # task = ImageToTextTask(open('examples/captcha_ms.jpeg', 'rb').read()) + + # Or from a file object: + # task = ImageToTextTask(open('examples/captcha_ms.jpeg', 'rb')) + job = client.create_task(task) job.join() print(job.get_captcha_text()) @@ -94,6 +109,19 @@ Example snippet for funcaptcha: job.join() print(job.get_token_response()) +Monitor solve progress +###################### + +You can pass an ``on_check`` callback to ``job.join()`` to monitor progress: + +.. code:: python + + def progress(elapsed, status): + print(f"Elapsed: {elapsed}s, status: {status}") + + job = client.create_task(task) + job.join(on_check=progress) + Report incorrect image ###################### @@ -123,7 +151,7 @@ the possibility of simply launching such a server by: pip install mitmproxy mitmweb -p 9190 -b 0.0.0.0 --ignore '.' --socks -Next to in your application use something like: +Then in your application use something like: .. code:: python