Windows Task Scheduler İşlerinde CAPTCHA Nasıl Çözülür

Windows Task Scheduler’dan CAPTCHA çözmek için sanal ortamınızın python.exe dosyasını doğrudan çalıştıran bir görev kaydedin, betiğe kendi yeniden denemelerini ve HTTP zaman aşımlarını verin ve ters giden geri kalan her şeyi görevin zaman sınırının yakalamasına bırakın. Task Scheduler CAPTCHA kurulumunun tamamı bundan ibarettir; CapSkip aynı bilgisayarda çalışır, bu yüzden barındıracağınız bir kuyruk ve çözüm başına bir maliyet yoktur. Varsayılan ayarlar dört tuzak gizler ve bu rehber her birini ele alır. Çalışma klasörü System32’dir, bu yüzden göreli bir dosya adı başarısız olur. Takılı kalan tek bir çalıştırma zamanlamayı sessizce bitirir. Bir cmd sarmalayıcısı, scheduler görevi sonlandırdığında gerçek Python sürecini çalışır halde bırakır. Ayrıca hata durumunda yeniden başlatma ayarı, hatayla çıkan bir betiği yeniden başlatmaz.
Neye ihtiyacınız var
- reCAPTCHA çözücüsü açık hâlde bir Windows bilgisayarında çalışan CapSkip. CapSkip bir masaüstü uygulamasıdır, bu yüzden görev yalnızca uygulama açıkken çalışır.
- Python 3.10 veya üzeri; CapSkip SDK’sının alt sınırı budur. Aşağıdaki her şey Windows 11 üzerinde, Python 3.14.0 ve capskip 1.3.0 ile, Windows PowerShell 5.1 içinde çalıştırıldı.
- Yönetici olarak açılmamış, sıradan bir PowerShell istemi. Testlerde görevi kaydetmek ve çalıştırmak yönetici onayı gerektirmedi.
- Çözücü için bir adres. Local modunda CapSkip 127.0.0.1 üzerinden yalnızca o cihaza yanıt verir. Server modunda ise ağ adresinizi veya genel IP’nizi dinler, böylece başka bir makinedeki bir görev onu API üzerinden çağırabilir. İkisi de şurada ayarlanır: bağlantı ayarları.
1. Adım: bir iş klasörü ve bir Python ortamı oluşturun
İşi, kendi sanal ortamı olan tek bir klasöre koyun. Görev, bu ortamın içindeki python.exe dosyasını tam yoluyla çalıştıracak; bu yüzden PATH değişkeninizden hiçbir şeye ve etkinleştirilmiş bir kabuğa ihtiyaç duymaz.
# PowerShell: make a job folder with its own Python environment mkdir C:\CapSkipJobs cd C:\CapSkipJobs python -m venv venv .\venv\Scripts\python.exe -m pip install capskip==1.3.0 requests
SDK sürümü sabitlenmiştir, çünkü 2. adımdaki zaman aşımı yaması SDK’nın iç yapısına erişir. Daha yeni bir sürüme geçmeden önce yamayı yeniden test edin. Task Manager her çalıştırma için iki python.exe süreci gösterir: ortamın başlatıcısı ve onun başlattığı gerçek yorumlayıcı. Bu normaldir.
2. Adım: ayarları okuyun, bir dosyaya log yazın ve SDK’ya bir zaman aşımı verin
2. ile 4. adımlar arasındaki kodu, gösterilen sırayla tek bir dosyaya, C:\CapSkipJobs\job.py dosyasına kaydedin. Dosyanın tamamı bu rehberin sonunda yeniden verilmiştir. İş, ayarlarını ortam değişkenlerinden okur ve bunları istemciye kendisi iletir, çünkü SDK onları kendiliğinden okumaz. Ayrıca varsayılan değerleri de vardır, bu yüzden dosya hiçbir kurulum yapmadan çalışır. CAPSKIP_API_KEY yalnızca CapSkip’te API anahtarı doğrulamasını açtıysanız gerekir.
import functools
import logging
import os
import re
import sys
import time
import types
import requests
import capskip.api
from capskip import ApiException, CapSkip, NetworkException, TimeoutException
HOST = os.getenv('CAPSKIP_HOST', '127.0.0.1')
PORT = int(os.getenv('CAPSKIP_PORT', '8080'))
API_KEY = os.getenv('CAPSKIP_API_KEY', 'YOUR_API_KEY')
SITE = os.getenv('SITE_URL', 'https://example.com').rstrip('/')
USER = os.getenv('SITE_USER', 'YOUR_USERNAME')
PASSWORD = os.getenv('SITE_PASSWORD', 'YOUR_PASSWORD')
LOG_FILE = os.getenv('JOB_LOG', r'C:\CapSkipJobs\job.log')
ATTEMPTS = int(os.getenv('JOB_ATTEMPTS', '3'))
PAUSE = int(os.getenv('JOB_PAUSE', '30'))Task Scheduler’da ortam değişkenleri için bir alan yoktur ve bir görev, yalnızca bir terminalde ayarladığınız bir değişkeni görmez. setx ile ayarlanan bir kullanıcı değişkeni ise göreve ulaşır; görev kaydedildikten sonra ayarlanmış olsa bile: bir sonraki çalıştırma onu, oturumu kapatıp açmaya gerek kalmadan alır. Değerler hesabınızın kayıt defterinde düz metin olarak durur ve bir .env dosyasıyla aşağı yukarı aynı gizlilik düzeyindedir.
# Task Scheduler has no environment field. User variables work: # the next run of the task sees them, with no sign-out needed. setx SITE_URL "https://example.com" setx SITE_USER "YOUR_USERNAME" setx SITE_PASSWORD "YOUR_PASSWORD"
Sırada log dosyası ve SDK için bir zaman aşımı var. Task Scheduler bir programın çıktısını atar, bu yüzden print() hiçbir yerde görünmez ve iş bunun yerine mutlak bir yolda bir log dosyasına yazar. Çalışma klasörü ayarlanmadığında görev C:\Windows\System32 içinde çalışır; orada job.log gibi göreli bir dosya adı PermissionError ile başarısız olur.
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)
logging.basicConfig(filename=LOG_FILE, level=logging.INFO,
format='%(asctime)s pid=%(process)d %(levelname)s %(message)s')
log = logging.getLogger('job')
# The SDK sets no HTTP timeouts, so give every CapSkip call one: connect 5 s, read 30 s.
# This reaches into the SDK, so the guard fails loudly if a newer version changes it.
if not hasattr(capskip.api, 'requests'):
log.error('capskip.api.requests is gone: check the timeout patch')
sys.exit(1)
capskip.api.requests = types.SimpleNamespace(
RequestException=requests.RequestException,
post=functools.partial(requests.post, timeout=(5, 30)),
get=functools.partial(requests.get, timeout=(5, 30)))Son satırlar, scheduler’ın çözemeyeceği bir sorunu giderir. CapSkip Python SDK’sı hiçbir HTTP zaman aşımı ayarlamaz; bu yüzden CapSkip bir bağlantıyı kabul edip ardından hiç yanıt vermezse çağrı sonsuza kadar bekler ve recaptchaTimeout ayarı yalnızca yoklamaların arasında devreye girer. Yama, her SDK çağrısına 5 saniyelik bir bağlantı zaman aşımı ve 30 saniyelik bir okuma zaman aşımı verir. Yanıt hiç gelmeyen bir görev gönderimi bu durumda 30 saniye sonra NetworkException olarak başarısız olur. Yanıt hiç gelmeyen bir sonuç yoklaması, recaptchaTimeout süresi dolduktan kısa süre sonra bir TimeoutException ile biter: varsayılan değeri 300 olan ayarla bu 333 saniyedir. Yamanın üstündeki koruma koşulu, daha yeni bir SDK’da bu öznitelik artık yoksa, işin zaman aşımları olmadan çalışmasına izin vermek yerine logda bir satır yazarak işi durdurur. APScheduler ile CAPTCHA çözme rehberi aynı yamayı daha ayrıntılı açıklar.
3. Adım: formu çekin, çözün ve gönderin
İş, giriş sayfasını bir requests Session içinde yükler, CSRF token’ını ve sitekey’i ondan okur ve CapSkip’ten bir token ister. Tek bir Session, CSRF token’ıyla birlikte gelen çerezi taşır. Form gönderimi Referer başlığını da gönderir, çünkü HTTPS üzerinden çalışan Django gibi bazı framework’ler, Referer olmayan bir form gönderimini reddeder. Yolları ve alan adlarını kendi sitenizin kullandıklarıyla değiştirin.
def fetch_login(session):
"""Load the login page: the session cookie, the CSRF token and the sitekey."""
page = session.get(SITE + '/login', timeout=(5, 30))
if page.status_code != 200:
raise RuntimeError('login page returned HTTP %d' % page.status_code)
csrf = re.search(r'name="csrfmiddlewaretoken" value="([^"]+)"', page.text)
key = re.search(r'data-sitekey="([^"]+)"', page.text)
if not csrf or not key:
raise RuntimeError('login page has no CSRF token or no sitekey')
return csrf.group(1), key.group(1)
def solve(sitekey):
solver = CapSkip(apiKey=API_KEY, host=HOST, port=PORT)
return solver.recaptcha(sitekey=sitekey, url=SITE + '/login')['code']solver.recaptcha, code alanı token olan bir sonuç döndürür. Aşağıdaki gönderim, token’ı diğer form alanlarının yanında g-recaptcha-response alanına koyar. Başarısız bir giriş çoğu zaman 200 durum koduyla ve yine giriş formuyla yanıtlanır; bu yüzden iş, hâlâ bir parola alanı içeren sayfayı da bir ret olarak değerlendirir. Bu testi sitenize uyacak şekilde değiştirin, çünkü reddedilen bir giriş için başarı bildiren bir iş, başarısız olan bir işten daha kötüdür.
def submit(session, csrf, token):
"""Post the login form, the way the browser would, Referer included."""
resp = session.post(SITE + '/login', timeout=(5, 30),
headers={'Referer': SITE + '/login'},
data={'csrfmiddlewaretoken': csrf, 'username': USER,
'password': PASSWORD, 'g-recaptcha-response': token})
# Many sites answer a failed login with 200 and the form again.
if resp.status_code != 200 or 'type="password"' in resp.text:
raise RuntimeError('login rejected: HTTP %d %s' % (resp.status_code, resp.text[:120]))
log.info('login accepted: %s', resp.text[:40])Diğer CAPTCHA türleri için eşleşen SDK metodunu çağırın ve gönderimdeki form alanı adını değiştirin. Python ile reCAPTCHA v2 çözme rehberi aynı çağrıyı sade bir betikte ele alır.
4. Adım: yeniden denemeyi betikte yapın ve bir kodla çıkın
Zamanlanmış bir işin başarısızlık için bir planı olmalıdır ve Task Scheduler’ın kendi yeniden başlatma ayarı böyle bir plan değildir. RestartCount ve RestartInterval, bir görevi yalnızca başlatılamadığında yeniden başlattı: bulunmayan bir program yaklaşık bir ve iki dakika sonra yeniden başlatıldı. 1 ya da 3 koduyla çıkan veya yakalanmamış bir istisnayla çöken bir betik bir kez çalıştı ve hiç yeniden başlatılmadı. Bu yüzden yeniden deneme betiğin içinde yer alır.
def run():
session = requests.Session() # a fresh session means a fresh CSRF token
csrf, sitekey = fetch_login(session)
log.info('solving reCAPTCHA v2, sitekey %s', sitekey)
submit(session, csrf, solve(sitekey))
def is_retryable(exc):
if isinstance(exc, (NetworkException, TimeoutException, requests.RequestException)):
return True
return isinstance(exc, ApiException) and 'UNSOLVABLE' in str(exc)Dört hata yeni bir denemeye değer: CapSkip’in yanıt vermemesi, bir TimeoutException, ERROR_CAPTCHA_UNSOLVABLE (CapSkip bu görevi çözemedi ve yeni bir deneme çözebilir) ve sitenin kendisinin yanıt vermemesi. Reddedilen bir giriş ya da CSRF token’ı olmayan bir sayfa gibi diğer her şey kalıcı bir hatadır, çünkü yeniden deneme aynı hatayı tekrarlar.
def main():
log.info('start, CapSkip at %s:%s, site %s', HOST, PORT, SITE)
for attempt in range(1, ATTEMPTS + 1):
try:
run()
log.info('done, exit 0')
return 0
except Exception as exc:
retry = is_retryable(exc)
log.warning('attempt %d/%d failed, %s: %s: %s', attempt, ATTEMPTS,
'retryable' if retry else 'fatal', type(exc).__name__, exc,
exc_info=not retry)
if not retry:
return 1
if attempt < ATTEMPTS:
time.sleep(PAUSE)
log.error('giving up after %d attempts, exit 3', ATTEMPTS)
return 3
if __name__ == '__main__':
sys.exit(main())İş, aralarında 30 saniye olan en fazla üç deneme yapar ve ardından Task Scheduler’ın Last Run Result olarak gösterdiği bir kodla çıkar.
| Çıkış kodu | Anlamı |
|---|---|
| 0 | Giriş başarılı oldu |
| 1 | Yeniden denemenin düzeltemeyeceği bir hata; traceback logda yer alır |
| 3 | Her deneme, kendiliğinden düzelebilecek bir hataya takıldı |
2 kodu bilerek dışarıda bırakıldı. Python, betik dosyasını açamadığında kendisi 2 koduyla çıkar; bu yüzden Last Run Result içindeki bir 2 belirsiz olurdu.
Aynı döngü henüz açılmamış bir CapSkip’i de kapsar. CapSkip kapalıyken bir deneme yaklaşık 2 saniyede başarısız olur. Çözücünün ve sitenin ikisinin de geç açıldığı bir testte ilk deneme başarısız oldu, 30 saniye sonraki ikinci deneme ise başarılı oldu. İşin bir zamanlamaya göre değil, oturum açıldığında başlamasını istiyorsanız, kendi hesabınız için bir oturum açma tetikleyicisi yönetici hakları olmadan kaydedilir ve gecikme tanımlamaya izin verir; bir dakikalık gecikme sorunsuz kaydedildi.
5. Adım: görevi kaydedin
Bu PowerShell betiği görevi geçerli kullanıcı için kaydeder. İçindeki hiçbir şey yönetici olarak açılmış bir istem gerektirmez.
$python = 'C:\CapSkipJobs\venv\Scripts\python.exe'
$jobDir = 'C:\CapSkipJobs'
$action = New-ScheduledTaskAction -Execute $python `
-Argument ('"{0}\job.py"' -f $jobDir) -WorkingDirectory $jobDir
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) `
-RepetitionInterval (New-TimeSpan -Hours 1)
$settings = New-ScheduledTaskSettingsSet `
-ExecutionTimeLimit (New-TimeSpan -Minutes 30) `
-MultipleInstances IgnoreNew `
-StartWhenAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName 'CapSkip login job' -Action $action `
-Trigger $trigger -Settings $settings -ForceHer bölümün orada olmasının bir nedeni var.
- Eylem, ortamın python.exe dosyasını doğrudan çalıştırır; betik tırnak içinde mutlak bir yol, iş klasörü ise çalışma klasörü olarak verilir. Önüne cmd /c ya da bir .bat dosyası koymayın. Nedenini, zaman sınırının gerçekte neyi durdurduğunu anlatan bölüm gösterir.
- Tetikleyici şu andan bir dakika sonra çalışır, ardından her saat yinelenir; bitiş tarihi yoktur.
- Zaman sınırı 30 dakikadır. Varsayılan değer 72 saat, yani üç gündür. Bir çalıştırmanın alabileceği en uzun süre yaklaşık 18 dakikaya çıkar: her biri sessiz kalan bir CapSkip’i 333 saniye boyunca sonuna kadar bekleyen üç deneme, artı iki adet 30 saniyelik bekleme. Otuz dakika buna yer bırakır ve takılı kalan bir çalıştırmayı yine de aynı sabah serbest bırakır.
- IgnoreNew, birden fazla örnek için zaten varsayılandır. Seçim görünür olsun diye açıkça yazılmıştır.
- Varsayılan olarak bir görev pil gücüyle çalışırken başlamaz ve bilgisayar pile geçtiğinde durur. AllowStartIfOnBatteries ve DontStopIfGoingOnBatteries ikisini de kapatır; bu, bir dizüstü bilgisayarda önemlidir. StartWhenAvailable, scheduler’ın, örneğin bilgisayar uykudayken kaçırdığı bir çalıştırmayı mümkün olur olmaz başlatmasını sağlar. Microsoft her seçeneği şurada belgeler: New-ScheduledTaskSettingsSet başvuru belgesi.
- Görev sizin adınıza, yalnızca oturumunuz açıkken çalışır. Bu, oturumunuzda çalışan bir masaüstü uygulaması olan CapSkip için uygundur.
Bir seçim daha python.exe ile pythonw.exe arasındadır. Bu testlerde kullanılan Windows 11 bilgisayarında python.exe görünür bir pencere açmadı, yalnızca gizli bir konsol ana bilgisayarı (conhost) açtı. pythonw.exe için hiç konsol yoktur, bu yüzden sys.stdout ve sys.stderr değerleri None olur: print() hiçbir şey yapmaz, sys.stderr.write bir AttributeError fırlatır ve yakalanmamış bir istisna hiçbir yerde iz bırakmaz. İş bir dosyaya log yazdığı için ikisiyle de çalışır. Yalnızca bilgisayarınızda bir konsol penceresi görünürse pythonw.exe kullanmaya geçin.
6. Adım: çalıştırın ve sonucu okuyun
Aşağıdaki blok görevi elle başlatır, artık çalışmayana kadar bekler, ardından görevin nasıl bittiğini ve işin neyi logladığını gösterir.
# Run the task now instead of waiting for the trigger
Start-ScheduledTask -TaskName 'CapSkip login job'
Start-Sleep -Seconds 2
# Wait until it is no longer running
while ((Get-ScheduledTask -TaskName 'CapSkip login job').State -eq 'Running') {
Start-Sleep -Seconds 2
}
# How did it end, and what did the job write?
Get-ScheduledTaskInfo -TaskName 'CapSkip login job' |
Select-Object LastRunTime, LastTaskResult, NextRunTime
Get-Content C:\CapSkipJobs\job.log -Tail 6Last Run Result bir sayıdır. Karşılaşacağınız değerler şunlardır.
| LastTaskResult | Onaltılık | Anlamı |
|---|---|---|
| 0 | 0x0 | İş 0 koduyla çıktı |
| 1 | 0x1 | İş 1 koduyla çıktı ya da yakalanmamış bir istisnayla çöktü |
| 3 | 0x3 | İş, denemelerinin ardından 3 koduyla çıktı |
| 267009 | 0x41301 | Görev şu anda çalışıyor |
| 267011 | 0x41303 | Görev henüz çalışmadı |
| 267014 | 0x41306 | Scheduler görevi zaman sınırında ya da Stop-ScheduledTask ile durdurdu |
| 2147946720 | 0x800710E0 | Bir çalıştırma hâlâ sürdüğü için bir tetikleyici yok sayıldı |
| 2147942402 | 0x80070002 | Program yolu mevcut değil |
Takılı kalan tek bir çalıştırma neden tüm zamanlamayı durdurur
Varsayılan ayarların en kötü hâle getirdiği hata budur. Birden fazla örnek için varsayılan ilke IgnoreNew’dur, bu yüzden önceki çalıştırma hâlâ sürerken zamanı gelen bir tetikleyici düşürülür. Varsayılan zaman sınırı 72 saattir. Bu ikisi birlikte, hiç bitmeyen tek bir çalıştırmanın zamanlamayı üç gün boyunca engellediği anlamına gelir.
Bir testte iş, zaman aşımı yaması olmadan, bağlantıyı kabul edip hiç yanıt vermeyen bir CapSkip’e karşı ve her dakika bir tetikleyiciyle çalıştırıldı. Görev, izlenen beş dakika boyunca Running durumunda kaldı. İş logunda bir başlangıç satırı vardı ve ondan sonra hiçbir şey yoktu. Bu sırada LastRunTime her dakika ileri gitti ve LastTaskResult, bir örnek hâlâ çalıştığı için yok sayılan bir tetikleyicinin kodu olan 0x800710E0 değerine geçti. Görev canlı görünüyordu ve sayı, takılı kalan çalıştırmayı değil, atlanan tetikleyiciyi işaret ediyordu. Task Scheduler’ın kendi geçmiş logu varsayılan olarak kapalıdır; bu yüzden elinizdeki tek kayıt, işinizin logudur.
Bunu üç katman önler ve her biri diğerlerinin kaçırdığını yakalar. SDK zaman aşımı, takılı kalan bir CapSkip çağrısını 30 ile 333 saniye içinde sonlandırır. Yeniden deneme döngüsü bunu başka bir denemeye ya da temiz bir 3 koduyla çıkışa dönüştürür. Zaman sınırı, aklınıza gelmeyen takılma için son güvenlik ağıdır. Üçü de yerindeyken, görev gönderimine hiç yanıt vermeyen bir CapSkip, işi yaklaşık 152 saniye sonra 3 koduyla bitirdi: üç adet 30 saniyelik zaman aşımı ve iki bekleme. Sonuç yoklamalarına hiç yanıt vermeyen bir CapSkip ise deneme başına en fazla 333 saniyeye mal olur; 30 dakikalık sınır bunu yine de karşılar.
Zaman sınırı gerçekte neyi durdurur
Zaman sınırı hassastır. Bir dakikalık sınır çalıştırmayı 60.2 saniyede sonlandırdı; Task Scheduler 30 saniyelik bir sınırı da kabul etti ve 30.5 saniyede sonlandırdı. Neyi sonlandırdığı, eylemin yapısına bağlıdır.
| Action | Sınırda sonlandırılan | Sonrasında hâlâ çalışan |
|---|---|---|
| Ortamın python.exe dosyası | Başlatıcı ve yorumlayıcı | Hiçbir şey |
| cmd /c python job.py | cmd.exe | Başlatıcı ve yorumlayıcı; CapSkip ile bağlantılarını hâlâ tutuyorlar |
| python çalıştıran bir .bat dosyası | cmd.exe | Başlatıcı ve yorumlayıcı; CapSkip ile bağlantılarını hâlâ tutuyorlar |
Aynı ayrım Stop-ScheduledTask ile de ortaya çıktı. Bu, bir CAPTCHA işi için önemlidir, çünkü yetim kalmış bir süreç CapSkip ile bağlantısını açık tutar. Sarmalayıcıların daha küçük tuzakları da vardır. Yönlendirme içeren bir cmd /c satırı fazladan bir dış tırnak çiftine ihtiyaç duyar, yoksa iş hiçbir şey loglamadan 1 koduyla çıkar; ayrıca yönlendirme hedefi mutlak bir yol olmalıdır. Son satırı echo olan bir .bat dosyası, Python ne döndürürse döndürsün 0 bildirir, bu yüzden dosyayı exit /b %ERRORLEVEL% ile bitirin. Unregister-ScheduledTask da sürmekte olan bir çalıştırmayı durdurmaz, bu yüzden önce Stop-ScheduledTask çağırın.
Tam iş
İşte job.py dosyasının altı bloğu bir arada. Dosyayı, görevin işaret ettiği yol olan C:\CapSkipJobs\job.py olarak kaydedin.
import functools
import logging
import os
import re
import sys
import time
import types
import requests
import capskip.api
from capskip import ApiException, CapSkip, NetworkException, TimeoutException
HOST = os.getenv('CAPSKIP_HOST', '127.0.0.1')
PORT = int(os.getenv('CAPSKIP_PORT', '8080'))
API_KEY = os.getenv('CAPSKIP_API_KEY', 'YOUR_API_KEY')
SITE = os.getenv('SITE_URL', 'https://example.com').rstrip('/')
USER = os.getenv('SITE_USER', 'YOUR_USERNAME')
PASSWORD = os.getenv('SITE_PASSWORD', 'YOUR_PASSWORD')
LOG_FILE = os.getenv('JOB_LOG', r'C:\CapSkipJobs\job.log')
ATTEMPTS = int(os.getenv('JOB_ATTEMPTS', '3'))
PAUSE = int(os.getenv('JOB_PAUSE', '30'))
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)
logging.basicConfig(filename=LOG_FILE, level=logging.INFO,
format='%(asctime)s pid=%(process)d %(levelname)s %(message)s')
log = logging.getLogger('job')
# The SDK sets no HTTP timeouts, so give every CapSkip call one: connect 5 s, read 30 s.
# This reaches into the SDK, so the guard fails loudly if a newer version changes it.
if not hasattr(capskip.api, 'requests'):
log.error('capskip.api.requests is gone: check the timeout patch')
sys.exit(1)
capskip.api.requests = types.SimpleNamespace(
RequestException=requests.RequestException,
post=functools.partial(requests.post, timeout=(5, 30)),
get=functools.partial(requests.get, timeout=(5, 30)))
def fetch_login(session):
"""Load the login page: the session cookie, the CSRF token and the sitekey."""
page = session.get(SITE + '/login', timeout=(5, 30))
if page.status_code != 200:
raise RuntimeError('login page returned HTTP %d' % page.status_code)
csrf = re.search(r'name="csrfmiddlewaretoken" value="([^"]+)"', page.text)
key = re.search(r'data-sitekey="([^"]+)"', page.text)
if not csrf or not key:
raise RuntimeError('login page has no CSRF token or no sitekey')
return csrf.group(1), key.group(1)
def solve(sitekey):
solver = CapSkip(apiKey=API_KEY, host=HOST, port=PORT)
return solver.recaptcha(sitekey=sitekey, url=SITE + '/login')['code']
def submit(session, csrf, token):
"""Post the login form, the way the browser would, Referer included."""
resp = session.post(SITE + '/login', timeout=(5, 30),
headers={'Referer': SITE + '/login'},
data={'csrfmiddlewaretoken': csrf, 'username': USER,
'password': PASSWORD, 'g-recaptcha-response': token})
# Many sites answer a failed login with 200 and the form again.
if resp.status_code != 200 or 'type="password"' in resp.text:
raise RuntimeError('login rejected: HTTP %d %s' % (resp.status_code, resp.text[:120]))
log.info('login accepted: %s', resp.text[:40])
def run():
session = requests.Session() # a fresh session means a fresh CSRF token
csrf, sitekey = fetch_login(session)
log.info('solving reCAPTCHA v2, sitekey %s', sitekey)
submit(session, csrf, solve(sitekey))
def is_retryable(exc):
if isinstance(exc, (NetworkException, TimeoutException, requests.RequestException)):
return True
return isinstance(exc, ApiException) and 'UNSOLVABLE' in str(exc)
def main():
log.info('start, CapSkip at %s:%s, site %s', HOST, PORT, SITE)
for attempt in range(1, ATTEMPTS + 1):
try:
run()
log.info('done, exit 0')
return 0
except Exception as exc:
retry = is_retryable(exc)
log.warning('attempt %d/%d failed, %s: %s: %s', attempt, ATTEMPTS,
'retryable' if retry else 'fatal', type(exc).__name__, exc,
exc_info=not retry)
if not retry:
return 1
if attempt < ATTEMPTS:
time.sleep(PAUSE)
log.error('giving up after %d attempts, exit 3', ATTEMPTS)
return 3
if __name__ == '__main__':
sys.exit(main())CapSkip’i başka bir makinede çalıştırmak
Görevin 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 dinlemeye başlar. Ardından işi ona yönlendirin. Aşağıdaki setx satırı bir sonraki çalıştırmada devreye girer.
# Only if CapSkip runs in Server mode on another Windows PC setx CAPSKIP_HOST "192.168.1.50" # Only if API key validation is switched on in CapSkip setx CAPSKIP_API_KEY "YOUR_API_KEY"
Rota internetten geçiyorsa statik bir genel IP kullanın ve API anahtarı doğrulamasını açıp aynı anahtarı CAPSKIP_API_KEY içinde de verin. CapSkip, Server modu başladığında portunu her adrese açar; bu yüzden erişimi beklediğiniz makinelerle sınırlamak için diğerlerine yönelik bir Windows Firewall engelleme kuralı ekleyin. Çözücü hâlâ sizin kendi Windows makinenizdir ve çözüm başına ücretlendirme hâlâ yoktur.
Sık görülen Task Scheduler CAPTCHA hataları
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| Görev durumu saatlerce Running olarak kalıyor | Bir çağrı takılı kaldı ve 72 saatlik varsayılan sınır çok uzakta | SDK zaman aşımını ve dakikalarla ölçülen bir zaman sınırını ekleyin |
| Her tetikleyicide 2147946720 (0x800710E0) | Bir çalıştırma hâlâ sürerken tetikleyiciler yok sayılıyor | İş logunun son satırını okuyun, ardından takılmayı giderin |
| 2147942402 (0x80070002) | Program yolu mevcut değil | Ortamın python.exe dosyasının tam yolunu kullanın |
| Last Run Result 2 ve boş bir log | Python job.py dosyasını açamadı; genellikle çalışma klasörü olmayan göreli bir yol yüzünden | Eyleme mutlak bir betik yolu ve bir çalışma klasörü verin |
| job.log üzerinde PermissionError | Göreli bir dosya adı C:\Windows\System32 içinde çözümlendi | Mutlak yollar kullanın |
| Her çalıştırmada 3 koduyla çıkış | CapSkip çalışmıyor, host ya da port yanlış veya her çözüm başarısız oldu | Logun ilk satırını ve bağlantı ayarlarındaki adresi kontrol edin |
| 267014 (0x41306) | Scheduler çalıştırmayı zaman sınırında durdurdu | Logun nerede bittiğini bulun ve o çağrıyı düzeltin |
| Ayarlar işin içinde eksik | Değişkenler yalnızca bir terminalde ayarlandı | Onları setx ile ayarlayın ya da varsayılanları dosyada tutun |
| Durdurmadan sonra iki python.exe süreci kalıyor | Eylem cmd /c ya da bir .bat dosyası | Eylem olarak python.exe çalıştırın |
FAQ
Oturumum kapalıyken görev çalışabilir mi?
Oturum açık olsun ya da olmasın çalışan ve saklanmış parolası olmayan bir görevi kaydetmek, yönetici olarak açılmamış bir PowerShell isteminden testte Access is denied (0x80070005) hatasıyla başarısız oldu. Saklanmış parolayla bir görev kaydetmek denenmedi, standart bir kullanıcı hesabı da denenmedi. Her iki durumda da CapSkip’in yanıt verebilmesi için açık olması gerekir ve o bir masaüstü uygulamasıdır; bu yüzden olağan kurulum, oturumunuzu açık bıraktığınız bir bilgisayardır. Çözücüye kimsenin kullanmadığı bir makinede ihtiyacınız varsa CapSkip’i orada Server modunda çalıştırın ve işi ona yönlendirin.
Sonraki tetikleyici, yok sayılmak yerine takılı kalan bir çalıştırmanın yerini alabilir mi?
Evet, StopExisting ilkesiyle. New-ScheduledTaskSettingsSet yalnızca Parallel, Queue ve IgnoreNew seçeneklerini sunar, bu yüzden değeri ayarlar nesnesinde elle belirleyin:
# New-ScheduledTaskSettingsSet cannot set this policy, so set it on the # $settings object from Step 5 by hand, then update the task. $settings.CimInstanceProperties['MultipleInstances'].Value = 3 Set-ScheduledTask -TaskName 'CapSkip login job' -Settings $settings
Dışa aktarılan görev bundan sonra StopExisting değerini gösterir. Eylem python.exe olduğunda her tetikleyici eski çalıştırmayı sonlandırdı ve yenisini başlattı. Eylem cmd /c olduğunda her sonlandırma geride yetim bir süreç bıraktı. Parallel, takılı kalan çalıştırma yerinde dururken her dakika yeni bir çalıştırma başlattı; Queue ise onun arkasında beklemeye devam etti.
Bu, derlenmiş bir C# programı için de çalışır mı?
Scheduler tarafı aynıdır. Eylemi exe dosyanıza yönlendirin, çalışma klasörünü ayarlayın, zaman sınırını koruyun ve mutlak bir log yolu kullanın. Yeniden denemeler ve çıkış kodları bu durumda kendi kodunuza aittir. Program, bir zamanlamaya göre başlatılmak yerine gün boyu çalışmalıysa, Worker Service (.NET) ile CAPTCHA çözme rehberi bu yapıyı ele alır.
Ne zaman bir kuyruk, Task Scheduler’dan daha uygundur?
İşi başka bir kod oluşturduğunda ya da her iş parçasının bir çökmeye dayanması ve kendi başına yeniden denenmesi gerektiğinde. Task Scheduler bir zamanlamaya göre yeni bir süreç başlatır ve tek tek işler hakkında hiçbir şey bilmez. Huey gibi bir kuyruk her görevi bir dosyada tutar ve yeniden dener; Huey görevlerinde CAPTCHA çözme rehberi Windows’ta tek bir SQLite dosyasıyla çalışan bir kurulumu gösterir.
Kısa özet
Bir Task Scheduler CAPTCHA işi, çözümün kendisinden fazlasına ihtiyaç duyar. Ortamın python.exe dosyasını doğrudan çalıştırın; bir çalışma klasörü, mutlak bir log yolu ve mutlak bir betik yolu verin. SDK’nın HTTP çağrılarına bir zaman aşımı verin ve yeniden denemeyi betiğin içinde yapın, çünkü yeniden başlatma ayarı çıkış kodlarını yok sayar. Dakikalarla ölçülen bir yürütme zaman sınırı ayarlayın, çünkü 72 saatlik varsayılan değer, takılı kalan tek bir çalıştırmanın sonraki her tetikleyiciyi engellemesine yol açar.
- Python paketinin desteklediği tüm CAPTCHA türleri: Python CAPTCHA çözücü sayfası.
- Onay kutulu reCAPTCHA’nın nasıl çalıştığı ve çözücünün neleri kapsadığı: reCAPTCHA v2 çözücü sayfası.
Her saat çalışan bir iş, ayda yaklaşık 720 çözüm yapar. Bunları kendi Windows makinenizde çalışan bir yerel captcha çözücü üzerinden yürütmek, bu sayının asla bir faturaya dönüşmemesi demektir.
