Tutorials

Izgara Görüntüsü CAPTCHA: Koordinat Haritalama ve Hücre Seçimi

CaptchaAI bir ızgara CAPTCHA'yı çözdüğünde size tıklanması gereken hücrelerin indekslerini döndürür — örneğin [1, 3, 6, 9]. Asıl iş bundan sonra başlar: bu numaraları tarayıcıda gerçek piksel tıklamalarına çevirmek. reCAPTCHA v2 görüntü zorlukları gibi ızgaralar 3×3 veya 4×4 gelir ve "Trafik ışığı olan tüm kareleri seçin" tarzı bir talimat gösterir. Bu rehber ızgarayı yakalamayı, indeksleri koordinatlara haritalamayı ve doğru döşemelere tıklamayı sırasıyla ele alır.

Bu akış, form ve ödeme adımı yoğun Türk e-ticaret ve fintech sitelerinin QA testlerinde sık karşınıza çıkar.

Sırasıyla dört adımı uygulayacağız:

  • Izgarayı yakalama: challenge iframe'ine geçip görseli ve talimat metnini alın.
  • CaptchaAI'ye gönderme: base64 görseli in.php'ye yollayın, sonucu res.php üzerinden sorgulayın.
  • Indeks → koordinat: dönen hücre indekslerini piksel merkezlerine çevirin.
  • Tıklama ve doğrulama: hesaplanan koordinatlara tıklayıp doğrula düğmesine basın.

Izgara boyutları ve hücre numaralandırması

CAPTCHA'lar iki standart ızgara boyutu kullanır:

3×3 Grid:          4×4 Grid:
1  2  3            1   2   3   4
4  5  6            5   6   7   8
7  8  9            9  10  11  12
                   13  14  15  16

Hücreler soldan sağa, yukarıdan aşağıya numaralandırılır; bu sıra, CaptchaAI indekslerinin temelidir.

Neden numaralandırma sırası önemli?

Bu numaralandırma sözleşmesi kritiktir: CaptchaAI [1, 3, 6, 9] gibi bir dizi döndürdüğünde bu sayılar tam olarak yukarıdaki şemadaki konumlara karşılık gelir. Sıralamayı yanlış varsayarsanız doğru döşemeleri değil komşularını tıklarsınız. Bu yüzden ilk iş, karşınızdaki ızgaranın 3×3 mü yoksa 4×4 mü olduğunu kesinleştirmektir — kod bunu rc-image-tile-33 / rc-image-tile-44 sınıf adından okur.


Adım 1: Izgara görüntüsünü yakalayın

Challenge iframe'ine geçin, talimat metnini ve ızgara görselini alın, ardından boyutu (3×3 mü 4×4 mü) sınıf adından belirleyin. Bu aşamada sayfadan üç şeyi çıkarırsınız:

  • Ana sayfadaki reCAPTCHA çerçevesinin son iframe'i olan challenge iframe'i.
  • .rc-imageselect-desc-wrapper içindeki talimat metni.
  • img.rc-image-tile-33 / img.rc-image-tile-44 görselinin base64 ekran görüntüsü.

Python (Selenium)

import base64
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get("https://example.com/form")

# Wait for reCAPTCHA iframe
WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, "iframe[src*='recaptcha']"))
)

# Switch to challenge iframe
iframes = driver.find_elements(By.CSS_SELECTOR, "iframe[src*='recaptcha']")
challenge_iframe = iframes[-1]  # Challenge iframe is typically the last one
driver.switch_to.frame(challenge_iframe)

# Get the grid image
grid_img = driver.find_element(By.CSS_SELECTOR, "img.rc-image-tile-33, img.rc-image-tile-44")
img_src = grid_img.get_attribute("src")

# Get instruction text
instruction = driver.find_element(
    By.CSS_SELECTOR, ".rc-imageselect-desc-wrapper"
).text
print(f"Instruction: {instruction}")

# Screenshot the grid as base64
img_b64 = grid_img.screenshot_as_base64

# Determine grid size
classes = grid_img.get_attribute("class")
grid_size = "4x4" if "44" in classes else "3x3"
print(f"Grid size: {grid_size}")

driver.switch_to.default_content()

JavaScript (Puppeteer)

const puppeteer = require('puppeteer');
const fs = require('fs');

const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');

// Find the challenge iframe
const frames = page.frames();
const challengeFrame = frames.find(f => f.url().includes('recaptcha'));

// Get instruction
const instruction = await challengeFrame.$eval(
  '.rc-imageselect-desc-wrapper',
  el => el.textContent.trim()
);

// Screenshot the grid image
const gridImg = await challengeFrame.$('img.rc-image-tile-33, img.rc-image-tile-44');
const imgBuffer = await gridImg.screenshot();
const imgBase64 = imgBuffer.toString('base64');

// Determine grid size
const className = await challengeFrame.$eval(
  'img.rc-image-tile-33, img.rc-image-tile-44',
  el => el.className
);
const gridSize = className.includes('44') ? '4x4' : '3x3';
console.log(`Grid: ${gridSize}, Instruction: ${instruction}`);

Bu adımdan üç çıktı taşırsınız: img_b64 (çözücüye göndereceğiniz görsel), instruction (hangi nesnenin seçileceği) ve grid_size. Üçü de bir sonraki isteğin girdisidir; herhangi biri eksik ya da yanlışsa çözüm ya reddedilir ya da yanlış hücreler döner.


Adım 2: Görüntüyü CaptchaAI'ye gönderin

Base64 görselini in.php'ye gönderin, dönen görev kimliğini res.php üzerinden sorgulayın. Talimattaki anahtar kelimeyi (örneğin traffic lights) instructions alanına koyun.

instructions alanı çözücüye ne aradığını söyler; talimat cümlesinden yalnızca anahtar nesneyi ("traffic lights", "crosswalks", "buses") ayıklayıp gönderin. grid_size alanını da eklediğinizde yanıt, o boyuta uygun aralıkta indeks döndürür (3×3 için 1–9, 4×4 için 1–16).

Sonucu sorgulama

Sonuç hazır olana kadar res.php'yi birkaç saniyede bir sorgularsınız; CAPCHA_NOT_READY yanıtı "henüz hazır değil, beklemeye devam edin" demektir. Görev tamamlandığında status alanı 1 döner ve request içinde hücre indeksleri gelir.

import requests
import time
import json

API_KEY = "YOUR_API_KEY"

# Parse the instruction to a simple keyword
# "Select all images with traffic lights" → "traffic lights"
import re
keyword_match = re.search(r'(?:with|of|containing)\s+(.+?)\.?$', instruction, re.I)
keyword = keyword_match.group(1) if keyword_match else instruction

# Submit
with open("/tmp/grid.png", "wb") as f:
    f.write(base64.b64decode(img_b64))

with open("/tmp/grid.png", "rb") as f:
    resp = requests.post("https://ocr.captchaai.com/in.php", 
        files={"file": f},
        data={
            "key": API_KEY,
            "method": "post",
            "grid_size": grid_size,
            "img_type": "recaptcha",
            "instructions": keyword,
            "json": "1",
        }
    ).json()

if resp["status"] != 1:
    raise Exception(f"Submit error: {resp['request']}")

task_id = resp["request"]

# Poll
for _ in range(20):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY, "action": "get", "id": task_id, "json": "1"
    }).json()

    if result["status"] == 1:
        cells = json.loads(result["request"])
        print(f"Cells to click: {cells}")  # e.g., [1, 3, 6, 9]
        break
    if result["request"] != "CAPCHA_NOT_READY":
        raise Exception(f"Error: {result['request']}")

Adım 3: Hücre indekslerini koordinatlara haritalayın

CaptchaAI'nin döndürdüğü 1 tabanlı indeksleri ızgara içindeki piksel merkezlerine çevirin: indeksi satır ve sütuna ayırın, hücre boyutuyla çarpın, ortaya hizalayın. Formülün mantığı üç parçadan oluşur:

  • Satır/sütun: indeksten 1 çıkarın; sütun idx % sütun_sayısı, satır idx // sütun_sayısı olur.
  • Hücre boyutu: ızgara genişliğini ve yüksekliğini sütun/satır sayısına bölün.
  • Merkez: hücrenin sol üst köşesine yarım hücre ekleyerek ortayı bulun — tıklamanın kenara değil ortaya düşmesi isabeti artırır.
def cell_to_coordinates(cell_index, grid_size, grid_width, grid_height):
    """Convert a 1-based cell index to (x, y) center coordinates."""
    if grid_size == "3x3":
        cols, rows = 3, 3
    else:
        cols, rows = 4, 4

    cell_w = grid_width / cols
    cell_h = grid_height / rows

    # Convert 1-based index to 0-based row/col
    idx = cell_index - 1
    col = idx % cols
    row = idx // cols

    # Center of the cell
    x = col * cell_w + cell_w / 2
    y = row * cell_h + cell_h / 2

    return int(x), int(y)

# Example: grid is 300×300
for cell in cells:
    x, y = cell_to_coordinates(cell, grid_size, 300, 300)
    print(f"Cell {cell} → ({x}, {y})")

Not: ızgara boyutlarını her zaman tarayıcıdan canlı okuyun. reCAPTCHA piksel boyutlarını ekran çözünürlüğüne ve zoom seviyesine göre değiştirebilir; sabit 300×300 varsayımı yalnızca örnek amaçlıdır.

3×3 ızgara için örnek çıktı (300×300 piksel):

Cell 1 → (50, 50)
Cell 3 → (250, 50)
Cell 6 → (250, 150)
Cell 9 → (250, 250)

Adım 4: Hücrelere tıklayın ve doğrulayın

Koordinatları ızgara öğesinin sol üst köşesine göre uygulayın. Selenium'da move_to_element_with_offset ofseti öğenin merkezinden ölçer; bu yüzden hesapladığınız merkez koordinatından ızgaranın yarı genişliğini ve yarı yüksekliğini çıkarırsınız. Puppeteer tarafında ise tabloyu satır/sütun olarak gezip hücreyi doğrudan seçmek daha güvenilirdir — piksel aritmetiği hiç devreye girmez.

Selenium

from selenium.webdriver.common.action_chains import ActionChains

driver.switch_to.frame(challenge_iframe)

# Get grid element position and size
grid_el = driver.find_element(By.CSS_SELECTOR, ".rc-imageselect-target")
grid_rect = grid_el.rect
grid_w = grid_rect["width"]
grid_h = grid_rect["height"]

actions = ActionChains(driver)

for cell in cells:
    x, y = cell_to_coordinates(cell, grid_size, grid_w, grid_h)
    # Click relative to grid element's top-left corner
    actions.move_to_element_with_offset(
        grid_el,
        x - grid_w / 2,  # offset from center
        y - grid_h / 2
    ).click()

actions.perform()

# Click verify
verify_btn = driver.find_element(By.ID, "recaptcha-verify-button")
verify_btn.click()

driver.switch_to.default_content()

Puppeteer

// Click each cell by index
const tableRows = await challengeFrame.$$('table.rc-imageselect-table tr');
for (const cellIdx of cells) {
  const row = Math.floor((cellIdx - 1) / (gridSize === '4x4' ? 4 : 3));
  const col = (cellIdx - 1) % (gridSize === '4x4' ? 4 : 3);
  const cell = (await tableRows[row].$$('td'))[col];
  await cell.click();
  await new Promise(r => setTimeout(r, 200));
}

await challengeFrame.click('#recaptcha-verify-button');

Değişen (dinamik) döşemeleri yönetme

Bazı reCAPTCHA v2 ızgaraları tıkladığınız döşemeyi yenisiyle değiştirir. Tek geçiş yetmez; ızgarayı yeniden yakalayıp çözen kısa bir döngü kurun. Döngünün üç sorumluluğu vardır:

  • Her turda ızgarayı ve talimatı yeniden yakalamak.
  • Yeni indeksler için CaptchaAI'ye tekrar göndermek.
  • Challenge iframe'i kaybolduğunda çözümün tamamlandığını anlamak.

İpucu: tur sayısını makul bir üst sınırla (max_rounds) tutun. Sonsuz döngü, dinamik ızgara hiç bitmediğinde thread'inizi gereksiz meşgul eder.

Yeniden deneme döngüsü

def solve_with_dynamic_tiles(driver, api_key, max_rounds=3):
    for round_num in range(max_rounds):
        driver.switch_to.frame(challenge_iframe)

        # Re-capture grid and instruction
        img_b64 = driver.find_element(
            By.CSS_SELECTOR, "img.rc-image-tile-33"
        ).screenshot_as_base64

        # Submit and get cells (same as above)
        cells = submit_and_poll(api_key, img_b64, "3x3", keyword)

        if not cells:
            break

        # Click cells
        click_cells(driver, cells, "3x3")

        # Click verify
        driver.find_element(By.ID, "recaptcha-verify-button").click()

        driver.switch_to.default_content()
        time.sleep(2)

        # Check if solved (no more challenge iframe)
        try:
            driver.switch_to.frame(challenge_iframe)
            driver.switch_to.default_content()
        except Exception:
            return True  # Solved

    return False

Türk pazarında tipik kullanım ve KVKK notu

Türkiye'deki e-ticaret ve fintech siteleri hesap açma ve sipariş akışlarını sıklıkla reCAPTCHA v2 ile korur; bu akışların uçtan uca QA testlerinde ızgara CAPTCHA en sık karşılaşılan engellerden biridir. Otomasyonu yalnızca yetkili olduğunuz kendi staging ortamlarınızda çalıştırın. Test verileri gerçek kişisel veri içeriyorsa bunların KVKK (Kişisel Verilerin Korunması Kanunu) kapsamına girdiğini unutmayın; mümkün olduğunca +90 telefon ve tr-TR biçiminde üretilmiş sahte veriyle çalışın.


Sorun giderme

Sorun Sebep Düzeltme
Yanlış hücreler döndü Yanlış grid_size Izgaranın 3×3 mü yoksa 4×4 mü olduğunu doğrulayın
Tıklamalar hücreleri ıskalıyor Koordinat ofseti hatalı Izgara öğesinin boyutlarını yeniden ölçün
ERROR_WRONG_FILE_EXTENSION Hatalı görüntü formatı PNG veya JPEG gönderin
Tıkladıktan sonra yeni döşemeler beliriyor Dinamik ızgara Her turdan sonra yeniden çözün

Isabet oranını artırma

Tıklamalar sürekli ıskalıyorsa önce ızgara boyutunu doğrulayın, sonra öğe boyutlarını yeniden ölçün — sabit varsayım değil, canlı rect değerlerini kullanın. Görseli kırpmadan ve yeniden sıkıştırmadan gönderin; ekran görüntüsünü doğrudan base64'e çevirmek en temiz girdiyi verir.


Sık sorulan sorular

Izgara CAPTCHA çözümü ne kadar sürer?

Süre görüntü karmaşıklığına ve sunucu yüküne göre değişir; sonucu res.php üzerinden birkaç saniyede bir sorgulayın, CAPCHA_NOT_READY geldiği sürece bekleyin. Dinamik ızgaralarda süre tur sayısıyla artar.

CaptchaAI hCaptcha ızgaralarını da çözüyor mu?

Hayır. CaptchaAI reCAPTCHA v2 görüntü zorluklarını ve ızgara OCR görevlerini destekler; ancak hCaptcha ve FunCaptcha desteklenmez. Bu akış yalnızca reCAPTCHA v2 tarzı ızgaralar içindir.

Koordinatları piksel piksel tam vermem gerekir mi?

Hayır, hücre merkezine yakın olması yeterlidir. Kod her hücrenin ortasını hedefler; birkaç piksellik sapma sorun çıkarmaz. Asıl belirleyici nokta ızgara boyutunu (grid_size) doğru belirlemektir.

Fiyatlandırma çözüm başına mı hesaplanıyor?

Hayır. CaptchaAI eşzamanlı thread başına faturalandırır; her planda thread başına sınırsız çözüm vardır. BASIC ($15/ay, 5 thread) ile başlayıp hacim büyüdükçe üst planlara geçebilirsiniz. Fiyatlar USD'dir; bu da TL dalgalanmasından bağımsız, öngörülebilir bir maliyet sağlar.

Aynı anda birkaç ızgara CAPTCHA çözebilir miyim?

Eşzamanlı çözüm sayısı planınızın thread sayısına bağlıdır: BASIC ($15/ay, 5 thread) ile aynı anda beş görevi işleyebilirsiniz. Her thread bağımsız çalışır; daha yüksek hacimli QA akışları için üst planlara geçerek eşzamanlılığı artırırsınız.


Izgara CAPTCHA'larını CaptchaAI ile çözmeye başlayın

API anahtarınızı captchaai.com üzerinden alın, örnek kodu iş akışınıza yapıştırın ve ilk ızgara CAPTCHA'nızın hücre indekslerini alın. Planlar thread tabanlı ve USD fiyatlıdır; günlük çözüm sınırı yoktur.


İlgili kılavuzlar

Bu makale için yorumlar devre dışı bırakılmıştır.