Cara Memecahkan CAPTCHA Pydoll dengan CapSkip di Python Async

Untuk memecahkan CAPTCHA di Pydoll, baca sitekey dari halaman, pecahkan dengan klien AsyncCapSkip milik CapSkip di event loop asyncio yang sama, tulis token ke kotak g-recaptcha-response, lalu jalankan callback halaman atau kirim formulirnya. Pydoll 3.0 tidak punya kode reCAPTCHA sendiri, jadi token harus datang dari pemecah CAPTCHA. CapSkip berjalan di PC Windows Anda sendiri, sehingga crawl yang membuka banyak halaman tidak memiliki biaya per pemecahan. Panduan ini membangun seluruh alur CAPTCHA Pydoll dalam sekitar 80 baris dan membahas jebakan yang menghabiskan waktu di Windows.
Apa yang Anda butuhkan
- CapSkip yang berjalan di PC Windows, dengan pemecah reCAPTCHA diaktifkan. Lihat panduan penyiapan yang menjelaskan cara menjalankan CapSkip untuk pertama kali.
- Python 3.10 atau lebih baru. Pydoll 3.0.0 dan paket capskip 1.3.0 sama-sama membutuhkannya. Semua yang ada di bawah dijalankan di Windows 11 dengan Python 3.14.0, dan skrip lengkapnya juga dijalankan di Python 3.11.7. Python 3.10, 3.12, dan 3.13 tidak dijalankan.
- Google Chrome terinstal di folder Program Files default. Panduan ini memakai Chrome 155, dan skrip lengkapnya juga dijalankan dengan Chrome for Testing 146.
- Prompt PowerShell. Perintahnya memakai sintaks PowerShell.
- Halaman milik Anda sendiri dengan kotak centang reCAPTCHA v2. Formulir contohnya adalah formulir pendaftaran biasa. Ubah selector agar sesuai dengan milik Anda.
- Sebuah alamat untuk pemecah CAPTCHA. Dalam mode Local, CapSkip menjawab di 127.0.0.1 hanya untuk perangkat itu. Dalam mode Server, CapSkip mendengarkan di alamat jaringan atau IP publik Anda, sehingga Pydoll di PC lain, VPS, atau platform hosted dapat memanggilnya lewat API. Keduanya diatur di pengaturan koneksi.
Pengukuran di bawah berasal dari mock CapSkip (pengganti CapSkip yang dibuat khusus untuk pengujian) dan halaman pendaftaran mock di PC yang sama, dipakai bersama Pydoll yang asli, SDK yang asli, Chrome yang asli, dan skrip api.js asli dari Google. Perilaku browser dan SDK juga berlaku di situs Anda sendiri. Waktu pemecahan serta aturan menerima dan menolak pada halaman adalah milik mock itu sendiri. Satu pemecahan terhadap CapSkip yang sedang berjalan, dengan sitekey uji publik dari Google dan pengaturan default, memakan 9.0 detik dan mengembalikan token sepanjang 1,764 karakter. Waktu pemecahan bervariasi dari satu run ke run berikutnya. Token itu tidak dipakai di mana pun, dan tidak ada situs live yang dicoba.
Di mana Pydoll berhenti dan CapSkip mulai
Pydoll mengendalikan Chrome lewat protokol DevTools, tanpa WebDriver di antaranya. Ia memberi Anda browser, elemen halaman, dan cara untuk menjalankan JavaScript. Satu-satunya kode CAPTCHA di versi 3.0.0 adalah helper untuk kotak centang Cloudflare Turnstile. Helper itu menemukan kotak centang lalu mengkliknya. Ia tidak pernah membaca token dan tidak pernah memunculkan error saat tidak terjadi apa-apa. Tidak ada penanganan reCAPTCHA sama sekali. Kotak centang reCAPTCHA v2 dipecahkan oleh layanan yang mengembalikan token, lalu halaman membutuhkan token itu di tempat yang tepat. Itulah pekerjaan CapSkip di sini, dan sisa panduan ini adalah perekatnya.
Langkah 1: buat proyek
Gunakan virtual environment di folder kosong. Perintah di bawah menjalankan Python milik environment itu lewat path-nya, jadi Anda tidak perlu mengaktifkannya, dan kebijakan skrip PowerShell yang dibatasi tidak menghalangi. Jalankan setiap skrip di bawah dengan Python milik environment itu, misalnya .\.venv\Scripts\python.exe solve.py. Instalasi Pydoll yang lama, seperti 2.27.0, akan gagal pada import pertama skrip di bawah dengan ImportError: cannot import name ‘Chrome’ from ‘pydoll’. Pydoll 3.0 mengekspor Chrome dari tingkat teratas.
# Windows PowerShell, in an empty folder python -m venv .venv .\.venv\Scripts\python.exe -m pip install pydoll-python capskip
Langkah 2: jalankan Chrome dan buka halaman
Simpan ini sebagai solve.py. Ini adalah skrip Pydoll terkecil yang membuka halaman Anda dan mencetak judulnya. Browser dimulai di dalam blok async with, sehingga ditutup lagi saat blok berakhir.
# 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 hanya mencari Chrome di dua tempat: Program Files dan Program Files (x86), di bawah Google, Chrome, Application. Chrome yang diinstal untuk satu pengguna, di bawah AppData, tidak ditemukan, dan skrip berhenti dengan InvalidBrowserPath. Setel options.binary_location ke path lengkap chrome.exe untuk memperbaikinya. Path yang tidak ada gagal dengan FailedToStartBrowser. Baris yang sama mengarahkan Pydoll ke Chrome for Testing, dan itu juga berhasil. Pydoll tidak mencocokkan versi browser dengan apa pun, jadi 146 dan 155 sama-sama berjalan.
Start-up lebih lambat daripada yang Anda duga di Windows. Di PC uji, browser.start() memakan 2.8 detik dengan pengaturan default dan Chrome 155 headless. go_to pertama memakan 2.1 detik lagi pada halaman tanpa skrip dari luar, dan sekitar 3.1 detik pada halaman pendaftaran, yang memuat skrip Google. Pydoll terhubung ke localhost, dan localhost mencoba alamat IPv6 lebih dulu. Port debugging Chrome tidak mendengarkan di IPv6, dan Windows butuh sekitar 2 detik untuk menolak koneksi loopback, sehingga setiap koneksi baru ke Chrome membayar sekitar 2 detik sebelum yang IPv4 berhasil. Artinya browser dan setiap tab tambahan yang Anda buka. Pydoll tidak punya pengaturan untuk itu. Membuat localhost diselesaikan ke 127.0.0.1 di dalam proses Python menghilangkan jeda itu dalam pengujian, tetapi cara itu menambal library standar, jadi panduan ini tidak menyentuhnya. Perhitungkan hal ini saat Anda mengukur waktu sebuah run.
Blok with menutup Chrome saat keluar secara normal, setelah exception di dalamnya, dan setelah task yang dibatalkan, serta menghapus folder profil sementara. Mengakhiri proses Python dengan taskkill /F melewatkan semua itu. Dalam pengujian, cara itu meninggalkan 13 proses chrome.exe yang tetap berjalan dan folder profil di disk. Ctrl+C di console tidak diuji. Jika Anda pernah menghentikan sebuah run secara paksa, periksa proses chrome.exe di Task Manager sebelum memulai run berikutnya.
Langkah 3: periksa bahwa CapSkip menjawab
Sebelum menambahkan browser, pastikan panggilan ke pemecah CAPTCHA bekerja dengan sendirinya. Simpan ini sebagai first_solve.py. AsyncCapSkip adalah klien async dari paket yang sama. SDK tidak membaca variabel lingkungan apa pun, jadi host dan port ditulis langsung ke dalam klien. Placeholder-nya literal. YOUR_SITEKEY dan alamat halaman harus berasal dari halaman yang benar-benar memuat widget reCAPTCHA v2, atau CapSkip menjawab dengan error. Salin sitekey dari sumber halaman, tempat nilainya adalah data-sitekey. Langkah 4 membacanya dari halaman untuk Anda. Jalankan file itu dengan .\.venv\Scripts\python.exe first_solve.py.
# 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())Langkah 4: baca sitekey dari halaman
Sitekey ada di halaman, dan Pydoll bisa membacanya. Widget biasa adalah div dengan class g-recaptcha dan atribut data-sitekey. Widget yang digambar halaman dengan grecaptcha.render() tidak memiliki div seperti itu. Widget semacam itu meninggalkan sebuah iframe yang alamatnya membawa sitekey di parameter k. Fungsi ini menangani keduanya dengan satu selector, dan nama tag memberi tahu mana yang didapat. Tambahkan ke solve.py di atas async def main().
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')Dua detail Pydoll penting di sini. get_attribute adalah fungsi biasa, bukan coroutine, jadi jangan di-await, dan ia mengembalikan None untuk atribut yang tidak ada. Lalu query memunculkan ElementNotFound ketika tidak ada yang cocok. Dengan timeout, query menunggu dan memunculkan WaitElementTimeout sebagai gantinya, dan itu pilihan yang tepat untuk widget yang muncul sesaat setelah halaman dimuat. Widget yang disisipkan 3 detik setelah pemuatan ditemukan sekitar 3 detik kemudian, dengan timeout 10 detik di find_sitekey.
Langkah 5: pecahkan di event loop yang sama
Pydoll berjalan di asyncio, dan panggilan pemecahan Anda berjalan di loop yang sama. Itu membuat pilihan klien menjadi penting. Tambahkan ini juga di atas async def main(), dan lakukan hal yang sama untuk fungsi di Langkah 6.
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']Klien CapSkip sinkron juga bisa dipakai, tetapi ia memblokir loop selama seluruh pemecahan, dan Pydoll berhenti menjawab Chrome selagi menunggu. Sebuah run mock menghitung seberapa sering halaman menjawab saat ditanya jam setiap 50 milidetik, sementara pemecahan mock 3 detik berjalan. Jeda terpanjang adalah waktu terlama antara dua jawaban:
| Klien | Waktu pemecahan | Jumlah tick | Jeda terpanjang |
|---|---|---|---|
| Klien CapSkip sinkron, dipanggil langsung di fungsi async | 3.76 s | 5 | 3.78 s |
| CapSkip di asyncio.to_thread | 3.76 s | 65 | 0.06 s |
| AsyncCapSkip | 5.0 s | 68 | 0.3 s |
Halaman itu sendiri tetap berjalan pada kasus pertama. Hanya sisi Python yang membeku: Python tidak bisa bereaksi pada apa pun yang dilakukan halaman sampai pemecahan selesai, sehingga event dari tab kedua ditangani terlambat. AsyncCapSkip memakan sekitar satu detik lebih lama di sini, tetapi itu bergantung pada letak polling berikutnya setelah pemecahan, dan dengan pemecahan mock 2, 4, dan 8 detik ia selesai lebih awal daripada versi thread. Yang selalu menjadi biayanya adalah sekitar 0.15 detik loop terblokir untuk setiap request, karena ia membangun klien HTTP baru setiap kali. Itu tetap lebih baik daripada loop yang membeku.
Langkah 6: tulis token ke halaman
reCAPTCHA yang sudah dipecahkan berupa token. Halaman mengharapkannya ada di textarea bernama g-recaptcha-response, dan jika widget memiliki callback, halaman mengharapkan callback itu dijalankan dengan token tersebut. Fungsi ini melakukan keduanya. Ia memakai execute_script milik Pydoll dan mengembalikan True saat menemukan dan menjalankan callback. Tambahkan di atas async def main() juga.
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-nya menelusuri objek konfigurasi milik Google sendiri untuk menemukan callback, karena kunci di dalamnya adalah nama pendek yang bisa diubah Google. Atribut data-callback disimpan di sana sebagai nama sebuah fungsi, jadi penelusuran mencari nama itu di window. Callback yang diberikan ke grecaptcha.render() disimpan sebagai fungsi itu sendiri. Kedua kasus dijalankan terhadap api.js asli dari Google.
Pydoll mengembalikan balasan DevTools mentah dari execute_script, jadi nilainya berada di reply[‘result’][‘result’][‘value’], dan Anda harus meng-await pemanggilannya. Sebuah objek kembali sebagai referensi kecuali Anda memberikan return_by_value=True. Error JavaScript tidak dimunculkan di Python. Ia menambahkan exceptionDetails ke balasan, itulah sebabnya fungsi memeriksanya dan memunculkan RuntimeError sendiri.
Langkah 7: gabungkan semuanya
Hapus async def main() dan baris asyncio.run(main()) di bagian bawah solve.py, pertahankan fungsi di atasnya, lalu tempel ini sebagai gantinya. Kode ini memecahkan setelah halaman dimuat, karena sitekey berasal dari halaman, dan memecahkan tepat sebelum token dipakai. Jika sebuah callback berjalan, halaman mengambil alih. Jika tidak, skrip mengklik tombol submit formulir dan menunggu navigasi.
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())Pada halaman yang callback-nya melakukan pengiriman, tidak ada yang perlu diklik. Versi ini menggantikan main() dengan cara yang sama. Apa yang terjadi selanjutnya bergantung pada halaman, jadi tunggu sesuatu yang diubah halaman itu sendiri. Versi ini menunggu elemen hasil pada halaman uji berubah dari waiting menjadi sesuatu yang lain. Ubah selector ke apa pun yang diperbarui halaman Anda.
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())Skrip lengkap
Berikut solve.py dalam satu bagian, dengan semua import di atas. File ini menggantikan blok yang Anda tambahkan satu per satu, jadi hapus blok-blok itu lebih dulu. Dijalankan pada halaman formulir biasa, skrip mencetak Welcome dan halaman menerima token sekali. Pada halaman yang callback-nya melakukan pengiriman, versi ini bisa mencetak judul lama sebelum halaman berubah, jadi pakai varian callback di atas di sana.
# 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())Pecahkan dua tab sekaligus
Dua tab bisa memecahkan pada saat yang sama dengan asyncio.gather. Dua pemecahan 3 detik yang dimulai bersamaan selesai bersamaan dalam waktu kurang dari 4 detik, dengan token yang berbeda. Jebakannya adalah cookie. Tab di browser context default berbagi satu cookie jar, sehingga pemuatan halaman kedua bisa menggantikan cookie sesi atau CSRF yang akan dipakai tab pertama untuk mengirim. Situs mock menyetel cookie sesi baru pada setiap pemuatan halaman, seperti yang dilakukan sebagian situs sungguhan, jadi pemuatan kedua menggantikan cookie tab pertama dan satu dari dua pengiriman bersamaan ditolak. Memberi setiap tab browser context sendiri memperbaikinya, dan kedua pengiriman diterima. Versi ini menggantikan main() dengan cara yang sama, dan ia mengklik submit, jadi cocok untuk formulir biasa.
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())Menjalankan Pydoll terhadap CapSkip di mesin lain
Pydoll dan pemecah CAPTCHA tidak harus berada di PC yang sama. Alihkan CapSkip ke mode Server di pengaturan koneksi, dan ia akan mendengarkan di alamat jaringan atau IP publik Anda. IP publik statis direkomendasikan untuk akses jarak jauh yang stabil. Setelah itu hanya baris klien yang berubah. Pemecah CAPTCHA tetap berupa mesin Windows milik Anda sendiri, dan pemecahannya tetap tanpa kuota.
# 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
)Perhatikan dua hal. SDK berbicara dengan CapSkip lewat HTTP biasa, sehingga API key dikirim sebagai teks polos. Jaga agar tautan itu berada di jaringan pribadi atau VPN, dan aktifkan API key validation. Lalu CapSkip membuka port-nya untuk semua alamat saat mode Server dimulai, jadi aturan blokir Windows Firewall untuk alamat yang tidak Anda harapkan adalah cara untuk mempersempitnya. Dengan AsyncCapSkip, alamat yang tidak dapat dijangkau gagal setelah sekitar 5 detik dengan NetworkException yang pesannya kosong. Penyiapan jarak jauh tidak dijalankan untuk panduan ini, hanya konstruktornya yang dibaca.
Timeout dan seperti apa kegagalan itu
Pecahkan, lalu kirim, dengan cepat. Token reCAPTCHA hanya berfungsi sekali dan kedaluwarsa, jadi pecahkan setelah halaman dimuat dan tepat sebelum Anda mengirim. Situs mock yang ketat menolak pengiriman kedua dengan token yang sama dengan 403, dan itu aturan milik mock itu sendiri. Halaman tentang kedaluwarsa token reCAPTCHA memuat rincian waktunya. Berikut seperti apa setiap kegagalan dengan AsyncCapSkip dan pengaturan default, terhadap mock:
| Kasus | Apa yang Anda lihat | Setelah |
|---|---|---|
| CapSkip tidak sedang berjalan | NetworkException: All connection attempts failed | 2.2 s |
| CapSkip menerima panggilan lalu diam | NetworkException dengan pesan kosong | 5.3 s |
| Pemecahan tidak dapat dilakukan | ApiException: ERROR_CAPTCHA_UNSOLVABLE | 0.7 s |
| Pemecahan 30 detik dengan recaptchaTimeout disetel ke 6 | TimeoutException: timeout 6.0 exceeded | 8.7 s |
| Pemecahan yang sama di dalam asyncio.wait_for dengan 4 detik | TimeoutError milik Python sendiri (asyncio.TimeoutError di Python 3.10) | 4.0 s |
Setel recaptchaTimeout pada klien, bukan pada panggilan. Argumen timeout pada panggilan memunculkan TypeError dengan pesan got multiple values for keyword argument ‘timeout’. SDK memeriksa batasnya hanya di antara polling, itulah sebabnya batas 6 detik terpicu pada 8.7 detik. Bungkus panggilan dengan asyncio.wait_for jika batas keras penting. Itu hanya membatalkan sisi Anda. CapSkip tetap menyimpan job sampai batasnya sendiri, hal yang tidak diuji dengan aplikasi asli. Pydoll punya error-nya sendiri. Navigasi yang memakan waktu lebih lama daripada yang diizinkan go_to memunculkan PageLoadTimeout, dan koneksi yang ditolak memunculkan NavigationError dengan net::ERR_CONNECTION_REFUSED di pesannya. Pydoll juga punya kelas TimeoutException, dan CapSkip punya satu dengan nama yang sama. Keduanya kelas yang berbeda, jadi import modulnya dan tulis capskip.TimeoutException saat Anda menangkap milik pemecah CAPTCHA.
Kesalahan umum pada CAPTCHA Pydoll
| Apa yang Anda lihat | Penyebab | Perbaiki |
|---|---|---|
| ImportError: cannot import name ‘Chrome’ from ‘pydoll’ | Pydoll 2.x terinstal | Upgrade ke pydoll-python 3 |
| InvalidBrowserPath: No valid browser path found | Chrome diinstal untuk satu pengguna, bukan di Program Files | Setel options.binary_location |
| FailedToStartBrowser: The browser exited with code 21 | user-data-dir yang tetap sudah dipakai oleh browser lain | Gunakan folder profil yang berbeda, atau tanpa folder profil |
| ArgumentAlreadyExistsInOptions | Objek ChromiumOptions yang sama dipakai ulang untuk browser kedua, atau Anda menambahkan flag yang sudah ditambahkan Pydoll sendiri | Buat objek options baru untuk setiap browser |
| WaitElementTimeout pada query sitekey | Halaman belum memiliki widget, atau selector tidak cocok dengannya | Periksa halaman di jendela yang terlihat, lalu naikkan timeout |
| NetworkException: All connection attempts failed | CapSkip tidak berjalan, atau port-nya salah | Jalankan CapSkip dan periksa pengaturan koneksi |
| ApiException: ERROR_CAPTCHA_UNSOLVABLE | CapSkip tidak dapat menyelesaikan pemecahan | Periksa sitekey dan alamat halaman, lalu coba lagi sekali. Lihat ERROR_CAPTCHA_UNSOLVABLE |
| RuntimeError: ReferenceError, sebuah nama tidak didefinisikan | JavaScript di fill_token melempar error di dalam halaman | Jalankan skrip yang sama di console browser |
| Halaman mengatakan CAPTCHA gagal, tidak ada error di Python | Token dipakai dua kali, atau callback tidak berjalan | Pecahkan lagi tepat sebelum setiap pengiriman |
| FailedToStartBrowser: Could not launch | options.binary_location menunjuk ke file yang tidak ada | Periksa path ke chrome.exe |
| Setiap run memakan sekitar 4 detik lebih lama daripada pekerjaannya | Setiap koneksi baru ke Chrome membayar jeda localhost sekitar 2 detik | Pakai ulang satu browser dan satu tab: go_to kedua pada tab yang sama memakan kurang dari 0.2 detik |
FAQ
Apakah Pydoll memecahkan reCAPTCHA dengan sendirinya?
Tidak. Pydoll 3.0.0 tidak punya kode reCAPTCHA. Satu-satunya helper CAPTCHA-nya mencari kotak centang Cloudflare Turnstile dan mengkliknya, yang bukan pemecahan dan tidak mengembalikan token.
Apakah ini berfungsi dengan Chrome headless?
Skrip lengkap lulus dalam mode headless maupun headed terhadap halaman mock, di Chrome 155 dan Chrome for Testing 146. Bagaimana situs live memperlakukan browser headless tidak diuji, dan itu pertanyaan terpisah dari token.
Bisakah saya menjalankan Pydoll di PC lain dan CapSkip di rumah?
Bisa, jika PC itu dapat menjangkau CapSkip. Jalankan CapSkip dalam mode Server, dan setel host serta port di klien. IP publik statis direkomendasikan untuk akses jarak jauh yang stabil lewat internet. Key dan alamat halaman dikirim sebagai teks polos lewat HTTP biasa, jadi pilih VPN atau jaringan pribadi, dan tambahkan aturan blokir Windows Firewall untuk alamat lain. Tidak ada penyiapan jarak jauh yang diuji untuk panduan ini.
Bagaimana dengan reCAPTCHA invisible, v3, dan Enterprise?
Panggilan recaptcha di SDK menerima opsi untuk semuanya: invisible disetel ke 1, enterprise disetel ke 1, dan version disetel ke v3. Sisi Pydoll membutuhkan pembacaan halaman yang berbeda, seperti nama action untuk v3, dan tidak satu pun varian itu dijalankan untuk panduan ini. Untuk pemanggilan pemecah v3 itu sendiri, lihat memecahkan reCAPTCHA v3 di Python.
Versi singkatnya
Alur CAPTCHA Pydoll memiliki lima bagian: baca sitekey dari data-sitekey atau dari alamat iframe, pecahkan dengan AsyncCapSkip agar event loop tetap hidup, tulis token ke g-recaptcha-response, jalankan callback halaman atau kirim formulir, dan beri setiap tab paralel browser context-nya sendiri. Pecahkan tepat sebelum Anda mengirim, dan setel recaptchaTimeout pada klien dengan asyncio.wait_for di sekitar panggilan sebagai batas keras.
- Setiap tipe CAPTCHA yang ditangani paket Python: halaman pemecah CAPTCHA Python.
- reCAPTCHA kotak centang di skrip Python biasa: memecahkan reCAPTCHA v2 di Python.
- Cara kerja pemecah kotak centang: halaman pemecah reCAPTCHA v2.
- Library browser serupa dengan API-nya sendiri: memecahkan CAPTCHA di nodriver.
Crawl dengan browser menjadi lambat jauh sebelum menjadi mahal, dan dengan sebuah pemecah captcha lokal di mesin Windows Anda sendiri, pemecahan CAPTCHA tidak menambah tagihan sama sekali.
