Windmill Betiğinde (Python) CAPTCHA Nasıl Çözülür

Bir Windmill captcha çözümü, bu entegrasyonun olabileceği kadar küçüktür. Windmill betiğinizin en üstündeki import satırlarını okur, bunları PyPI’ye karşı çözümler ve bir lockfile içinde sabitler; böylece CapSkip SDK’sı kurulum adımı ve requirements dosyası olmadan gelir. Geriye kalan, bir sitekey alıp size bir token döndüren bir main fonksiyonudur. Üzerinde düşünmeye değer kısım kod değil, worker’ın hangi makinede çalıştığıdır; çünkü çözücünün loopback adresinde mi kalacağını yoksa ağınızı mı dinlemesi gerektiğini bu belirler.
Neye ihtiyacınız var
- Kendi sunucunuzda ya da onların bulutunda bir Windmill örneği ve betik dağıtabileceğiniz bir workspace.
- Bir Windows makinesinde çalışan CapSkip. Worker aynı makinede çalışıyorsa Local modu yeterlidir. Worker’lar konteynerlerde ya da başka bir host üzerinde duruyorsa Server moduna geçin.
- Otomatikleştirdiğiniz sitenin sitekey'i ve sayfa URL'si.
- Çözücü anahtarını tutan bir Windmill değişkeni ve adresini tutan bir worker ortam değişkeni.
Import satırı neden kurulumun tamamıdır
Windmill, bir betiği kaydettiğinizde en üst düzey import’ları ayrıştırır, hangi PyPI paketlerine karşılık geldiklerini bulur ve bir lockfile yazan bir bağımlılık işi başlatır. O lockfile betiğin sürümüne iliştirilir; böylece test ettiğiniz dağıtım, altı ay sonra çalışan dağıtımdır. Bakımını yapacağınız bir requirements dosyası yoktur ve worker üzerine elle kurulacak hiçbir şey yoktur.
Yorumlayıcıyı da aynı yerde, betik başlığındaki bir yorum satırıyla sabitleyebilirsiniz. Sürüm istemeyen, dağıtılmış bir betik Python 3.11 üzerinde çalışır.
# py312 # pip install capskip - Windmill resolves this import itself # and locks the version when the script is deployed. from capskip import CapSkip
Adım 1: çözüm betiği
Bir Windmill betiği bir main fonksiyonudur. Argümanları girdi şemasını ve Windmill’in oluşturduğu formu belirler, bu yüzden onlara tip verin. Döndürdüğünüz her şey betiğin sonucudur ve aşağı akıştaki bir flow adımı onu oradan okur.
# py312
# pip install capskip - resolved from this import on save.
import wmill
from capskip import CapSkip
def main(sitekey: str, page_url: str) -> str:
# Host and port come from the worker environment. The key is
# a Windmill variable, so it is stored encrypted and never
# appears in the script body or in the run logs.
solver = CapSkip(
host=wmill.get_variable("u/admin/capskip_host"),
port=8080,
apiKey=wmill.get_variable("u/admin/capskip_key"),
)
result = solver.recaptcha(sitekey=sitekey, url=page_url)
return result["code"] # the token, for the next stepreCAPTCHA v2 için entegrasyonun tamamı budur. Diğer her varyant, fazladan bir anahtar kelimeyle aynı yöntemdir: invisible 1 olarak, enterprise 1 olarak ya da version bir action adıyla birlikte v3 olarak ayarlanır. Turnstile ve GeeTest aynı biçime sahip kendi yöntemlerine sahiptir ve tam parametre listesi şurada: CapSkip API dokümantasyonu.
Elle yazılmış bir yoklama döngüsüne uzanmadan önce SDK hakkında bilinmeye değer iki şey var. Yoklamayı sizin yerinize yapar: sabit bir aralıkta uyumak yerine 250 milisaniyeden başlayıp geri çekilir, ki bu genellikle ham API’nin yayımlanmış bekleme sürelerini geride bırakır. Ve reCAPTCHA, Turnstile ile GeeTest için üst sınırı, recaptchaTimeout ile belirlenen 300 saniyedir. Bu sayı, Adım 4’te betik zaman aşımını ayarlarken önem kazanır.
Adım 2: anahtarı bir Windmill değişkeninde tutun
Windmill birinci sınıf değişkenlere ve gizli değerlere sahiptir ve yukarıdaki betik bunlardan birini doğrudan okur. Bunu yapmanın akışlara daha uygun ikinci bir yolu var: değişkeni referans söz dizimini kullanarak adım argümanı olarak geçirin, Windmill de onu çalışma zamanında çağıranın izinleriyle çözümlesin.
| Değerin bulunduğu yer | Betiğin ona nasıl ulaştığı |
|---|---|
| Bir Windmill gizli değişkeni | Yukarıdaki gibi, betik gövdesinde wmill istemcisiyle okuyun |
| Adım argümanı olarak geçirilen bir Windmill değişkeni | Argümanın değeri olarak dolar-var ve ardından değişken yolunu verin |
| Aynı anda birkaç alan tutan bir Windmill kaynağı | Argümanın değeri olarak dolar-res ve ardından kaynak yolunu verin |
| Worker host’undaki bir ortam değişkeni | Worker’ın onu geçirmesine izin verildikten sonra, süreç ortamından okuyun |
Bu referanslar, listelerin ve iç içe nesnelerin içi dahil olmak üzere özyinelemeli olarak çözümlenir; böylece bir anahtar listesi alan bir adım her elemanda bir referans tutabilir. Çalıştırdığınız her şeyde tek bir anahtarı paylaşmak yerine bu workspace’e kendi çözücü anahtarını verin.
Adım 3: bağlantı modunu worker’ın nerede çalıştığı belirler
Kurulumu asıl şekillendiren soru budur ve betik her iki durumda da aynı göründüğü için yanlış yapmak kolaydır. Bir Windmill worker’ı, aynı anda tek bir betik çalıştıran otonom bir süreçtir. Veritabanının yanındaki bir konteyner, bir VM üzerindeki bir süreç ya da kendi masaüstünüzdeki bir süreç olabilir. Hangisi olursa olsun, SDK çağrısı worker’dan bir soket açar; dolayısıyla çözücünün oradan erişilebilir olması gerekir, başka hiçbir yerden değil.
CapSkip’in tam olarak bunun için iki bağlantı modu var. Local, 127.0.0.1 adresine bağlanır ve yalnızca o cihaza hizmet verir. Server ise ağ adresinize ya da genel IP’nize bağlanır; böylece başka bir makine, bir konteyner host’u ya da barındırılan bir platform aynı Windows makinesine API üzerinden ulaşabilir. Her ikisi de şurada ayarlanır: bağlantı ayarları, ve Server modu yalnızca çözücünün nerede çalıştığını değiştirir. Donanım hâlâ sizindir ve hâlâ ölçümsüzdür.
| Worker’ınızın çalıştığı yer | Hangi mod ve host değeri |
|---|---|
| CapSkip ile aynı Windows makinesinde | Local modu. Host değeri 127.0.0.1 olarak kalır |
| Bir konteynerde ya da kendi ağınızdaki başka bir makinede | Server modu. Host değeri, çözücü makinenin LAN adresidir |
| Windmill’in bulutunda ya da ağınızın dışındaki bir VM’de | Statik genel IP’li Server modu, artı bir güvenlik duvarı kuralı |
Windmill worker’ları Windows üzerinde de çalışır ve loopback adresinde kalmanızı sağlayan durum budur. Orada tek bir ayar önem taşır. PID ad alanı yalıtımı Linux’ta varsayılan olarak true’dur ve Windmill’in kendi belgeleri, Windows worker’ları için bunun false yapılmasını söyler. Bir Windows worker’ında ENABLE_UNSHARE_PID adlı değişkeni false yapın, worker normal şekilde başlar.
Diğer iki satır için adres, betikte değil worker ortamında bulunmalıdır. Windmill her host değişkenini varsayılan olarak bir işe geçirmez; bu yüzden istediklerinizi worker üzerindeki WHITELIST_ENVS adlı değişkende virgülle ayırarak adlandırın. Bir worker grubu da arayüzde ayarlanan kendi statik ve dinamik ortam değişkenlerini taşıyabilir; worker’larınızın yalnızca bir kısmı çözücünün yakınında olduğunda daha derli toplu seçenek budur.
Adım 4: zaman aşımı ve yeniden deneme
Windmill, bir betiğin çalışma zamanı ayarlarında, Cache ve Concurrency limitlerinin yanına bir Timeout alanı koyar. Bunu en yavaş çözümünüzün altına değil, üstüne ayarlayın. Bir reCAPTCHA v2 onay kutusu genellikle bir dakikanın epey altında biter, ama Turnstile doğrulama sayfaları ve GeeTest daha uzun sürer ve SDK, bir TimeoutException ile pes etmeden önce 300 saniyeye kadar yoklamayı sürdürür. Bu değerin altındaki bir betik zaman aşımı, yavaş bir çözümü, günlükte işe yarar hiçbir şey bulunmayan sonlandırılmış bir işe çevirir.
Betik bir akıştaki adım hâline geldiğinde ikinci bir katman kazanırsınız. Windmill akış adımları iki biçimde yeniden dener ve üstel olanı, kısa süreliğine meşgul olan bir çözücüye uygundur.
| Yeniden deneme biçimi | Neyi yapılandırırsınız | Ne zaman kullanılır |
|---|---|---|
| Sabit gecikme | Azami deneme sayısı ve sabit bir gecikme | Ara sıra yeniden başlayan, sabit beklemenin sorun olmadığı bir çözücü |
| Üstel geri çekilme | Azami deneme sayısı, saniye cinsinden bir taban ve bir çarpan | Gerçekten meşgul olabilecek her şey; böylece üzerine gitmek yerine geri çekilirsiniz |
Üstel biçimdeki gecikme, çarpanın, deneme sayısı kuvvetine yükseltilmiş tabanla çarpımıdır; yani 3 tabanı ile 2 çarpanı beş deneme boyunca beklemeleri 6 saniyeden 486 saniyeye kadar yayar. Ayrıca, yeniden denemeler tükendikten sonra akışın devam etmesini sağlayan ve hatayı adım sonucu olarak aktaran bir Continue on error ayarı vardır; başarısız olmak yerine yedeğe düşen bir dal böyle kurulur.
Tam çalışan örnek
Çözen ve gönderen tek bir betik; böylece token bir sonraki adımı bekleyerek ortalıkta durmaz. Bu son nokta üslupla ilgili değil. Bir reCAPTCHA token’ı yaklaşık iki dakika geçerlidir ve bir adımda çözen, sonra bir onay bekleyen, ardından başka bir adımda gönderen bir akış, onu kaybetmenin güvenilir yoludur. Bu konuda daha fazlası şu rehberde: reCAPTCHA token süresinin dolması.
# py312
# pip install capskip requests - both resolved from these imports.
import os
import requests
import wmill
from capskip import CapSkip
from capskip.exceptions import TimeoutException, NetworkException
SITE = "https://example.com/page-with-recaptcha"
def main(sitekey: str, username: str) -> dict:
# CAPSKIP_HOST is set on the worker and allowed through by
# WHITELIST_ENVS. It falls back to the loopback address so the
# same script still runs on a worker that sits next to CapSkip.
solver = CapSkip(
host=os.environ.get("CAPSKIP_HOST", "127.0.0.1"),
port=8080,
apiKey=wmill.get_variable("u/admin/capskip_key"),
)
try:
result = solver.recaptcha(sitekey=sitekey, url=SITE)
except TimeoutException:
# Let the flow's retry policy decide what happens next.
raise
except NetworkException:
raise RuntimeError("CapSkip is unreachable from this worker")
# Submit immediately. The token is short lived, and the field
# name below is the one the page's own form posts.
posted = requests.post(
SITE,
data={
"username": username,
"g-recaptcha-response": result["code"],
},
timeout=30,
)
return {"status": posted.status_code, "captcha_id": result["captchaId"]}Son betik, token yerine captcha id’sini döndürüyor ve bu bilinçli bir tercih. Windmill’in çalıştırma geçmişini sonradan okurken id işe yarar, token ise yaramaz: o zamana kadar süresi dolmuştur ve onu saklanan bir iş sonucuna koymak, günlüklerinize koymak demektir.
Aynı anda birkaç tanesini çözme
Bir Windmill worker’ı, sahip olduğu makinenin tamamını kullanarak aynı anda tek bir betik çalıştırır. Yani buradaki eşzamanlılık, betiğinizin ne yaptığıyla değil, kaç worker çalıştırdığınızla ilgilidir. Bunu elde etmenin iki yolu var ve ikisi birleştirilebilir.
- Daha fazla worker çalıştırın. Bir worker grubu bağımsız olarak ölçeklenebilir ve işler hangi worker boştaysa onun tarafından alınır.
- Tek bir betiğin içinde toplu çözün. Python SDK’sı gerçek bir asenkron istemciyle gelir; böylece tek bir işte birkaç çözüm aynı anda havada olabilir. Bir koşu bir yerine on token gerektirdiğinde bunu yapmaya değer ve bu kalıp şurada anlatılıyor: Python ile CAPTCHA’ları paralel çözme kılavuzu.
Kırılgan olan taraf hedef siteyse betiğe bir eşzamanlılık sınırı koyun. CapSkip’in kendisi ölçümlü değildir, yani bunlardan daha fazlasını çalıştırmanın hiçbir ek maliyeti yoktur; ama otomatikleştirdiğiniz site bunu pekâlâ fark edebilir.
Sık görülen hatalar ve anlamları
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| NetworkException, 8080 portunda bağlantı reddedildi | Worker, CapSkip’in bağlı olduğu makinede değil | Server moduna geçin ve host değişkenini çözücünün adresi olarak ayarlayın |
| Host ortam değişkeni işin içinde boş görünüyor | Worker üzerinde var, ama geçmesine hiç izin verilmemiş | Adını WHITELIST_ENVS’e ekleyin ya da worker grubunda ayarlayın |
| capskip import’unda ModuleNotFoundError | Bağımlılık işi bu sürüm için henüz çalışmadı | Betiği kaydedip dağıtın, sonra bağımlılık işinin bittiğini kontrol edin |
| İş, bir çözümün ortasında sonlandırılıyor | Betik zaman aşımı, çözümün sürdüğü süreden kısa | Betiğin çalışma zamanı ayarlarındaki Timeout değerini 300 saniyenin üzerine çıkarın |
| SDK’dan TimeoutException | Çözüm gerçekten recaptchaTimeout süresini aştı | Akışın yeniden denemesine izin verin ve sitekey ile sayfa URL’sinin doğru olduğunu kontrol edin |
| Yanıtta ERROR_WRONG_USER_KEY | Windmill değişkeni boş, bu yüzden boş bir anahtar gönderildi | Workspace ön eki dahil, değişken yolunu kontrol edin |
| Windows üzerindeki bir worker başlamıyor | Bu worker için PID ad alanı yalıtımı kapatılmamış | O worker üzerinde ENABLE_UNSHARE_PID değerini false yapın |
| Geçerli bir token hedef site tarafından reddediliyor | Çözüm adımı ile gönderim adımı arasında süresi doldu | Tek bir betikte ya da arada bekleme olmayan bitişik adımlarda çözün ve gönderin |
FAQ
CapSkip’i Windmill ile birlikte loopback adresinde tutabilir miyim?
Evet, worker çözücüyle aynı Windows makinesinde çalışıyorsa. Local modunun ayakta kaldığı tek dağıtım biçimi budur ve bunu bilinçli olarak kurmaya değer: çözücü makinesinde özel bir worker çalıştırın, ona kendi worker etiketini verin ve CAPTCHA betiklerini o etikete yönlendirin. Windmill’in bulutu ve herhangi bir konteyner dahil diğer her biçim Server modu gerektirir, çünkü worker başka bir yerdedir.
SDK için bir requirements dosyasına ihtiyacım var mı?
Hayır. Windmill, betik kaydedildiğinde en üst düzey import’ları okur, bunları PyPI paketleriyle eşleştirir ve betiğin o sürümü için bir lockfile üretir. Import satırı, bağımlılık bildiriminin ta kendisidir. Import çalışma zamanında başarısız olursa bakılacak şey bir dosyanın eksik olup olmadığı değil, bağımlılık işinin tamamlanıp tamamlanmadığıdır.
Sonucu akışın kendisi mi yoklamalı?
Tek bir işe sığan bir çözüm için hayır. SDK zaten yoklama yapıyor ve sabit bir aralıkta uyumak yerine 250 milisaniyeden geri çekiliyor; dolayısıyla elle kurulmuş bir bekleme adımları döngüsü hem daha yavaş hem daha fazla kod olur. Akıştan yalnızca gönderme ile toplamayı bilinçli olarak iki adıma böldüyseniz yoklayın; o durumda da bekleme yanıtını adına göre sınayın. Adı, bir T eksik olacak şekilde CAPCHA_NOT_READY yazılır ve bir şeylerin ters gittiği değil, beklemeye devam edin anlamına gelir. Şu kaynak da var: CAPCHA_NOT_READY yanıtının tam açıklaması.
Bu, aynı işi Airflow, Dagster ya da n8n’de yapmakla nasıl karşılaştırılır?
Dördü arasında en az kodu Windmill gerektirir, çünkü bir betik düz bir fonksiyondur ve bağımlılıkları import satırından gelir. Airflow ise bir DAG içinde bir task ister ve üzerine düşünülecek bir zamanlayıcı aralığı vardır; bu şurada ele alınıyor: Airflow CAPTCHA DAG rehberi. Dagster aynı işi bir asset olarak çerçeveler; anlatımı şurada: Dagster anlatımı. n8n bir kod çalıştırma ortamı değil, bir düğüm grafiğidir; bu yüzden n8n rehberi onun HTTP Request düğümü etrafında kurulmuştur. Bağlantı sorusu dördünde de aynıdır.
Kısa özet
SDK’yı bir Windmill betiğinin en üstünde import edin ve bağımlılık işinin onu sabitlemesine izin verin. Çözücü anahtarını bir Windmill değişkenine, adresini de WHITELIST_ENVS’in geçmesine izin verdiği bir worker ortam değişkenine koyun. Bağlantı modunu, sizin nerede oturduğunuzu değil, worker’ın nerede çalıştığını sorarak belirleyin: çözücünün kendi Windows makinesindeki bir worker Local modunda kalır, diğer her şey Server modu gerektirir. Betik zaman aşımını 300 saniyenin üzerine ayarlayın, akış adımına üstel geri çekilme ekleyin ve token’ı onu üreten işin içinde gönderin.
- Python SDK’sının kendisi şurada anlatılıyor: Python CAPTCHA çözücü sayfası.
- Onay kutusu doğrulaması şurada anlatılıyor: reCAPTCHA v2 çözücü sayfası.
- Node.js, PHP ve C# karşılıkları şurada listeleniyor: CAPTCHA çözme SDK sayfası.
Bunu her beş dakikada bir zamanlamadan önce tartmaya değer bir nokta: CapSkip bir yerel captcha çözücü olup zaten sahip olduğunuz donanımda çalışır; dolayısıyla sürekli tetiklenen bir akış ile ara sıra tetiklenen bir akış tam olarak aynı maliyettedir.
