{"id":24967,"date":"2026-08-06T10:16:59","date_gmt":"2026-08-06T10:16:59","guid":{"rendered":"https:\/\/capskip.com\/?p=24967"},"modified":"2026-08-06T10:16:59","modified_gmt":"2026-08-06T10:16:59","slug":"recaptcha-v2-python","status":"publish","type":"post","link":"https:\/\/capskip.com\/zh\/recaptcha-v2-python\/","title":{"rendered":"\u5982\u4f55\u7528 CapSkip SDK \u5728 Python \u4e2d\u8bc6\u522b reCAPTCHA v2"},"content":{"rendered":"<p>reCAPTCHA v2 has three variants, and in Python they are one function with different keyword arguments. Checkbox is the bare call, Invisible and Enterprise are flags, and both can be set at once. Python is also the only CapSkip SDK with a genuinely separate async client, which matters as soon as you are solving more than one at a time.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Setup<\/h2>\n<pre data-enlighter-language=\"bash\" class=\"EnlighterJSRAW\"># Python 3.10 or newer.\npip install capskip<\/pre>\n<p>CapSkip solves locally, so start the desktop app first, then point the client at the port from its settings:<\/p>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">from capskip import CapSkip\n\nsolver = CapSkip(\n    apiKey=&quot;capskip&quot;,        # any string when key validation is off\n    host=&quot;127.0.0.1&quot;,\n    port=8080,\n    recaptchaTimeout=300,    # seconds\n)<\/pre>\n<p>In production, read those from the environment instead:<\/p>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">import os\nfrom capskip import CapSkip\n\nsolver = CapSkip(\n    apiKey=os.getenv(&quot;CAPSKIP_API_KEY&quot;, &quot;capskip&quot;),\n    host=os.getenv(&quot;CAPSKIP_HOST&quot;, &quot;127.0.0.1&quot;),\n    port=int(os.getenv(&quot;CAPSKIP_PORT&quot;, &quot;8080&quot;)),\n)<\/pre>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">The three variants<\/h2>\n<table>\n<thead>\n<tr>\n<th>Variant<\/th>\n<th>Keyword to add<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Checkbox<\/td>\n<td>none<\/td>\n<\/tr>\n<tr>\n<td>Invisible<\/td>\n<td><code>invisible=1<\/code><\/td>\n<\/tr>\n<tr>\n<td>Enterprise<\/td>\n<td><code>enterprise=1<\/code><\/td>\n<\/tr>\n<tr>\n<td>Invisible Enterprise<\/td>\n<td>both<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\"># Checkbox: the baseline call.\nresult = solver.recaptcha(\n    sitekey=&quot;6Lc...YOUR_SITEKEY&quot;,\n    url=&quot;https:\/\/example.com\/login&quot;,\n)\n\nprint(result[&quot;code&quot;])   # g-recaptcha-response token\n\n# Invisible.\nresult = solver.recaptcha(sitekey=sitekey, url=page_url, invisible=1)\n\n# Enterprise, and both together.\nresult = solver.recaptcha(sitekey=sitekey, url=page_url, enterprise=1)\nresult = solver.recaptcha(sitekey=sitekey, url=page_url, enterprise=1, invisible=1)<\/pre>\n<p>The return value is a plain dict, so <code>result[\"code\"]<\/code> is the token. There is also <code>result[\"captchaId\"]<\/code> if you want to log which internal solve produced it.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Getting the sitekey and URL right<\/h2>\n<p>The sitekey is the <code>data-sitekey<\/code> attribute on the widget container, or the first argument to <code>grecaptcha.render<\/code> when there is no container. It always begins with <code>6L<\/code> and is public.<\/p>\n<p>The URL has to be the page the widget renders on. Passing your form handler or a post-login redirect is the most common cause of a token that solves fine and then fails validation.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Submitting the token<\/h2>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">import requests\n\nresponse = requests.post(\n    &quot;https:\/\/example.com\/login&quot;,\n    data={\n        &quot;g-recaptcha-response&quot;: result[&quot;code&quot;],\n        &quot;username&quot;: &quot;...&quot;,\n        &quot;password&quot;: &quot;...&quot;,\n    },\n)<\/pre>\n<p>Tokens last around two minutes and are single use, so solve as late in the flow as you can. If the site hands the token to a JavaScript callback instead of a form field, the solve is identical but submission differs, which our <a href=\"https:\/\/capskip.com\/recaptcha-v2-callback-solver\/\">reCAPTCHA v2 callback solver<\/a> page covers.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Solving several at once<\/h2>\n<p>This is where Python differs from the other CapSkip SDKs. <code>AsyncCapSkip<\/code> is a real async implementation, not an alias, so it genuinely overlaps solves:<\/p>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">import asyncio\nfrom capskip import AsyncCapSkip\n\nasync def main():\n    solver = AsyncCapSkip()\n    r1, r2 = await asyncio.gather(\n        solver.recaptcha(sitekey=key_a, url=&quot;https:\/\/a.example.com&quot;),\n        solver.recaptcha(sitekey=key_b, url=&quot;https:\/\/b.example.com&quot;),\n    )\n    print(r1[&quot;code&quot;], r2[&quot;code&quot;])\n\nasyncio.run(main())<\/pre>\n<p>In the Node.js and .NET SDKs <code>AsyncCapSkip<\/code> is only an alias, and in PHP it is there purely so ported code compiles. Python is the one where switching to it actually changes behaviour.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Errors<\/h2>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">from capskip import (\n    CapSkip, ValidationException, NetworkException,\n    ApiException, TimeoutException,\n)\n\ntry:\n    result = solver.recaptcha(sitekey=sitekey, url=page_url)\nexcept ValidationException:\n    pass   # missing or malformed arguments\nexcept NetworkException:\n    pass   # CapSkip is not running\nexcept ApiException:\n    pass   # bad sitekey or pageurl\nexcept TimeoutException:\n    pass   # exceeded recaptchaTimeout<\/pre>\n<p>All four derive from a common base, so <code>except CapSkipError<\/code> catches everything if you would rather handle failures in one place.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Using a proxy<\/h2>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">result = solver.recaptcha(\n    sitekey=sitekey,\n    url=page_url,\n    proxy={&quot;type&quot;: &quot;HTTPS&quot;, &quot;uri&quot;: &quot;user:pass@1.2.3.4:3128&quot;},\n)<\/pre>\n<p>Proxies work for reCAPTCHA, Turnstile and GeeTest. They are not supported for image CAPTCHAs, which are solved from the image bytes and never reach the target site.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Frequently asked questions<\/h2>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">Do I need to poll for the result?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">No. The SDK polls internally and returns the finished token, so <code>CAPCHA_NOT_READY<\/code> never reaches your code. It starts checking after 250ms and backs off, which usually beats a hand-written loop.<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">Is AsyncCapSkip worth using for a single solve?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">Not really. It matters when several solves overlap, or when you are already inside an event loop and a blocking call would stall it. For one solve in a script the sync client is simpler.<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">Which Python versions are supported?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">3.10 and newer. The package has no heavy dependencies, so it drops into an existing scraping or automation project without pulling a tree of extras.<\/p>\n<\/details>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Summary<\/h2>\n<p>One function, three variants, selected with <code>invisible<\/code> and <code>enterprise<\/code>. Read <code>result[\"code\"]<\/code>, submit it as <code>g-recaptcha-response<\/code>, and reach for <code>AsyncCapSkip<\/code> when you are solving in bulk.<\/p>\n<p>The wider Python surface is on the <a href=\"https:\/\/capskip.com\/python-captcha-solver\/\">Python CAPTCHA solver<\/a> page, other languages on the <a href=\"https:\/\/capskip.com\/recaptcha-v2-solver\/\">reCAPTCHA v2 solver<\/a> page, and there is a <a href=\"https:\/\/capskip.com\/captcha-demo\/recaptcha-v2\/\">live v2 demo<\/a> to test against. CapSkip is a <a href=\"https:\/\/capskip.com\/\">captcha solver<\/a> that runs on your own machine.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u590d\u9009\u6846\u3001\u9690\u5f62\u4e0e Enterprise \u5728 Python \u4e2d\u662f\u540c\u4e00\u4e2a\u8c03\u7528\u3001\u4e0d\u540c\u5173\u952e\u5b57\u3002\u8fd9\u91cc\u7ed9\u51fa\u6bcf\u4e00\u79cd\uff0c\u4ee5\u53ca AsyncCapSkip \u4e0e\u540c\u6b65\u5ba2\u6237\u7aef\u7684\u533a\u522b\u3002<\/p>","protected":false},"author":1,"featured_media":24966,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Solve reCAPTCHA v2 in Python | CapSkip","rank_math_description":"One call covers reCAPTCHA v2 checkbox, Invisible and Enterprise in Python. Here is the keyword each variant needs, plus the async client for bulk work.","rank_math_focus_keyword":"solve recaptcha v2 in python","footnotes":""},"categories":[71],"tags":[],"class_list":["post-24967","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-google-recaptcha"],"_links":{"self":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/24967","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/comments?post=24967"}],"version-history":[{"count":1,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/24967\/revisions"}],"predecessor-version":[{"id":24989,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/24967\/revisions\/24989"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/media\/24966"}],"wp:attachment":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/media?parent=24967"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/categories?post=24967"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/tags?post=24967"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}