Cara Memecahkan CAPTCHA di Patchright Tanpa Merusak Stealth

patchright captcha - How to Solve CAPTCHA in Patchright Without Breaking Stealth

Alur captcha di Patchright terdiri dari tiga langkah yang sama seperti di tempat lain: baca sitekey, kirimkan ke solver, lalu kembalikan token ke halaman. Langkah ketiga itulah yang membuat library ini mengejutkan banyak orang. Secara default Patchright menjalankan JavaScript Anda di sebuah isolated context, dan isolated context berbagi DOM halaman tetapi tidak berbagi global JavaScript halaman. Jadi penulisan token memang berhasil, textarea benar-benar berisi nilainya, dan callback milik situs tidak pernah berjalan karena callback itu tidak ada di dalam scope tempat kode Anda dieksekusi. Satu argumen tambahan menyelesaikannya.

Apa yang Anda butuhkan

  • Python 3.10 atau lebih baru, atau Node.js jika Anda lebih suka paket JavaScript-nya. Patchright tersedia untuk kedua runtime tersebut dan menjadi pengganti langsung untuk Playwright di masing-masing runtime.
  • Browser Chromium yang diunduh melalui installer milik Patchright sendiri. Firefox dan WebKit tidak ditambal dan tidak didukung.
  • URL halaman dari formulir yang dilindungi. Sitekey dibaca saat runtime.
  • CapSkip yang berjalan dalam mode Local ketika skrip dan solver berada di satu mesin, atau dalam mode Server ketika keduanya tidak berada di satu mesin. Keduanya dijelaskan di pengaturan koneksi.
# pip install patchright
pip install -U capskip patchright

# Pulls the browser. Real Chrome is the recommended channel,
# and the maintainers say so explicitly.
patchright install chrome

Apa yang sebenarnya diubah Patchright

Patchright adalah Playwright dengan tanda-tanda otomatisasi yang paling kentara dihilangkan. Tambalan utamanya adalah ia tidak pernah memanggil Runtime.enable, sinyal paling nyaring yang dipancarkan sesi Playwright bawaan, dan itu dicapai dengan menjalankan skrip Anda di ExecutionContexts yang terisolasi. Patchright juga mematikan Console API sepenuhnya, menambahkan flag yang menyembunyikan navigator.webdriver, dan membuang beberapa default Playwright yang menandai sebuah sesi sebagai otomatis: flag automation itu sendiri, penimpaan pemblokir popup, blokir pembaruan komponen, serta switch yang menonaktifkan aplikasi dan ekstensi bawaan.

Dua di antaranya berdampak langsung pada pekerjaan CAPTCHA, dan keduanya mudah membuat Anda tersandung.

Konsol yang dimatikan berarti tidak ada satu pun yang Anda log dari dalam halaman sampai ke Anda. Fungsionalitas console sama sekali tidak bekerja di Patchright, jadi kebiasaan biasa menaruh baris log di dalam panggilan evaluate lalu membacanya dari driver sudah mati di sini. Kembalikan sebuah nilai dari panggilan itu sebagai gantinya. Itu justru praktik yang lebih baik dan memang satu-satunya pilihan yang Anda punya.

Ekstensi yang kembali diaktifkan adalah yang lebih bersahabat. Playwright biasanya dijalankan dengan ekstensi dinonaktifkan, dan Patchright menghapus switch tersebut, sehingga ekstensi browser yang dimuat ke dalam profil persisten benar-benar berjalan. Jika Anda lebih memilih tidak menulis kode ini sama sekali, ekstensi browser CapSkip menangani widget di dalam halaman dan Anda mengendalikan formulirnya seolah-olah seorang manusia yang lolos.

Satu kemampuan lagi yang layak diketahui: Patchright bisa menjangkau closed shadow root dengan locator dan XPath biasa. Widget yang menyembunyikan markup-nya di balik closed root tetap dapat dialamati tanpa penanganan khusus.

Langkah 1: jalankan sesuai rekomendasi para maintainer

Stealth milik Patchright bergantung pada konfigurasi peluncuran sama besarnya dengan pada tambalannya. Penyiapan yang didokumentasikan adalah persistent context pada channel Chrome asli, dengan jendela yang terlihat dan tanpa penimpaan viewport, serta tanpa user agent maupun header kustom sama sekali. Dua hal terakhir itu penting: user agent yang diatur manual bertentangan dengan sisa fingerprint dan meniadakan semua usaha tadi.

# pip install patchright
from patchright.sync_api import sync_playwright

with sync_playwright() as p:
    context = p.chromium.launch_persistent_context(
        user_data_dir="C:\\profiles\\scraper",
        channel="chrome",
        headless=False,
        no_viewport=True,
        # Do not set user_agent or extra headers here.
    )
    page = context.new_page()
    page.goto("https://example.com/page-with-recaptcha")

Perhatikan jendela yang terlihat itu. Mode headless adalah tempat sebagian besar anggaran deteksi terkuras, dan konfigurasi yang direkomendasikan tidak memakainya. Di Windows itu berarti akun yang menjalankan skrip membutuhkan sesi desktop interaktif, dan hal ini layak direncanakan sebelum Anda menempatkannya di sebuah server.

Langkah 2: baca sitekey dari halaman

Sitekey berada di dokumen host, bukan di dalam iframe widget, dan locator biasa sudah bisa membacanya. Locator berjalan lewat protokol browser alih-alih melalui execution context mana pun, jadi tidak ada urusan isolated world yang memengaruhi langkah ini.

# Locators auto-wait, so this doubles as a wait condition
# for a widget that renders late.
holder = page.locator("div.g-recaptcha")
holder.wait_for(state="attached", timeout=15000)

sitekey = holder.get_attribute("data-sitekey")
print(sitekey)   # 6Lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Sebagian situs tidak pernah menaruh key-nya di halaman host dan hanya mengoperkannya di URL iframe widget. Dalam kasus itu, baca dari query string, dan periksa sebelum menghabiskan satu pemecahan, karena nilai kosong akan berjalan sampai ke solver dan kembali sebagai ERROR_GOOGLEKEY, jauh sekali dari operasi baca yang sebenarnya gagal.

# Fallback: the k= parameter on the anchor iframe.
from urllib.parse import urlparse, parse_qs

src = page.locator("iframe[src*='recaptcha/api2/anchor']").get_attribute("src")
sitekey = parse_qs(urlparse(src).query)["k"][0]

Langkah 3: pecahkan di komputer Anda sendiri

SDK Python berbicara dengan CapSkip di port 8080 dan mengembalikan token sebagai string biasa. Satu metode mencakup reCAPTCHA v2, Invisible, Enterprise, dan v3, dengan varian-variannya diberikan sebagai opsi alih-alih sebagai panggilan terpisah.

# pip install capskip
from capskip import CapSkip

solver = CapSkip(host="127.0.0.1", port=8080)

# Invisible v2 takes invisible=1, Enterprise takes enterprise=1,
# and v3 takes version="v3" with an action.
result = solver.recaptcha(sitekey=sitekey, url=PAGE_URL)

token = result["code"]   # the g-recaptcha-response value

Turnstile dan GeeTest punya metode sendiri dan berbentuk sama. Turnstile juga mengembalikan user agent yang dipakai saat pemecahan dilakukan, dan halaman challenge akan menolak token kecuali user agent tersebut ikut dikirim bersamanya. Kirimkan hanya pada permintaan formulir. Jangan berikan ke peluncur browser, karena user agent yang diatur manual persis merupakan hal yang dilarang oleh konfigurasi stealth. Daftar parameter lengkapnya ada di dokumentasi API CapSkip.

Langkah 4: taruh token di tempat yang bisa dipakai halaman

Inilah bagian yang khas untuk library ini. Textarea respons disembunyikan dengan display:none, jadi tidak ada yang bisa mengetik ke dalamnya dan nilainya harus diberikan lewat JavaScript. Penugasan nilai itu berhasil dari isolated context, karena DOM-nya dipakai bersama. Bangun string-nya dengan json.dumps alih-alih f-string, karena string literal JSON juga merupakan string literal JavaScript yang sah, lengkap dengan tanda kutip dan escaping-nya.

# A DOM write is fine from the isolated context.
import json

page.evaluate(
    "document.getElementById('g-recaptcha-response').value = "
    + json.dumps(token)
)

page.click("button[type=submit]")

Itu mencakup situs yang formulirnya membaca textarea saat submit. Banyak situs tidak begitu. Situs-situs itu mendaftarkan callback sukses ke widget dan sama sekali tidak pernah melihat textarea, jadi token harus diserahkan ke sebuah fungsi yang didefinisikan halaman. Isolated context milik Patchright punya global JavaScript sendiri, yang berarti fungsi-fungsi halaman dan konfigurasi client reCAPTCHA sama sekali tidak ada di dalamnya. Panggilan itu gagal dengan reference error dan sebanyak apa pun percobaan ulang tidak akan mengubahnya.

Jawaban Patchright adalah sebuah argumen tambahan. Metode evaluate, evaluate_handle, dan evaluate_all sama-sama menerima isolated_context, nilainya default True, dan menyetelnya ke False akan menjalankan skrip di main world milik halaman itu sendiri.

# The main world is where the page's own globals live.
page.evaluate(
    "token => window.onRecaptchaSuccess(token)",
    token,
    isolated_context=False,
)

Baca nama callback dari markup halaman alih-alih menebaknya. Gunakan main world hanya untuk injeksi dan tidak untuk hal lain: kode yang berjalan di sana terlihat oleh situs, dan itulah alasan utama isolated context dijadikan default. Kedua gaya pengiriman itu tetap reCAPTCHA v2 biasa di baliknya, dan keduanya dibahas di halaman pemecah reCAPTCHA v2.

Contoh lengkap yang berfungsi

Semua yang di atas dalam satu skrip. Solver dibuat sekali, sitekey diperiksa sebelum satu pemecahan dihabiskan untuknya, dan token diverifikasi dengan mengembalikan panjangnya alih-alih dengan melakukan logging di dalam halaman.

# pip install capskip patchright
import json
from patchright.sync_api import sync_playwright
from capskip import CapSkip

PAGE_URL = "https://example.com/page-with-recaptcha"

solver = CapSkip(host="127.0.0.1", port=8080)

with sync_playwright() as p:
    context = p.chromium.launch_persistent_context(
        user_data_dir="C:\\profiles\\scraper",
        channel="chrome",
        headless=False,
        no_viewport=True,
    )
    page = context.new_page()
    page.goto(PAGE_URL)

    holder = page.locator("div.g-recaptcha")
    holder.wait_for(state="attached", timeout=15000)
    sitekey = holder.get_attribute("data-sitekey")
    if not sitekey:
        raise RuntimeError("Widget found but data-sitekey was empty.")

    token = solver.recaptcha(sitekey=sitekey, url=PAGE_URL)["code"]
    page.evaluate(
        "document.getElementById('g-recaptcha-response').value = "
        + json.dumps(token)
    )

    length = page.evaluate(
        "document.getElementById('g-recaptcha-response').value.length"
    )
    print(length)   # 0 means the injection did not land

    page.click("button[type=submit]")
    page.wait_for_load_state("networkidle")
    context.close()

Menjalankan solver di mesin lain

Patchright biasanya berakhir di mesin yang lebih besar daripada tempat Anda menulis skripnya, dan penyiapan jendela terlihat yang direkomendasikan cukup cepat mendorong orang ke VM khusus. Solver tidak harus ikut berpindah.

CapSkip punya dua mode koneksi. Local mengikat ke 127.0.0.1 dan hanya melayani perangkat itu, dan itulah pengaturan yang tepat selama Anda menulis skrip di mesin tempat aplikasinya berjalan. Server mengikat ke alamat jaringan atau IP publik Anda, sehingga VM scraping, workstation kedua, atau sekumpulan penuh mesin seperti itu memanggil mesin Windows yang sama lewat API. IP publik statis menjaga alamat itu tetap stabil. Tidak ada yang berubah di kode selain host-nya, dan tidak ada pula yang berubah pada biayanya, karena perangkat kerasnya tetap milik Anda.

# Same SDK, same call. Only the host moves.
solver = CapSkip(host="10.0.0.12", port=8080, apiKey="YOUR_API_KEY")

Aktifkan validasi key begitu solver mendengarkan di alamat jaringan, dan beri setiap mesin key-nya sendiri agar satu key bisa dicabut tanpa mengusik yang lain. Kedua mode itu dijelaskan langkah demi langkah dalam panduan penyiapan CapSkip.

Kesalahan umum dan artinya

Apa yang Anda lihatPenyebabPerbaiki
Textarea berisi token tetapi formulir gagalSitus memakai callback dan tidak pernah membaca textareaPanggil callback dengan isolated_context=False
Reference error yang menyebut sebuah fungsi halamanGlobal halaman tidak ada di isolated contextPerbaikan yang sama: jalankan panggilan itu di main world
Tidak ada yang sampai dari console log di halamanPatchright menonaktifkan Console API sepenuhnyaKembalikan nilai dari evaluate alih-alih melakukan logging
Firefox atau WebKit berperilaku seperti Playwright biasaHanya browser Chromium yang ditambalGunakan channel Chromium atau Chrome
Diblokir meski sudah ditambalUser agent atau header kustom bertentangan dengan fingerprintHapus keduanya dan pakai persistent context di Chrome
ERROR_GOOGLEKEYSitekey kosong sampai ke solverPastikan nilainya benar sebelum memanggil recaptcha
NetworkExceptionCapSkip tidak berjalan, atau host-nya salahJalankan aplikasinya, atau arahkan host ke alamat server
TimeoutExceptionProses pemecahan melampaui recaptchaTimeoutNaikkan di atas nilai default 300 detik

FAQ

Bisakah saya memindahkan skrip Playwright saya tanpa perubahan?

Ganti import-nya dan sebagian besar akan berjalan. Locator, context, route, wait, dan navigasi semuanya berperilaku sama seperti sebelumnya. Tiga hal perlu ditinjau ulang: setiap panggilan evaluate yang menyentuh sesuatu yang didefinisikan halaman, yang kini butuh argumen tambahan itu; apa pun yang mengandalkan output console, yang sudah hilang; dan target Firefox atau WebKit mana pun, yang tidak ditambal. Gambaran Playwright yang lebih luas ada di halaman pemecah CAPTCHA Playwright.

Apakah memakai main world membuat saya terdeteksi?

Pada prinsipnya ya, karena halaman bisa melihat kode yang berjalan di sana. Pada praktiknya paparannya hanya satu panggilan fungsi yang berlangsung beberapa mikrodetik, dan tampak sama dengan yang dilakukan skrip milik widget itu sendiri ketika seorang manusia lolos dari challenge. Simpan semua hal lain di isolated context, lakukan injeksi dalam satu panggilan alih-alih beberapa panggilan, dan permukaan paparannya tetap kecil.

Haruskah saya mengeklik widget Turnstile alih-alih menyuntikkan token?

Kadang begitu. Checkbox Turnstile dalam mode managed bisa lolos dengan sendirinya ketika browsernya tampak meyakinkan, dan itulah justru tujuan Patchright, jadi mengeklik lebih dulu lalu jatuh kembali ke pemecahan layak dicoba. Klik pada checkbox reCAPTCHA hanya akan membuka challenge gambar, jadi tidak ada yang bisa didapat di sana. Sisi widget-nya dibahas di halaman pemecah Cloudflare Turnstile.

Crawler saya berjalan di Linux. Di mana CapSkip ditempatkan?

Di mesin Windows yang Anda kendalikan, dengan mode Server dinyalakan. Mesin Linux lalu memanggilnya lewat API seperti layanan internal lainnya, sehingga Patchright dan solver tidak perlu berbagi sistem operasi atau bahkan segmen jaringan. Arahkan argumen host ke alamat itu, aktifkan validasi kunci, dan beri crawler kunci miliknya sendiri.

Versi singkatnya

Instal Patchright, jalankan persistent context di channel Chrome dengan jendela yang terlihat dan tanpa user agent kustom, baca sitekey dengan locator biasa, lalu pecahkan lewat CapSkip di 127.0.0.1:8080. Tulis token langsung ke textarea dari isolated context bawaan, dan gunakan isolated_context=False hanya ketika situs ingin sebuah callback dipanggil. Untuk sisa lanskap Python, termasuk Selenium dan Playwright, lihat halaman pemecah CAPTCHA Python.

Ada satu hal yang layak diketahui sebelum Anda menaikkan skala crawling. CapSkip adalah pemecah captcha tanpa batas yang berjalan di perangkat keras yang sudah Anda miliki, jadi mencoba ulang seribu halaman memakan biaya persis sama dengan mencoba ulang sepuluh halaman.