Skip to main content

wulu-geetest-bypass

GitHub Actions Workflow Status Python License Geetest v4 downloads

English | 简体中文

A lightweight, pure Python library to automatically solve Geetest Behavioral CAPTCHA v4 without Node.js or headless browsers. Features dynamic mouse trajectory simulation, 7 built-in risk type solvers, accessible voice bypass, and an extensible custom solver registry.

✨ Features

  • 🚀 Pure Python 3.11+ — Zero Node.js, headless browsers, or external runtime dependencies required.
  • 🛡️ Multi-Risk Type Support — Out-of-the-box solvers for 7 risk types (see full table).
  • 🎯 Human-like Track Simulation — Dynamically generated mouse trajectories for every run (no fixed replays).
  • 🔁 Smart Auto-Retry — One-call resolve() automatically retries up to 3 times on transient failures.
  • 🕹️ Granular Step-by-Step Flow — Separate load() and verify() steps for intercepting payloads and tokens.
  • ♿ Accessible Voice Bypass — Seamlessly switch to offline speech recognition when the voice channel is enabled.
  • 🔌 Extensible Solver Registry — Easily plug in custom OCR / Vision models, or override built-in solvers.
  • 🌐 Advanced Networking — Native support for proxy chains, browser TLS fingerprint emulation, and custom headers.

🧩 Supported Risk Types

Type Description Dependency Support
ai Silent verification none ✅
slide Slider puzzle [slide] ✅
match 3×3 connect none ✅
winlinze Gomoku none ✅
svg_seed SVG 3x3 image selection [svg] ✅
svg_icon SVG 2x2 icon selection [svg] ✅
voice Voice verification [voice] ✅
icon Icon click none ❌
word Word click none ❌
nine Nine-grid none ❌
phrase Phrase recognition none ❌
pencil Doodle none ❌
space Spatial reasoning none ❌

The Dependency column refers to the dependency groups below. Types marked ❌ have no built-in solver — register your own via custom solvers.

📦 Installation

uv is recommended (faster, more modern Python package manager):

uv add "wulu-geetest-bypass[all]"

You can also use pip:

pip install "wulu-geetest-bypass[all]"

Dependency groups (install only what you need):

# voice verification
uv add "wulu-geetest-bypass[voice]"

# slide puzzle (requires opencv)
uv add "wulu-geetest-bypass[slide]"

# SVG icon & seed selection
uv add "wulu-geetest-bypass[svg]"

# Install everything
uv add "wulu-geetest-bypass[all]"

🚀 Quick Start

import asyncio
from wulu_geetest_bypass import Geetest


async def main():
    g = Geetest(captcha_id='your_captcha_id', risk_type='slide')
    result = await g.resolve()
    print(result)
    # {
    #     "captcha_id": "xxx",
    #     "lot_number": "xxx",
    #     "pass_token": "xxx",
    #     "gen_time": "xxx",
    #     "captcha_output": "xxx"
    # }


asyncio.run(main())

That is all you need for the common case. See Advanced Usage for retry control, the step-by-step flow, voice mode, custom solvers, and HTTP configuration.

💡 Advanced Usage

Automatic retry and one-call resolve()

resolve() is load() + verify() in one call, with automatic retry on failure:

g = Geetest(captcha_id='your_captcha_id', risk_type='slide')
result = await g.resolve()  # default: up to 3 attempts
result = await g.resolve(retry=5)  # override the attempt count

On the final failure it raises VerifyError instead of returning a partial result.

Step-by-step flow: load() → verify()

When you need to intervene between the two stages (log, inspect the payload, run your own recognition), call them separately:

g = Geetest(captcha_id='your_captcha_id', risk_type='slide')
data = (
    await g.load()
)  # init data: captcha_type, lot_number, payload, process_token, pow_detail, ...
response = await g.verify(data)  # full response: status + data

load() returns a dict whose fields can be passed directly into verify(). The return types are listed under Data Models.

Accessible (voice) mode

Some Geetest v4 sites enable the voice channel (accessible mode) server-side. When a site supports it, regardless of the original risk type, you can force voice verification via voice=True, bypassing the original slider / click behavioral checks:

# Originally a slide verification, but the site supports accessible mode
g = Geetest(captcha_id='your_captcha_id', risk_type='slide', voice=True)
result = await g.resolve()

The flow becomes: load voice captcha → download audio → recognize digits offline → submit verification. No browser environment or image recognition needed.

Note: Not all sites enable the accessible channel. If unsupported, the show_voice field in load() returns false, and setting voice=True has no effect — the original risk_type is still used.

Register custom solvers

For risk types without built-in support, inject a custom solver via register_solver:

from wulu_geetest_bypass import Geetest


def solve_icon(imgs: bytes, ques: list[bytes]) -> list[tuple[float, float]]: ...


Geetest.register_solver('icon', solve_icon)

Once registered, generate_w() calls it automatically with the corresponding payload fields. Click/draw solvers return normalized coordinates in [0, 1] relative to the verification image — the library takes care of scaling them to the window/payload formats (e.g. userresponse uses image-based percent × 10000) and of generating the click tracks (including the final submit-button click for icon/word/phrase):

Type Solver signature
icon / word (imgs: bytes, ques: list[bytes]) -> list[tuple[float, float]]
phrase (imgs: bytes) -> list[tuple[float, float]]
nine (imgs: bytes, ques: list[bytes], nine_nums: int) -> list[tuple[int, int]]
pencil (imgs: bytes) -> list
space Not built-in separately; Geetest routes space to svg_icon (solved by the SVG solver)

Built-in solvers can also be overridden, either by passing the solver directly or as a decorator:

Geetest.register_solver('slide', my_custom_slide_solver)
@Geetest.register_solver('slide')
def my_custom_slide_solver(bg, slice, ypos): ...

Proxy and HTTP client configuration

Geetest forwards all HTTP concerns to wreq, so proxies, custom headers, and client emulation are configured once at construction time. Pass a ClientConfig via client_options, or an already-constructed client via client (which takes priority):

from wreq import Client, ClientConfig

config = ClientConfig(...)  # proxy chains, headers, emulation, timeouts, ...

g = Geetest(captcha_id='your_captcha_id', risk_type='slide', client_options=config)
# equivalent, when you need to build the client yourself first:
g = Geetest(captcha_id='your_captcha_id', risk_type='slide', client=Client(config))

📖 API Reference

Configuration — Geetest(**options)

Parameter Type Description
captcha_id str Verification ID (required)
risk_type RiskType Risk type, default 'ai'
client_type ClientType Client type, 'web' / 'web_mobile' / 'android' / 'ios'
lang Lang Language, 'zho' / 'eng' / 'fra' / 'deu' and 13 more
challenge str Custom challenge (auto-generated if omitted)
user_info Any Extra user info (reserved)
voice bool Enable accessible voice verification (requires [voice])
client_options wreq.ClientConfig HTTP client config (proxy, headers, emulation, etc.)
client wreq.Client | None Custom HTTP client (takes priority over client_options)

Data models

load() -> dict returns init data containing captcha_type, lot_number, payload, process_token, pow_detail and other fields, passable directly into verify().

verify(data) -> VerifyResponse:

class VerifyResponse:
    status: str  # "success" / "error"
    data: VerifyData  # VerifyDataSuccess | VerifyDataFail, discriminated by `result`


class VerifyDataSuccess:  # result == "success"
    lot_number: str
    result: str
    fail_count: int
    seccode: Seccode  # success only
    score: str
    payload: str
    process_token: str
    payload_protocol: int


class VerifyDataFail:  # result == "fail" / "forbidden" / "continue" — no seccode
    lot_number: str
    result: str
    fail_count: int
    score: str
    payload: str
    process_token: str
    payload_protocol: int

resolve(retry=3) -> Seccode:

class Seccode:
    captcha_id: str
    lot_number: str
    pass_token: str
    gen_time: str
    captcha_output: str
Parameter Type Description
retry int Retries on fail, default 3; forbidden raises at once

Exceptions

Exception Description
GeetestError Base class of all custom exceptions
VerifyError /verify did not return success; carries .result / .fail_count

VerifyError.result is the raw server value: fail (scored and rejected — wrong answer, bad headers or low risk score; retryable), forbidden (rejected before scoring — an IP-level rate limit, not an answer problem; back off or change the exit IP) or continue (another round of the same challenge is wanted, match only).

⚖️ Disclaimer

This project is for learning and research purposes only. Users should comply with applicable laws and platform terms of service; any illegal use is prohibited. The author assumes no responsibility for any legal issues arising from the use of this project.

🤝 Support & Updates

  • This project continuously tracks Geetest v4 behavioral verification changes and updates the bypass logic and solvers promptly.
  • Please open an Issue if you encounter problems, and PRs are welcome.
  • If this project helps you, feel free to give it a ⭐ Star to encourage continued development.

📄 License

Released under the MIT License — see LICENSE.

Metadata

Release files for wulu-geetest-bypass 0.4.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wulu-geetest-bypass 0.4.3
File Size Uploaded
wulu_geetest_bypass-0.4.3.tar.gz 156.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wulu-geetest-bypass 0.4.3
File Interpreter ABI Platform
wulu_geetest_bypass-0.4.3-py3-none-any.whl Python 3 none any Details

Total release size: 190.4 kB

Release files / wulu_geetest_bypass-0.4.3.tar.gz

Download URL wulu_geetest_bypass-0.4.3.tar.gz
Size 156.2 kB
Tags Source
SHA-256 checksum
How to use checksums
dd467c7ae6a8d94bf7ce57c3c3c8300054301b47b3f8da1938d7c0c2a82371b3
BLAKE2b-256 checksum
How to use checksums
cb6d9c0f53e290d5e367b7e12fd7b9e581bf429349f0a9d4abcba65f00069584
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / wulu_geetest_bypass-0.4.3-py3-none-any.whl

Download URL wulu_geetest_bypass-0.4.3-py3-none-any.whl
Size 34.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c79f440196a1d5f8b41e238ee8f17bb66b765c349bbedad5d18d9b45d1769c7a
BLAKE2b-256 checksum
How to use checksums
8253b48f7875229cd263058669b8f5858273a129bbe93dea803a38df19d43b03
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.4.3 This release

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page