SeleniumBase Testlerinde CAPTCHA Nasıl Çözülür (Python)

seleniumbase captcha - How to Solve CAPTCHA in SeleniumBase Tests (Python)

SeleniumBase tarayıcıyı sürer. CAPTCHA'yı sizin yerinize asla okumaz. Bu yüzden bir SeleniumBase captcha adımı üç hamleden oluşur: sitekey'i sayfadan çekin, bir çözücüden token isteyin, sonra o token'ı forma geri yazıp gönderin. Çözüm tarayıcının dışında gerçekleşir; aynı kodun headed bir çalıştırmada, headless bir çalıştırmada ve bir CI işinde çalışmasının nedeni de budur. İşte kullanıyor olma ihtimaliniz en yüksek olan iki sözdizimi biçiminde.

Neye ihtiyacınız var

  • SeleniumBase ve CapSkip SDK'sı kurulu olacak şekilde Python 3.10 veya daha yenisi.
  • Gerçekten bir widget oluşturan bir sayfa. Google’ın kendi reCAPTCHA test anahtarları her zaman geçer, dolayısıyla kodunuz hakkında hiçbir şey kanıtlamazlar.
  • Local modda loopback adresinde ya da Server modda test runner'ınızın erişebileceği bir makinede çalışan bir CapSkip. İkisi de şurada açıklanmıştır: bağlantı ayarları, hangisini isteyeceğiniz ise testlerinizin nerede çalıştığına bağlıdır.
# Both packages, one command.
pip install seleniumbase capskip

UC mode ne yapar, ne yapmaz

SeleniumBase, UC mode ile birlikte gelir ve insanlar ondan bir çözücü beklediği için görevini net söylemekte fayda var. UC mode, bir tarayıcının sızdırdığı otomasyon sinyallerini azaltır ve GUI yardımcıları bir Cloudflare ara sayfasındaki onay kutusuna tıklayabilir. Bu, bir reCAPTCHA token'ı üretmekten farklı bir problemdir. UC mode’da hiçbir şey bozulmuş bir görüntüyü okumaz ya da içinde otobüs olan kareleri seçmez.

# pip install seleniumbase
from seleniumbase import SB

with SB(uc=True) as sb:
    # Disconnects the driver briefly so the page loads unobserved.
    sb.uc_open_with_reconnect("https://example.com/protected", reconnect_time=3)

    # Drives the real mouse pointer, so it needs a desktop session
    # or a virtual display. It clicks a checkbox; it solves nothing.
    sb.uc_gui_click_captcha()

Bundan iki sonuç çıkar. GUI yardımcıları gerçek bir ekran ister; bu da onları çoğu headless CI ortamının dışında bırakır. Ve reCAPTCHA ile GeeTest için hâlâ bir token'a ihtiyacınız var; bu yazının geri kalanı da bunu anlatıyor. İkisini birlikte kullanın: ne sıklıkta doğrulamaya takıldığınızı azaltmak için UC mode, yine de gelen doğrulamalar için bir çözücü.

Adım 1: sitekey'i sayfadan okuyun

Sitekey herkese açıktır. Widget öğesinde bir öznitelik olarak durur ve SeleniumBase onu tek bir çağrıyla okuyabilir; böylece her ortam için ayrı ayrı sabit kodlamak zorunda kalmazsınız.

# pip install seleniumbase
from seleniumbase import SB

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

with SB() as sb:
    sb.open(PAGE)

    # Present on the widget div for v2, and on the script tag for v3.
    sitekey = sb.get_attribute("[data-sitekey]", "data-sitekey")

    print(sitekey)      # this plus the page URL is all the solver needs

Adım 2: çözücüden bir token alın

Bu kısmın SeleniumBase ile hiçbir ilgisi yoktur. Kendi makinenizdeki bir servise yapılan sıradan bir Python çağrısıdır ve bir insan widget'ı geçseydi sayfanın üreteceği token dizesini döndürür.

# pip install capskip
from capskip import CapSkip

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

# v2 checkbox is the default shape. Pass invisible=1 or
# enterprise=1 for those variants, or version="v3" for v3.
result = solver.recaptcha(
    sitekey=sitekey,
    url=PAGE,
)

token = result["code"]      # the value the form is waiting for

Aynı istemci, bir test paketinde karşılaşma ihtimaliniz olan diğer türleri de karşılar. Turnstile için sitekey ve sayfa URL'si ile solver.turnstile, GeeTest için gt ve challenge değerleriyle solver.geetest, bir görsel CAPTCHA için ise bir dosya yolu, bir URL veya base64 data URI ile solver.normal kullanılır. Python CAPTCHA çözücü sayfası tüm kapsamı ele alıyor.

Adım 3: token'ı enjekte edin ve gönderin

Google, forma gizli bir textarea koyar ve token'ı onun değerinde bekler. Bir script çağrısıyla oraya yazın, sonra formu sayfanın kendi arayüzünün göndereceği şekilde gönderin.

# The response field is hidden, so a normal type() will not reach it.
sb.execute_script(
    "document.getElementById('g-recaptcha-response').value = arguments[0];",
    token,
)

sb.click("button[type='submit']")
sb.assert_element(".signup-success")

Sayfa, gönderimde alanı okumak yerine widget'a kendi callback fonksiyonunu bağlıyorsa, tıklamak yerine o fonksiyonu token ile çağırın. Hangisine ihtiyacınız olduğu widget işaretlemesinde görünür: bir data-callback özniteliği fonksiyonu adlandırır, yokluğu ise formun alanı okuduğu anlamına gelir.

Testin tamamı

İşte her şey bir BaseCase sınıfı olarak; bu, mevcut bir pytest paketine ek hiçbir bağlantı gerektirmeden oturan biçimdir.

# pip install seleniumbase capskip
from seleniumbase import BaseCase
from capskip import CapSkip

BaseCase.main(__name__, __file__)

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


class RecaptchaTest(BaseCase):
    def test_signup_form(self):
        self.open(PAGE)
        sitekey = self.get_attribute("[data-sitekey]", "data-sitekey")

        solver = CapSkip(host="127.0.0.1", port=8080)
        token = solver.recaptcha(sitekey=sitekey, url=PAGE)["code"]

        self.execute_script(
            "document.getElementById('g-recaptcha-response').value = arguments[0];",
            token,
        )
        self.click("button[type='submit']")
        self.assert_element(".signup-success")

Geç çözün. Bir reCAPTCHA token'ı yaklaşık iki dakika geçerlidir; bu yüzden testin başında bir tane alıp dört adım sonra kullanmak, ara sıra kaybedeceğiniz bir yarıştır. Çözümü gönderimden hemen önceye koyun; yeniden denemenin yeri de orasıdır.

Çözücüyü bir sunucuda çalıştırmak

Test runner'ları nadiren başında oturduğunuz makinedir. CapSkip bunu ikinci bir bağlantı moduyla karşılar ve kodunuzda değişen tek şey host olur.

ModDinlediği adresNe zaman kullanılır
Yerel127.0.0.1, yalnızca o cihazTestler ve çözücü tek makinede çalışır
SunucuAğ adresiniz veya genel IP'nizBir CI runner'ı, bir VPS veya bir test grid'i dışarıdan bağlanır
# pip install capskip
import os
from capskip import CapSkip

# The SDK reads these names from the environment too, so one test
# file runs unchanged on a laptop and on a shared runner.
solver = CapSkip(
    host=os.environ.get("CAPSKIP_HOST", "127.0.0.1"),
    port=int(os.environ.get("CAPSKIP_PORT", "8080")),
)

Çağıranlar kendi ağınızın dışındaysa statik bir genel IP önerilir. Server modu hâlâ sizin donanımınızdır ve kullanım hâlâ ölçülmez: çözücünün nerede çalıştığını değiştirir; kime ait olduğunu ya da çözüm başına ne tuttuğunu asla değiştirmez. Seçeneklerin tamamı şurada yer alır: bağlantı ayarları.

Yaygın hatalar

GördüğünüzNedenDüzeltme
NetworkExceptionO host ve portta dinleyen bir şey yokCapSkip’i başlatın veya host'u onu çalıştıran sunucuya yöneltin
TimeoutExceptionYoklama recaptchaTimeout süresini aştıZaman aşımını yükseltin veya sitekey'in canlı olan olduğunu kontrol edin
ERROR_GOOGLEKEYSitekey hiç gelmedi veya bozukGöndermeden önce get_attribute'ün ne döndürdüğünü yazdırın
ERROR_PAGEURLSayfa URL'si eksik veya tam bir URL değilTarayıcının üzerinde olduğu mutlak URL'nin aynısını gönderin
Form geçerli bir token'ı reddediyorSayfa, alan yerine bir callback kullanıyordata-callback fonksiyonunu token ile çağırın

API'nin döndürebileceği her kod şurada listelenmiştir: CapSkip API dokümantasyonu, her birini neyin tetiklediğiyle birlikte.

FAQ

UC mode reCAPTCHA'yı tek başına çözer mi?

Hayır. UC mode, tarayıcının daha az otomatik görünmesini sağlar ve GUI yardımcıları aracılığıyla bir Cloudflare ara sayfasındaki onay kutusuna tıklayabilir. Bunların hiçbiri bir reCAPTCHA token'ı üretmez. Token'ı yine bir çözücüden alır ve tam da yukarıda gösterildiği gibi forma yazarsınız. İkisini de çalıştırın: UC mode ne sıklıkta doğrulamayla karşılaştığınızı azaltır, çözücü ise karşılaştığınız doğrulamaları temizler.

Bunu CI'da headless çalıştırabilir miyim?

Evet, çünkü çözüm tarayıcıya hiç dokunmaz. SB'ye headless geçirin ya da bayrağı pytest komut satırına ekleyin; üç adım değişmeden kalır. Headless bir runner'da ayakta kalmayan kısım, gerçek bir fare imleci süren ve bir masaüstü oturumu ya da sanal ekran isteyen UC mode GUI tıklamasıdır.

Testlerim bir Linux runner'ında çalışıyor. Çözücü nereye gider?

Kontrol ettiğiniz bir Windows makinesine, Server modunda erişilecek şekilde. CapSkip bir Windows uygulamasıdır; dolayısıyla desen şudur: bir Windows makinesinde tek bir çözücü örneği ve API üzerinden ona bağlanan istediğiniz kadar runner. Runner'da CAPSKIP_HOST'u ayarlayın; testte başka hiçbir şey değişmez.

Çözümün tarayıcımla eşleşmesi için proxy'ye ihtiyacım var mı?

Bazen, ve bu reCAPTCHA, Turnstile ve GeeTest için destekleniyor. Bir tür ve bir URI içeren proxy sözlüğü geçirin; çözüm onun üzerinden yapılır. Bu, site token ile oturumun aynı adresten gelmesini önemsediğinde fark yaratır. Görsel CAPTCHA'lar proxy almaz, çünkü onlarla ilgili hiçbir şey bir ağ yoluna bağlı değildir.

Kısa özet

Sitekey'i get_attribute ile okuyun, token'ı alın, gizli yanıt alanına yazın, gönderin. Token taze kalsın diye çözümü gönderimle aynı adımda tutun ve paket her yerde aynı çalışsın diye host'u bir ortam değişkeninde tutun. Daha geniş Selenium tablosu için şuraya bakın: Selenium CAPTCHA çözücü sayfası, v2'ye özgü ayrıntılar için ise şuraya bakın: reCAPTCHA v2 çözücü sayfası. Geriye maliyet kalıyor; her commit'te çalışan bir test paketinin en çok canını yaktığı yer de burası: yerel captcha çözücü her çözümün zaten sahip olduğunuz donanımda, sayaç olmadan gerçekleşmesi anlamına gelir; testler ne sıklıkta tetiklenirse tetiklensin.