Async Python’da CapSkip ile Pydoll CAPTCHA Nasıl Çözülür

Pydoll ile CAPTCHA çözmek için sitekey’i sayfadan okuyun, aynı asyncio olay döngüsünde CapSkip’in AsyncCapSkip istemcisiyle çözün, token’ı g-recaptcha-response kutusuna yazın ve sayfanın callback’ini çalıştırın ya da formu gönderin. Pydoll 3.0’da kendi reCAPTCHA kodu yoktur, bu yüzden token bir çözücüden gelmek zorundadır. CapSkip kendi Windows bilgisayarınızda çalışır, dolayısıyla çok sayıda sayfa açan bir taramanın çözüm başına maliyeti yoktur. Bu rehber, Pydoll CAPTCHA akışının tamamını yaklaşık 80 satırda oluşturur ve Windows’ta zaman kaybettiren tuzakları kapsar.
Neye ihtiyacınız var
- reCAPTCHA çözücüsü açık hâlde bir Windows bilgisayarında çalışan CapSkip. İlk başlatmayı kurulum kılavuzu adım adım anlatıyor.
- Python 3.10 veya üzeri. Pydoll 3.0.0 da capskip 1.3.0 paketi de bunu gerektirir. Aşağıdaki her şey Windows 11 üzerinde Python 3.14.0 ile çalıştırıldı, tam betik ayrıca Python 3.11.7 üzerinde de çalıştı. Python 3.10, 3.12 ve 3.13 denenmedi.
- Varsayılan Program Files klasörüne kurulu Google Chrome. Rehberde Chrome 155 kullanıldı, tam betik ayrıca Chrome for Testing 146 ile de çalıştı.
- Bir PowerShell istemi. Komutlar PowerShell sözdizimini kullanır.
- Sahibi olduğunuz, reCAPTCHA v2 onay kutusu bulunan bir sayfa. Örnek form sade bir kayıt formudur. Seçicileri kendi sayfanıza uyacak şekilde değiştirin.
- Çözücü için bir adres. Local modunda CapSkip yalnızca o cihaz için 127.0.0.1 üzerinden yanıt verir. Server modunda ağ adresinizi veya genel IP’nizi dinler, böylece başka bir bilgisayardaki, bir VPS’teki ya da barındırılan bir platformdaki Pydoll onu API üzerinden çağırabilir. İkisi de şurada ayarlanır: bağlantı ayarları.
Aşağıdaki ölçümler, aynı bilgisayardaki sahte (mock) bir CapSkip ve sahte bir kayıt sayfasından alındı; gerçek Pydoll, gerçek SDK, gerçek bir Chrome ve Google’ın gerçek api.js betiğiyle birlikte kullanıldılar. Tarayıcı ve SDK davranışı sizin kendi siteniz için de geçerlidir. Çözüm süreleri ile sayfanın kabul ve ret kuralları mock’un kendisine aittir. Çalışan bir CapSkip’e karşı, Google’ın herkese açık test sitekey’i ve varsayılan ayarlar kullanılarak yapılan bir çözüm 9,0 saniye sürdü ve 1.764 karakterlik bir token döndürdü. Çözüm süreleri çalıştırmadan çalıştırmaya değişir. O token hiçbir yerde kullanılmadı ve hiçbir canlı site denenmedi.
Pydoll nerede biter, CapSkip nerede başlar
Pydoll, araya WebDriver girmeden Chrome’u DevTools protokolü üzerinden sürer. Size tarayıcıyı, sayfanın elementlerini ve JavaScript çalıştırma yolunu verir. 3.0.0 sürümündeki tek CAPTCHA kodu, Cloudflare Turnstile onay kutusu için bir yardımcıdır. Bu yardımcı onay kutusunu bulur ve tıklar. Hiçbir zaman token okumaz ve hiçbir şey olmadığında hata da vermez. reCAPTCHA’yı ele alan hiçbir kod yoktur. reCAPTCHA v2 onay kutusunu bir token döndüren bir servis çözer ve sayfanın o token’a doğru yerde ihtiyacı vardır. CapSkip’in burada yaptığı iş budur ve bu rehberin geri kalanı bağlayıcı koddur.
1. Adım: projeyi oluşturun
Boş bir klasörde bir sanal ortam kullanın. Komutlar ortamın kendi Python’unu yoluyla çalıştırır, bu yüzden onu etkinleştirmeniz gerekmez ve kısıtlı bir PowerShell betik ilkesi de engel olmaz. Aşağıdaki her betiği ortamın Python’uyla çalıştırın, örneğin .\.venv\Scripts\python.exe solve.py. 2.27.0 gibi eski bir Pydoll kurulumu, aşağıdaki betiğin ilk import satırında ImportError: cannot import name ‘Chrome’ from ‘pydoll’ hatasıyla başarısız olur. Pydoll 3.0, Chrome’u en üst düzeyden dışa aktarır.
# Windows PowerShell, in an empty folder python -m venv .venv .\.venv\Scripts\python.exe -m pip install pydoll-python capskip
Adım 2: Chrome’u başlatın ve sayfayı açın
Bunu solve.py olarak kaydedin. Sayfanızı açıp başlığını yazdıran en küçük Pydoll betiğidir. Tarayıcı bir async with bloğunun içinde başlar, bu yüzden blok bittiğinde yeniden kapanır.
# pip install pydoll-python capskip
import asyncio
from pydoll import Chrome
from pydoll.browser.options import ChromiumOptions
PAGE = 'https://example.com/page-with-recaptcha'
async def main():
options = ChromiumOptions()
options.headless = True # set to False to watch the window
async with Chrome(options=options) as browser:
tab = await browser.start()
await tab.go_to(PAGE)
print(await tab.title())
asyncio.run(main())Pydoll Chrome’u yalnızca iki yerde arar: Google, Chrome, Application altında Program Files ve Program Files (x86). Tek bir kullanıcı için AppData altına kurulmuş bir Chrome bulunamaz ve betik InvalidBrowserPath ile durur. Düzeltmek için options.binary_location değerini chrome.exe dosyasının tam yoluna ayarlayın. Var olmayan bir yol bunun yerine FailedToStartBrowser ile başarısız olur. Aynı satır Pydoll’u Chrome for Testing’e de yöneltir ve bu da çalıştı. Pydoll tarayıcı sürümlerini hiçbir şeyle eşleştirmez, bu yüzden 146 ve 155 ikisi de çalıştı.
Windows’ta başlatma beklediğinizden yavaştır. Test bilgisayarında, varsayılan ayarlarla ve headless Chrome 155 ile browser.start() 2,8 saniye sürdü. İlk go_to, dışarıdan betik yüklemeyen bir sayfada 2,1 saniye daha, Google’ın betiğini yükleyen kayıt sayfasında ise yaklaşık 3,1 saniye sürdü. Pydoll localhost’a bağlanır ve localhost önce IPv6 adresini dener. Chrome’un hata ayıklama portu IPv6 üzerinde dinlemez ve Windows bir loopback bağlantısını reddetmek için yaklaşık 2 saniye harcar; bu yüzden Chrome’a açılan her yeni bağlantı, IPv4 olanı çalışmadan önce yaklaşık 2 saniye öder. Bu, tarayıcı ve açtığınız her ek sekme demektir. Pydoll’da bunun için bir ayar yoktur. Python sürecinin içinde localhost adının 127.0.0.1’e çözümlenmesini sağlamak bir testte gecikmeyi ortadan kaldırır, ama standart kütüphaneyi yamalar; bu yüzden bu rehber ona dokunmaz. Bir çalıştırmayı ölçerken bunu hesaba katın.
with bloğu Chrome’u normal çıkışta, içindeki bir istisnadan sonra ve iptal edilmiş bir görevden sonra kapatır ve geçici profil klasörünü kaldırır. Python sürecini taskkill /F ile sonlandırmak bunu atlar. Testte 13 chrome.exe süreci çalışır durumda ve profil klasörü diskte kaldı. Bir konsolda Ctrl+C denenmedi. Bir çalıştırmayı sonlandırdıysanız, bir sonrakini başlatmadan önce Task Manager’da chrome.exe süreçlerine bakın.
Adım 3: CapSkip’in yanıt verdiğini kontrol edin
Bir tarayıcı eklemeden önce çözücü çağrısının tek başına çalıştığını doğrulayın. Bunu first_solve.py olarak kaydedin. AsyncCapSkip, aynı paketteki async istemcidir. SDK hiçbir ortam değişkenini okumaz, bu yüzden host ve port istemcinin içine yazılır. Yer tutucular gerçek değer değildir: YOUR_SITEKEY ve sayfa adresi, gerçekten bir reCAPTCHA v2 widget’ı taşıyan bir sayfadan gelmelidir, aksi halde CapSkip bir hatayla yanıt verir. Sitekey’i sayfa kaynağından kopyalayın; orada data-sitekey değeridir. Adım 4 onu sizin için sayfadan okur. Dosyayı .\.venv\Scripts\python.exe first_solve.py ile çalıştırın.
# pip install capskip
import asyncio
from capskip import AsyncCapSkip
async def main():
solver = AsyncCapSkip(host='127.0.0.1', port=8080)
result = await solver.recaptcha(
sitekey='YOUR_SITEKEY',
url='https://example.com/page-with-recaptcha',
)
print(result['code'][:30])
asyncio.run(main())Adım 4: sitekey’i sayfadan okuyun
Sitekey sayfadadır ve Pydoll onu okuyabilir. Normal bir widget, g-recaptcha sınıfına ve data-sitekey özniteliğine sahip bir div’dir. Sayfanın grecaptcha.render() ile çizdiği bir widget’ta böyle bir div yoktur. Onun yerine, adresinin k parametresinde sitekey’i taşıyan bir iframe bırakır. Bu fonksiyon ikisini de tek bir seçiciyle ele alır ve etiket adı hangisini aldığını söyler. Onu solve.py içinde async def main() satırının üstüne ekleyin.
from urllib.parse import parse_qs, urlparse
async def find_sitekey(tab):
# A normal widget carries data-sitekey. A widget drawn by
# grecaptcha.render() only leaves its iframe, with k=<sitekey>.
found = await tab.query(
'.g-recaptcha[data-sitekey], '
'iframe[src*="recaptcha/api2/anchor"]',
timeout=10,
)
if found.tag_name == 'iframe':
src = found.get_attribute('src')
return parse_qs(urlparse(src).query)['k'][0]
return found.get_attribute('data-sitekey')Burada iki Pydoll ayrıntısı önemlidir. get_attribute bir coroutine değil, düz bir fonksiyondur, bu yüzden await etmeyin; olmayan bir öznitelik için None döndürür. Ayrıca query hiçbir şey eşleşmediğinde ElementNotFound fırlatır. Bir zaman aşımıyla birlikte bekler ve bunun yerine WaitElementTimeout fırlatır; bu da sayfa yüklendikten kısa süre sonra beliren bir widget için doğru seçimdir. Yüklemeden 3 saniye sonra enjekte edilen bir widget, find_sitekey içindeki 10 saniyelik zaman aşımıyla yaklaşık 3 saniye sonra bulundu.
Adım 5: aynı olay döngüsünde çözün
Pydoll asyncio üzerinde çalışır ve çözüm çağrınız aynı döngüde çalışır. Bu, istemci seçimini önemli kılar. Bunu da async def main() satırının üstüne ekleyin ve Adım 6’daki fonksiyon için de aynısını yapın.
from capskip import AsyncCapSkip
solver = AsyncCapSkip(host='127.0.0.1', port=8080)
async def solve(sitekey, url):
result = await solver.recaptcha(sitekey, url)
return result['code']Senkron CapSkip istemcisi de çalışırdı, ama tüm çözüm boyunca döngüyü bloke eder ve Pydoll beklerken Chrome’a yanıt vermeyi bırakır. Bir mock çalıştırması, 3 saniyelik bir mock çözüm sürerken sayfanın, 50 milisaniyede bir zaman sorulduğunda ne sıklıkla yanıt verdiğini saydı. En uzun boşluk, iki yanıt arasındaki en uzun süredir:
| İstemci | Çözüm süresi | Sayaç tikleri | En uzun boşluk |
|---|---|---|---|
| Senkron CapSkip istemcisi, async fonksiyonun içinde doğrudan çağrıldı | 3.76 s | 5 | 3.78 s |
| asyncio.to_thread içinde CapSkip | 3.76 s | 65 | 0.06 s |
| AsyncCapSkip | 5.0 s | 68 | 0.3 s |
Sayfanın kendisi ilk durumda çalışmaya devam etti. Yalnızca Python tarafı dondu: Python, çözüm bitene kadar sayfanın yaptığı hiçbir şeye tepki veremez, bu yüzden ikinci bir sekmedeki olaylar geç işlenir. AsyncCapSkip burada yaklaşık bir saniye daha uzun sürdü, ama bu, çözümden sonra bir sonraki yoklamasının nereye düştüğüne bağlıdır ve 2, 4 ve 8 saniyelik mock çözümlerle thread sürümünden daha erken bitti. Her zaman maliyeti ise her istek için yaklaşık 0,15 saniyelik bloke olmuş döngüdür, çünkü her seferinde yeni bir HTTP istemcisi kurar. Bu, yine de donmuş bir döngüden iyidir.
Adım 6: token’ı sayfaya yazın
Çözülmüş bir reCAPTCHA bir token’dır. Sayfa onu g-recaptcha-response adlı bir textarea içinde bekler ve widget’ın bir callback’i varsa, callback’in token ile çalışmasını bekler. Bu fonksiyon ikisini de yapar. Pydoll’un execute_script fonksiyonunu kullanır ve bir callback bulup çalıştırdıysa True döndürür. Onu da async def main() satırının üstüne ekleyin.
import json
FILL_JS = """
(function (token) {
var seen = new Set(), fn = null;
document.querySelectorAll('textarea[name="g-recaptcha-response"]')
.forEach(function (box) { box.value = token; });
(function walk(o, depth) {
if (!o || typeof o !== 'object' || seen.has(o) || depth > 6) return;
seen.add(o);
for (var k in o) {
var v; try { v = o[k]; } catch (e) { continue; }
if (k === 'callback' && !fn) {
fn = typeof v === 'string' ? window[v] : v;
}
if (v && typeof v === 'object' && !(v instanceof Node)) {
walk(v, depth + 1);
}
}
})(window.___grecaptcha_cfg, 0);
if (typeof fn === 'function') fn(token);
return typeof fn === 'function';
})(%s)
"""
async def fill_token(tab, token):
reply = await tab.execute_script(
FILL_JS % json.dumps(token), return_by_value=True)
outcome = reply['result']
if 'exceptionDetails' in outcome:
error = outcome['exceptionDetails']['exception']
raise RuntimeError(error['description'])
return outcome['result']['value'] # True if a callback ranJavaScript, callback’i bulmak için Google’ın kendi yapılandırma nesnesini dolaşır, çünkü içindeki anahtarlar Google’ın değiştirebileceği kısa adlardır. Bir data-callback özniteliği orada bir fonksiyonun adı olarak saklanır, bu yüzden dolaşma adı window üzerinde arar. grecaptcha.render() fonksiyonuna verilen bir callback ise fonksiyonun kendisi olarak saklanır. Her iki durum da Google’ın gerçek api.js dosyasına karşı çalıştı.
Pydoll, execute_script’ten ham DevTools yanıtını döndürür; bu yüzden değer reply[‘result’][‘result’][‘value’] konumunda durur ve çağrıyı await etmelisiniz. return_by_value=True vermezseniz bir nesne referans olarak gelir. Bir JavaScript hatası Python’da fırlatılmaz. Yanıta exceptionDetails ekler; fonksiyonun onu kontrol etmesi ve kendi RuntimeError hatasını fırlatması bu yüzdendir.
Adım 7: hepsini birleştirin
solve.py dosyasının en altındaki async def main() ve asyncio.run(main()) satırlarını silin, üstlerindeki fonksiyonları tutun ve bunun yerine şunu yapıştırın. Sayfa yüklendikten sonra çözer, çünkü sitekey sayfadan gelir ve token kullanılmadan hemen önce çözer. Bir callback çalıştıysa sayfa devralır. Çalışmadıysa betik formun gönder düğmesine tıklar ve gezinmeyi bekler.
async def main():
options = ChromiumOptions()
options.headless = True # set to False to watch the window
async with Chrome(options=options) as browser:
tab = await browser.start()
await tab.go_to(PAGE)
sitekey = await find_sitekey(tab)
token = await solve(sitekey, await tab.current_url())
if not await fill_token(tab, token):
button = await tab.query('form button[type="submit"]')
async with tab.expect_navigation():
await button.click()
print(await tab.title())
asyncio.run(main())Göndermeyi bir callback’in yaptığı bir sayfada tıklanacak bir şey yoktur. Bu sürüm main() fonksiyonunu aynı şekilde değiştirir. Sonra ne olacağı sayfaya bağlıdır, bu yüzden sayfanın kendisinin değiştirdiği bir şeyi bekleyin. Bu sürüm, test sayfasındaki bir sonuç elementinin waiting değerinden başka bir değere değişmesini bekler. Seçiciyi sayfanızın güncellediği şeye göre değiştirin.
async def main():
options = ChromiumOptions()
options.headless = True # set to False to watch the window
async with Chrome(options=options) as browser:
tab = await browser.start()
await tab.go_to(PAGE)
sitekey = await find_sitekey(tab)
token = await solve(sitekey, await tab.current_url())
if await fill_token(tab, token):
# The page's own callback takes over. What it does next is
# page specific: this page writes its answer into #result.
await tab.wait_for_script(
"var r = document.querySelector('#result');"
"return r && r.textContent !== 'waiting';"
)
print(await (await tab.query('#result')).text())
asyncio.run(main())Tüm betik
İşte solve.py tek parça halinde, tüm import satırları en üstte. Tek tek eklediğiniz blokların yerini alır, bu yüzden önce onları silin. Düz form sayfasında çalıştırıldığında Welcome yazdırdı ve sayfa token’ı bir kez kabul etti. Callback’in gönderimi yaptığı bir sayfada bu sürüm, sayfa değişmeden önce eski başlığı yazdırabilir; orada yukarıdaki callback varyantını kullanın.
# pip install pydoll-python capskip
import asyncio
import json
from urllib.parse import parse_qs, urlparse
from capskip import AsyncCapSkip
from pydoll import Chrome
from pydoll.browser.options import ChromiumOptions
PAGE = 'https://example.com/page-with-recaptcha'
solver = AsyncCapSkip(host='127.0.0.1', port=8080)
# Put the token in every response box, then run the page's callback.
FILL_JS = """
(function (token) {
var seen = new Set(), fn = null;
document.querySelectorAll('textarea[name="g-recaptcha-response"]')
.forEach(function (box) { box.value = token; });
(function walk(o, depth) {
if (!o || typeof o !== 'object' || seen.has(o) || depth > 6) return;
seen.add(o);
for (var k in o) {
var v; try { v = o[k]; } catch (e) { continue; }
if (k === 'callback' && !fn) {
fn = typeof v === 'string' ? window[v] : v;
}
if (v && typeof v === 'object' && !(v instanceof Node)) {
walk(v, depth + 1);
}
}
})(window.___grecaptcha_cfg, 0);
if (typeof fn === 'function') fn(token);
return typeof fn === 'function';
})(%s)
"""
async def find_sitekey(tab):
# A normal widget carries data-sitekey. A widget drawn by
# grecaptcha.render() only leaves its iframe, with k=<sitekey>.
found = await tab.query(
'.g-recaptcha[data-sitekey], '
'iframe[src*="recaptcha/api2/anchor"]',
timeout=10,
)
if found.tag_name == 'iframe':
src = found.get_attribute('src')
return parse_qs(urlparse(src).query)['k'][0]
return found.get_attribute('data-sitekey')
async def solve(sitekey, url):
result = await solver.recaptcha(sitekey, url)
return result['code']
async def fill_token(tab, token):
reply = await tab.execute_script(
FILL_JS % json.dumps(token), return_by_value=True)
outcome = reply['result']
if 'exceptionDetails' in outcome:
error = outcome['exceptionDetails']['exception']
raise RuntimeError(error['description'])
return outcome['result']['value'] # True if a callback ran
async def main():
options = ChromiumOptions()
options.headless = True # set to False to watch the window
async with Chrome(options=options) as browser:
tab = await browser.start()
await tab.go_to(PAGE)
sitekey = await find_sitekey(tab)
token = await solve(sitekey, await tab.current_url())
if not await fill_token(tab, token):
button = await tab.query('form button[type="submit"]')
async with tab.expect_navigation():
await button.click()
print(await tab.title())
asyncio.run(main())İki sekmeyi aynı anda çözün
İki sekme asyncio.gather ile aynı anda çözüm yapabilir. Birlikte başlatılan iki 3 saniyelik çözüm, farklı token’larla, 4 saniyenin altında birlikte bitti. Tuzak çerezlerdedir. Varsayılan tarayıcı bağlamındaki (browser context) sekmeler tek bir çerez deposunu paylaşır, bu yüzden ikinci sayfa yüklemesi, ilk sekmenin göndermek üzere olduğu oturum ya da CSRF çerezinin yerine geçebilir. Mock site, bazı gerçek sitelerin yaptığı gibi her sayfa yüklemesinde yeni bir oturum çerezi ayarlar; bu yüzden ikinci yükleme ilk sekmenin çerezinin yerine geçti ve eşzamanlı iki gönderimden biri reddedildi. Her sekmeye kendi tarayıcı bağlamını vermek sorunu çözdü ve iki gönderim de kabul edildi. Bu sürüm main() fonksiyonunu aynı şekilde değiştirir ve gönder düğmesine tıkladığı için düz bir forma uygundur.
async def solve_page(tab):
sitekey = await find_sitekey(tab)
token = await solve(sitekey, await tab.current_url())
await fill_token(tab, token)
button = await tab.query('form button[type="submit"]')
async with tab.expect_navigation():
await button.click()
return await tab.title()
async def main():
options = ChromiumOptions()
options.headless = True
async with Chrome(options=options) as browser:
await browser.start()
# One browser context per tab: tabs in the default context
# share cookies, and a second page load can replace the first
# tab's session or CSRF cookie.
contexts = [await browser.create_browser_context() for _ in range(2)]
tabs = [
await browser.new_tab(PAGE, browser_context_id=context)
for context in contexts
]
print(await asyncio.gather(*[solve_page(tab) for tab in tabs]))
for context in contexts:
await browser.delete_browser_context(context)
asyncio.run(main())Pydoll’u başka bir makinedeki CapSkip’e karşı çalıştırın
Pydoll ve çözücünün aynı bilgisayarı paylaşması gerekmez. Bağlantı ayarlarından CapSkip’i Server moduna alın; ağ adresinizi veya genel IP’nizi dinler. Kararlı uzaktan erişim için statik bir genel IP önerilir. Ardından yalnızca istemci satırı değişir. Çözücü hâlâ sizin kendi Windows makinenizdir ve çözüm başına ücretlendirme hâlâ yoktur.
# CapSkip on another Windows PC, in Server mode
solver = AsyncCapSkip(
host='192.168.1.50', # that PC's network address
port=8080,
apiKey='YOUR_API_KEY', # only if API key validation is on
)İki şeye dikkat edin. SDK, CapSkip ile düz HTTP üzerinden konuşur, bu yüzden API anahtarı açık metin olarak taşınır. Bu bağlantıyı özel bir ağda ya da bir VPN içinde tutun ve API key validation’ı açın. Ayrıca CapSkip, Server modu başladığında portunu her adrese açar; bu yüzden beklemediğiniz adresler için bir Windows Firewall engelleme kuralı onu daraltmanın yoludur. AsyncCapSkip ile ulaşılamayan bir adres, yaklaşık 5 saniye sonra mesajı boş bir NetworkException ile başarısız olur. Uzaktan kurulum bu rehber için çalıştırılmadı, yalnızca yapıcı (constructor) okundu.
Zaman aşımları ve bir hatanın nasıl göründüğü
Çözün, sonra hızlıca gönderin. Bir reCAPTCHA token’ı bir kez çalışır ve süresi dolar; bu yüzden sayfa yüklendikten sonra ve göndermeden hemen önce çözün. Katı mock site, aynı token’ın ikinci gönderimini 403 ile reddetti; bu mock’un kendi kuralıdır. Zamanlama için reCAPTCHA token süresinin dolması sayfasına bakın. Her hatanın, mock’a karşı AsyncCapSkip ve varsayılan ayarlarla nasıl göründüğü şöyleydi:
| Durum | Gördüğünüz | Süre |
|---|---|---|
| CapSkip çalışmıyor | NetworkException: All connection attempts failed | 2.2 s |
| CapSkip çağrıyı kabul eder ve sessizleşir | Boş mesajlı NetworkException | 5.3 s |
| Çözüm yapılamıyor | ApiException: ERROR_CAPTCHA_UNSOLVABLE | 0.7 s |
| recaptchaTimeout değeri 6 olarak ayarlanmış, 30 saniyelik bir çözüm | TimeoutException: timeout 6.0 exceeded | 8.7 s |
| Aynı çözüm, 4 saniyelik asyncio.wait_for içinde | Python’un kendi TimeoutError hatası (Python 3.10’da asyncio.TimeoutError) | 4.0 s |
recaptchaTimeout değerini çağrıda değil, istemcide ayarlayın. Çağrıya verilen bir timeout argümanı, got multiple values for keyword argument ‘timeout’ mesajıyla TypeError fırlatır. SDK sınırını yalnızca yoklamalar arasında kontrol eder; 6 saniyelik sınırın 8,7 saniyede tetiklenmesinin nedeni budur. Sert bir tavan önemliyse çağrıyı asyncio.wait_for ile sarın. Bu yalnızca sizin tarafınızı iptal eder. CapSkip işi kendi sınırlarına kadar tutar; bu, gerçek uygulamayla test edilmedi. Pydoll’un kendi hataları vardır. go_to’nun izin verdiğinden uzun süren bir gezinme PageLoadTimeout fırlatır ve reddedilen bir bağlantı, mesajında net::ERR_CONNECTION_REFUSED bulunan bir NavigationError fırlatır. Pydoll’un ayrıca TimeoutException adlı bir sınıfı vardır ve CapSkip’in de aynı adda bir tane vardır. Bunlar farklı sınıflardır, bu yüzden modülleri import edin ve çözücünün hatasını yakalarken capskip.TimeoutException yazın.
Pydoll ile CAPTCHA çözerken sık görülen hatalar
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| ImportError: cannot import name ‘Chrome’ from ‘pydoll’ | Pydoll 2.x kurulu | pydoll-python 3’e yükseltin |
| InvalidBrowserPath: No valid browser path found | Chrome tek bir kullanıcı için kurulmuş, Program Files içinde değil | options.binary_location değerini ayarlayın |
| FailedToStartBrowser: The browser exited with code 21 | Sabit bir user-data-dir başka bir tarayıcı tarafından zaten kullanılıyor | Farklı bir profil klasörü kullanın ya da hiç kullanmayın |
| ArgumentAlreadyExistsInOptions | Aynı ChromiumOptions nesnesi ikinci bir tarayıcı için yeniden kullanıldı ya da Pydoll’un kendisinin eklediği bir bayrağı eklediniz | Her tarayıcı için yeni bir options nesnesi oluşturun |
| Sitekey sorgusunda WaitElementTimeout | Sayfada henüz widget yok ya da seçici onunla eşleşmiyor | Sayfayı görünür bir pencerede kontrol edin, sonra zaman aşımını artırın |
| NetworkException: All connection attempts failed | CapSkip çalışmıyor ya da port yanlış | CapSkip’i başlatın ve bağlantı ayarlarını kontrol edin |
| ApiException: ERROR_CAPTCHA_UNSOLVABLE | CapSkip çözümü tamamlayamadı | Sitekey’i ve sayfa adresini kontrol edin, sonra bir kez daha deneyin. Bkz. ERROR_CAPTCHA_UNSOLVABLE |
| RuntimeError: ReferenceError, bir ad tanımlı değil | fill_token içindeki JavaScript sayfanın içinde hata fırlattı | Aynı betiği tarayıcı konsolunda çalıştırın |
| Sayfa CAPTCHA’nın başarısız olduğunu söylüyor, Python’da hata yok | Token iki kez kullanıldı ya da callback çalışmadı | Her gönderimden hemen önce yeniden çözün |
| FailedToStartBrowser: Could not launch | options.binary_location olmayan bir dosyayı gösteriyor | chrome.exe yolunu kontrol edin |
| Her çalıştırma işin gerektirdiğinden yaklaşık 4 saniye uzun sürüyor | Chrome’a yapılan her yeni bağlantı, yaklaşık 2 saniyelik localhost gecikmesini öder | Tek bir tarayıcıyı ve tek bir sekmeyi yeniden kullanın: aynı sekmedeki ikinci bir go_to 0,2 saniyenin altında sürdü |
FAQ
Pydoll reCAPTCHA’yı kendi başına çözer mi?
Hayır. Pydoll 3.0.0’ın reCAPTCHA kodu yoktur. Tek CAPTCHA yardımcısı bir Cloudflare Turnstile onay kutusu arar ve ona tıklar; bu bir çözüm değildir ve hiçbir token döndürmez.
Bu, headless Chrome ile çalışır mı?
Tam betik, mock sayfaya karşı Chrome 155 ve Chrome for Testing 146 üzerinde hem headless hem headed çalıştırıldığında geçti. Canlı bir sitenin headless bir tarayıcıya nasıl davrandığı test edilmedi ve bu, token’dan ayrı bir sorudur.
Pydoll’u başka bir bilgisayarda, CapSkip’i ise evde çalıştırabilir miyim?
Evet, o bilgisayar CapSkip’e ulaşabiliyorsa. CapSkip’i Server moduna alın ve istemcide host ile port’u ayarlayın. İnternet üzerinden kararlı uzaktan erişim için statik bir genel IP önerilir. Anahtar ve sayfa adresi düz HTTP üzerinden açık metin olarak taşınır, bu yüzden bir VPN ya da özel bir ağı tercih edin ve diğer adresler için bir Windows Firewall engelleme kuralı ekleyin. Bu rehber için hiçbir uzaktan kurulum test edilmedi.
Peki ya invisible reCAPTCHA, v3 ve Enterprise?
SDK’nın recaptcha çağrısı bunlar için seçenekler alır: invisible değeri 1, enterprise değeri 1 ve version değeri v3 olarak ayarlanır. Pydoll tarafı, v3 için eylem adı gibi farklı bir sayfa okuması gerektirir ve bu rehber için bu varyantların hiçbiri çalıştırılmadı. v3 çözücü çağrısının kendisi için şuraya bakın: Python’da reCAPTCHA v3 çözme.
Kısa özet
Bir Pydoll CAPTCHA akışı beş parçadan oluşur: sitekey’i data-sitekey değerinden ya da iframe adresinden okuyun, olay döngüsü ayakta kalsın diye AsyncCapSkip ile çözün, token’ı g-recaptcha-response alanına yazın, sayfanın callback’ini çalıştırın ya da formu gönderin ve her paralel sekmeye kendi tarayıcı bağlamını verin. Göndermeden hemen önce çözün ve istemcide recaptchaTimeout ayarlayın; çağrının çevresine sert bir tavan olarak asyncio.wait_for koyun.
- Python paketinin desteklediği tüm CAPTCHA türleri: Python CAPTCHA çözücü sayfası.
- Düz bir Python betiğinde onay kutulu reCAPTCHA: Python’da reCAPTCHA v2 çözme.
- Onay kutulu çözücünün nasıl çalıştığı: reCAPTCHA v2 çözücü sayfası.
- Kendi API’sine sahip benzer bir tarayıcı kütüphanesi: nodriver’da CAPTCHA çözme.
Bir tarayıcı taraması pahalılaşmadan çok önce yavaşlar. Kendi Windows makinenizde çalışan bir yerel captcha çözücü kullandığınızda çözümler faturaya hiçbir şey eklemez.
