{"id":32850,"date":"2025-10-26T16:41:33","date_gmt":"2025-10-26T13:41:33","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=32850"},"modified":"2025-10-26T16:41:33","modified_gmt":"2025-10-26T13:41:33","slug":"puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/","title":{"rendered":"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir?"},"content":{"rendered":"<p><body><\/p>\n<h2>Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir?<\/h2>\n<p>G\u00fcn\u00fcm\u00fcz\u00fcn veri odakl\u0131 d\u00fcnyas\u0131nda, web sitelerinden bilgi toplamak i\u015f zekas\u0131, pazar ara\u015ft\u0131rmas\u0131 ve rekabet analizi gibi bir\u00e7ok alanda kritik bir rol oynamaktad\u0131r. Web scraping, bu veriye programatik olarak eri\u015fmenin temel y\u00f6ntemidir. Ancak, b\u00fcy\u00fck \u00f6l\u00e7ekli ve dinamik web sitelerinden veri \u00e7ekerken tekil bir scraper yetersiz kalabilir. \u0130\u015fte bu noktada e\u015f zamanl\u0131l\u0131k ve \u00f6l\u00e7eklenebilirlik devreye girer.<\/p>\n<p>Bu makalede, modern web scraping ihtiya\u00e7lar\u0131n\u0131 kar\u015f\u0131lamak \u00fczere tasarlanm\u0131\u015f, g\u00fc\u00e7l\u00fc ve \u00f6l\u00e7eklenebilir bir mimariyi ad\u0131m ad\u0131m inceleyece\u011fiz. Node.js&#8217;in asenkron yap\u0131s\u0131ndan yararlanarak Puppeteer ile taray\u0131c\u0131 otomasyonu ger\u00e7ekle\u015ftirecek, Docker ile uygulamam\u0131z\u0131 konteynerize edecek ve son olarak Kubernetes&#8217;in orkestrasyon yetenekleriyle scraper&#8217;\u0131m\u0131z\u0131 y\u00fcksek oranda e\u015f zamanl\u0131 ve hataya dayan\u0131kl\u0131 hale getirece\u011fiz. Bu teknoloji y\u0131\u011f\u0131n\u0131, sadece veri toplamakla kalmayacak, ayn\u0131 zamanda operasyonel verimlilik ve esneklik de sa\u011flayacakt\u0131r.<\/p>\n<h3>Web Scraping ve E\u015f Zamanl\u0131l\u0131k Neden \u00d6nemli?<\/h3>\n<p>Web scraping, web sitelerindeki yap\u0131land\u0131r\u0131lmam\u0131\u015f veriyi yap\u0131land\u0131r\u0131lm\u0131\u015f formata d\u00f6n\u00fc\u015ft\u00fcrme s\u00fcrecidir. Bu s\u00fcre\u00e7, e-ticaret sitelerinden \u00fcr\u00fcn fiyatlar\u0131 \u00e7ekmekten, haber sitelerinden makale ba\u015fl\u0131klar\u0131 toplamaya kadar geni\u015f bir yelpazeyi kapsar. Ancak, modern web siteleri genellikle JavaScript ile dinamik olarak y\u00fcklenen i\u00e7eriklere sahiptir ve geleneksel HTTP istek tabanl\u0131 scraper&#8217;lar bu i\u00e7eri\u011fi g\u00f6remez. Puppeteer gibi taray\u0131c\u0131 otomasyon ara\u00e7lar\u0131 bu sorunu \u00e7\u00f6zerek ger\u00e7ek bir kullan\u0131c\u0131 deneyimini sim\u00fcle etmemizi sa\u011flar.<\/p>\n<p>E\u015f zamanl\u0131l\u0131k ise, birden fazla scraping g\u00f6revini ayn\u0131 anda veya paralel olarak y\u00fcr\u00fctme yetene\u011fidir. Tekil bir scraper, her seferinde bir URL&#8217;yi i\u015flerken, binlerce veya milyonlarca URL&#8217;yi taramak g\u00fcnler hatta haftalar s\u00fcrebilir. E\u015f zamanl\u0131 bir yakla\u015f\u0131m, bu s\u00fcreyi \u00f6nemli \u00f6l\u00e7\u00fcde k\u0131salt\u0131r, kaynak kullan\u0131m\u0131n\u0131 optimize eder ve scraping s\u00fcrecinin genel verimlili\u011fini art\u0131r\u0131r. \u00d6zellikle hedef sitenin talepleri, a\u011f gecikmeleri ve i\u015flem s\u00fcreleri g\u00f6z \u00f6n\u00fcne al\u0131nd\u0131\u011f\u0131nda, e\u015f zamanl\u0131l\u0131k olmadan b\u00fcy\u00fck veri setlerini toplamak pratik de\u011fildir. Ayr\u0131ca, bir g\u00f6revin ba\u015far\u0131s\u0131z olmas\u0131 durumunda di\u011fer g\u00f6revlerin etkilenmemesi ve sistemin genel dayan\u0131kl\u0131l\u0131\u011f\u0131 a\u00e7\u0131s\u0131ndan da e\u015f zamanl\u0131l\u0131k kritik bir fakt\u00f6rd\u00fcr.<\/p>\n<h3>Kullan\u0131lacak Teknolojilere Genel Bak\u0131\u015f<\/h3>\n<p>Bu projenin temelini olu\u015fturan d\u00f6rt ana teknoloji, her biri kendi alan\u0131nda g\u00fc\u00e7l\u00fc yetenekler sunar ve bir araya geldiklerinde sinerjik bir \u00e7\u00f6z\u00fcm olu\u015ftururlar.<\/p>\n<h4>Node.js<\/h4>\n<p>Node.js, JavaScript&#8217;i taray\u0131c\u0131 d\u0131\u015f\u0131nda \u00e7al\u0131\u015ft\u0131rmam\u0131z\u0131 sa\u011flayan a\u00e7\u0131k kaynakl\u0131, sunucu taraf\u0131 bir \u00e7al\u0131\u015fma zaman\u0131 ortam\u0131d\u0131r. Olay d\u00f6ng\u00fcs\u00fc (event loop) tabanl\u0131, engellemeyen (non-blocking) G\/\u00c7 modeli sayesinde, e\u015f zamanl\u0131 i\u015flemler i\u00e7in m\u00fckemmel bir se\u00e7imdir. Web scraper&#8217;lar genellikle a\u011f istekleri ve dosya i\u015flemleri gibi G\/\u00c7 yo\u011fun g\u00f6revler i\u00e7erir. Node.js&#8217;in bu yap\u0131s\u0131, ayn\u0131 anda binlerce ba\u011flant\u0131y\u0131 y\u00f6netebilirken performans d\u00fc\u015f\u00fc\u015f\u00fc ya\u015famadan y\u00fcksek verimli bir scraping motoru olu\u015fturmam\u0131za olanak tan\u0131r. Geni\u015f npm ekosistemi de geli\u015ftirme s\u00fcrecini h\u0131zland\u0131r\u0131r ve bir\u00e7ok kullan\u0131\u015fl\u0131 k\u00fct\u00fcphaneye eri\u015fim sa\u011flar.<\/p>\n<h4>Puppeteer<\/h4>\n<p>Puppeteer, Google taraf\u0131ndan geli\u015ftirilen bir Node.js k\u00fct\u00fcphanesidir ve Chrome veya Chromium gibi headless (ba\u015fs\u0131z) veya tam s\u00fcr\u00fcm taray\u0131c\u0131lar\u0131 bir API arac\u0131l\u0131\u011f\u0131yla kontrol etmemizi sa\u011flar. Bu, JavaScript ile olu\u015fturulan dinamik i\u00e7eri\u011fi i\u015fleyebilen, formlar\u0131 doldurabilen, d\u00fc\u011fmelere t\u0131klayabilen, ekran g\u00f6r\u00fcnt\u00fcleri alabilen ve hatta PDF&#8217;ler olu\u015fturabilen bir scraper in\u015fa edebilece\u011fimiz anlam\u0131na gelir. Geleneksel HTTP k\u00fct\u00fcphanelerinin aksine, Puppeteer ger\u00e7ek bir taray\u0131c\u0131 ortam\u0131n\u0131 taklit ederek, modern web sitelerinin karma\u015f\u0131k yap\u0131lar\u0131yla etkile\u015fime ge\u00e7me yetene\u011fi sunar. Bu, \u00f6zellikle AJAX \u00e7a\u011fr\u0131lar\u0131, tek sayfa uygulamalar\u0131 (SPA&#8217;lar) ve karma\u015f\u0131k DOM manip\u00fclasyonlar\u0131 i\u00e7eren siteler i\u00e7in vazge\u00e7ilmezdir.<\/p>\n<h4>Docker<\/h4>\n<p>Docker, uygulamalar\u0131 ve ba\u011f\u0131ml\u0131l\u0131klar\u0131n\u0131 izole edilmi\u015f, ta\u015f\u0131nabilir birimler olan konteynerler i\u00e7inde paketlemeyi sa\u011flayan bir platformdur. Bir uygulaman\u0131n &#8220;benim makinemde \u00e7al\u0131\u015f\u0131yor&#8221; sorununu ortadan kald\u0131r\u0131r. Scraper&#8217;\u0131m\u0131z i\u00e7in Docker kullanmak, Node.js ve Puppeteer&#8217;\u0131n t\u00fcm ba\u011f\u0131ml\u0131l\u0131klar\u0131n\u0131n (\u00f6rne\u011fin, Chromium&#8217;un ihtiya\u00e7 duydu\u011fu sistem k\u00fct\u00fcphaneleri) tek bir imajda toplanmas\u0131n\u0131 sa\u011flar. Bu, geli\u015ftirme ortam\u0131ndan \u00fcretim ortam\u0131na kadar tutarl\u0131 bir \u00e7al\u0131\u015fma ortam\u0131 sunar, da\u011f\u0131t\u0131m\u0131 basitle\u015ftirir ve &#8220;ba\u011f\u0131ml\u0131l\u0131k cehennemi&#8221; sorunlar\u0131n\u0131 en aza indirir. Her bir scraper \u00f6rne\u011fi ayr\u0131 bir konteynerde \u00e7al\u0131\u015fabilir, bu da izolasyon ve kaynak y\u00f6netimi a\u00e7\u0131s\u0131ndan b\u00fcy\u00fck avantajlar sunar.<\/p>\n<h4>Kubernetes<\/h4>\n<p>Kubernetes (genellikle K8s olarak an\u0131l\u0131r), konteynerize edilmi\u015f i\u015f y\u00fcklerini ve servisleri otomatik olarak da\u011f\u0131tmak, \u00f6l\u00e7eklendirmek ve y\u00f6netmek i\u00e7in kullan\u0131lan a\u00e7\u0131k kaynakl\u0131 bir sistemdir. Docker konteynerlerini orkestra etmek i\u00e7in end\u00fcstri standard\u0131 haline gelmi\u015ftir. Web scraper&#8217;\u0131m\u0131z i\u00e7in Kubernetes kullanmak, binlerce scraping g\u00f6revini e\u015f zamanl\u0131 olarak y\u00fcr\u00fctmek i\u00e7in dinamik olarak Pod&#8217;lar olu\u015fturmam\u0131z\u0131, y\u00fck\u00fc dengelememizi, ba\u015far\u0131s\u0131z olan Pod&#8217;lar\u0131 otomatik olarak yeniden ba\u015flatmam\u0131z\u0131 ve genel sistemin hataya dayan\u0131kl\u0131 olmas\u0131n\u0131 sa\u011flamam\u0131z\u0131 m\u00fcmk\u00fcn k\u0131lar. Otomatik \u00f6l\u00e7eklendirme (Horizontal Pod Autoscaler &#8211; HPA) ile talebe g\u00f6re kaynaklar\u0131 dinamik olarak ayarlayabiliriz, b\u00f6ylece maliyetleri optimize ederken performans s\u00fcreklili\u011fini garanti ederiz.<\/p>\n<h3>Temel Web Scraper Uygulamas\u0131<\/h3>\n<p>Bu b\u00f6l\u00fcmde, Puppeteer ve Node.js kullanarak basit bir web scraper&#8217;\u0131n nas\u0131l olu\u015fturulaca\u011f\u0131n\u0131 ad\u0131m ad\u0131m inceleyece\u011fiz. Amac\u0131m\u0131z, belirli bir web sayfas\u0131ndan veri \u00e7ekmek ve bu veriyi yap\u0131land\u0131r\u0131lm\u0131\u015f bir formatta kaydetmektir.<\/p>\n<h4>Proje Yap\u0131s\u0131 ve Ba\u011f\u0131ml\u0131l\u0131klar<\/h4>\n<p>\u00d6ncelikle yeni bir Node.js projesi olu\u015ftural\u0131m ve gerekli ba\u011f\u0131ml\u0131l\u0131klar\u0131 kural\u0131m:<\/p>\n<pre><code class=\"language-bash\">mkdir concurrent-scraper\ncd concurrent-scraper\nnpm init -y\nnpm install puppeteer p-queue<\/code><\/pre>\n<p><code>p-queue<\/code> k\u00fct\u00fcphanesi, e\u015f zamanl\u0131 g\u00f6revlerin say\u0131s\u0131n\u0131 kontrol etmemize yard\u0131mc\u0131 olacak basit bir kuyruk y\u00f6netimi sa\u011flar. Proje yap\u0131m\u0131z ba\u015flang\u0131\u00e7ta \u015f\u00f6yle olabilir:<\/p>\n<pre><code class=\"language-plaintext\">concurrent-scraper\/\n\u251c\u2500\u2500 node_modules\/\n\u251c\u2500\u2500 package.json\n\u251c\u2500\u2500 package-lock.json\n\u2514\u2500\u2500 scraper.js<\/code><\/pre>\n<h4>Puppeteer ile \u0130lk Ad\u0131mlar<\/h4>\n<p>\u015eimdi <code>scraper.js<\/code> dosyam\u0131z\u0131 olu\u015ftural\u0131m ve Puppeteer ile basit bir sayfa ziyaretini ve veri \u00e7ekimini ger\u00e7ekle\u015ftirelim. \u00d6rnek olarak, bir blog sayfas\u0131ndaki ba\u015fl\u0131klar\u0131 \u00e7ekmeyi hedefleyebiliriz:<\/p>\n<pre><code class=\"language-javascript\">const puppeteer = require('puppeteer');\n\nasync function scrapePage(url) {\n    let browser;\n    try {\n        browser = await puppeteer.launch({ headless: true }); \/\/ headless: true varsay\u0131lan olarak gelir\n        const page = await browser.newPage();\n        await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 }); \/\/ Sayfan\u0131n y\u00fcklenmesini bekle\n\n        \/\/ Sayfadaki t\u00fcm ba\u015fl\u0131klar\u0131 \u00e7ek\n        const titles = await page.evaluate(() => {\n            const elements = Array.from(document.querySelectorAll('h1, h2, h3'));\n            return elements.map(el => el.innerText.trim());\n        });\n\n        console.log(<code>URL: ${url}<\/code>);\n        console.log('Ba\u015fl\u0131klar:', titles);\n        return { url, titles };\n\n    } catch (error) {\n        console.error(<code>URL ${url} i\u015flenirken hata olu\u015ftu:<\/code>, error);\n        return { url, error: error.message };\n    } finally {\n        if (browser) {\n            await browser.close();\n        }\n    }\n}\n\n\/\/ \u00d6rnek kullan\u0131m\n\/\/ scrapePage('https:\/\/example.com').then(data => console.log('\u00c7ekilen veri:', data));\n<\/code><\/pre>\n<p>Bu kod par\u00e7as\u0131, Puppeteer&#8217;\u0131 ba\u015flat\u0131r, belirtilen URL&#8217;ye gider, sayfadaki H1, H2, H3 etiketlerini bulur ve i\u00e7 metinlerini \u00e7eker. Son olarak, taray\u0131c\u0131y\u0131 kapat\u0131r. <code>waitUntil<\/code> ve <code>timeout<\/code> se\u00e7enekleri, sayfa y\u00fckleme davran\u0131\u015f\u0131n\u0131 kontrol etmek i\u00e7in \u00f6nemlidir.<\/p>\n<h4>Veri \u00c7ekme ve Kaydetme<\/h4>\n<p>\u00d6nceki \u00f6rnekte sadece ba\u015fl\u0131klar\u0131 \u00e7ektik. Ger\u00e7ek bir senaryoda, daha fazla veri noktas\u0131 (fiyat, a\u00e7\u0131klama, resim URL&#8217;leri vb.) \u00e7ekmek isteyebiliriz. <code>page.evaluate()<\/code> fonksiyonu i\u00e7inde, taray\u0131c\u0131 ba\u011flam\u0131nda \u00e7al\u0131\u015fan JavaScript kodunu yazarak DOM \u00fczerinde her t\u00fcrl\u00fc manip\u00fclasyonu yapabiliriz. \u00d6rne\u011fin, bir \u00fcr\u00fcn sayfas\u0131ndan fiyat ve a\u00e7\u0131klama \u00e7ekmek i\u00e7in:<\/p>\n<pre><code class=\"language-javascript\">        const productData = await page.evaluate(() => {\n            const title = document.querySelector('h1.product-title')?.innerText.trim();\n            const price = document.querySelector('.product-price')?.innerText.trim();\n            const description = document.querySelector('.product-description')?.innerText.trim();\n            return { title, price, description };\n        });\n        console.log('\u00dcr\u00fcn Verileri:', productData);\n        return { url, productData };\n<\/code><\/pre>\n<p>\u00c7ekilen veriyi daha sonra bir dosyaya (JSON, CSV) veya bir veritaban\u0131na kaydedebiliriz. Basit bir JSON dosyas\u0131na kaydetme \u00f6rne\u011fi:<\/p>\n<pre><code class=\"language-javascript\">const fs = require('fs').promises; \/\/ Node.js dosya sistemi mod\u00fcl\u00fc\n\n\/\/ ... (scrapePage fonksiyonu) ...\n\nasync function main() {\n    const urlsToScrape = [\n        'https:\/\/example.com\/product\/1',\n        'https:\/\/example.com\/product\/2',\n        \/\/ ...\n    ];\n    const allScrapedData = [];\n    for (const url of urlsToScrape) {\n        const data = await scrapePage(url);\n        allScrapedData.push(data);\n    }\n    await fs.writeFile('scraped_data.json', JSON.stringify(allScrapedData, null, 2));\n    console.log('T\u00fcm veriler scraped_data.json dosyas\u0131na kaydedildi.');\n}\n\n\/\/ main(); \/\/ E\u015f zamanl\u0131l\u0131k ekledikten sonra \u00e7a\u011f\u0131raca\u011f\u0131z.\n<\/code><\/pre>\n<h4>Hata Y\u00f6netimi ve Robustluk<\/h4>\n<p>Web scraping, a\u011f sorunlar\u0131, sayfa yap\u0131s\u0131 de\u011fi\u015fiklikleri, anti-bot mekanizmalar\u0131 ve sunucu hatalar\u0131 gibi bir\u00e7ok sorunla kar\u015f\u0131la\u015fabilir. Scraper&#8217;\u0131m\u0131z\u0131n robust olmas\u0131 i\u00e7in hata y\u00f6netimi kritik \u00f6neme sahiptir:<\/p>\n<ul>\n<li><code>try-catch<\/code> bloklar\u0131: Puppeteer i\u015flemleri s\u0131ras\u0131nda meydana gelebilecek hatalar\u0131 yakalamak i\u00e7in kullan\u0131l\u0131r.<\/li>\n<li>Zaman a\u015f\u0131mlar\u0131 (<code>timeout<\/code>): <code>page.goto()<\/code> veya <code>page.waitForSelector()<\/code> gibi i\u015flemlerde belirli bir s\u00fcre i\u00e7inde yan\u0131t al\u0131namazsa hata f\u0131rlat\u0131r.<\/li>\n<li>Yeniden deneme mekanizmalar\u0131: Ge\u00e7ici a\u011f hatalar\u0131 veya sunucu yo\u011funlu\u011fu durumunda i\u015flemi birka\u00e7 kez yeniden denemek faydal\u0131 olabilir (\u00f6rne\u011fin, <code>axios-retry<\/code> gibi k\u00fct\u00fcphanelerle veya \u00f6zel bir <code>retry<\/code> fonksiyonu ile).<\/li>\n<li>User-Agent rotasyonu: Baz\u0131 siteler belirli User-Agent&#8217;lara kar\u015f\u0131 hassas olabilir. Farkl\u0131 User-Agent&#8217;lar kullanmak bot tespitini atlatmaya yard\u0131mc\u0131 olabilir.<\/li>\n<li>Proxy kullan\u0131m\u0131: IP adresinizin engellenmesini \u00f6nlemek i\u00e7in proxy sunucular\u0131 \u00fczerinden istek g\u00f6ndermek \u00f6nemlidir.<\/li>\n<li>Headless modda sorun giderme: <code>headless: false<\/code> ile taray\u0131c\u0131y\u0131 g\u00f6rsel olarak a\u00e7arak hatalar\u0131 daha kolay tespit edebiliriz.<\/li>\n<\/ul>\n<p>Yukar\u0131daki <code>scrapePage<\/code> fonksiyonu, temel bir <code>try-catch<\/code> blo\u011fu i\u00e7erir. Daha geli\u015fmi\u015f senaryolarda, belirli hata kodlar\u0131na g\u00f6re farkl\u0131 yeniden deneme stratejileri uygulamak veya ba\u015far\u0131s\u0131z olan URL&#8217;leri ayr\u0131 bir kuyru\u011fa atmak d\u00fc\u015f\u00fcn\u00fclebilir.<\/p>\n<h3>E\u015f Zamanl\u0131l\u0131k ve Performans Optimizasyonu<\/h3>\n<p>Tek bir URL&#8217;yi \u00e7ekmek basit olsa da, binlerce URL&#8217;yi verimli bir \u015fekilde \u00e7ekmek i\u00e7in e\u015f zamanl\u0131l\u0131k \u015fartt\u0131r. Node.js, asenkron yap\u0131s\u0131yla bu konuda do\u011fal bir avantaj sunar.<\/p>\n<h4>Node.js&#8217;te E\u015f Zamanl\u0131l\u0131k<\/h4>\n<p>Node.js&#8217;in olay d\u00f6ng\u00fcs\u00fc, G\/\u00c7 i\u015flemlerinin engellemeden \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flar. Bu, birden fazla web sayfas\u0131n\u0131 ayn\u0131 anda ziyaret etmeye \u00e7al\u0131\u015ft\u0131\u011f\u0131m\u0131zda CPU kaynaklar\u0131n\u0131n bo\u015fta kalmamas\u0131n\u0131 ve a\u011f isteklerinin paralel olarak y\u00fcr\u00fct\u00fclmesini sa\u011flar. Ancak, \u00e7ok fazla e\u015f zamanl\u0131 Puppeteer taray\u0131c\u0131 \u00f6rne\u011fi a\u00e7mak sistem kaynaklar\u0131n\u0131 (RAM, CPU) h\u0131zla t\u00fcketebilir ve hedef sunucu taraf\u0131ndan engellenmenize neden olabilir. Bu nedenle, e\u015f zamanl\u0131l\u0131k seviyesini s\u0131n\u0131rlamak \u00f6nemlidir.<\/p>\n<p>Daha \u00f6nce kurdu\u011fumuz <code>p-queue<\/code> k\u00fct\u00fcphanesi, e\u015f zamanl\u0131 \u00e7al\u0131\u015fan g\u00f6rev say\u0131s\u0131n\u0131 kontrol etmek i\u00e7in m\u00fckemmel bir ara\u00e7t\u0131r. \u0130\u015fte <code>p-queue<\/code> kullanarak e\u015f zamanl\u0131 scraping \u00f6rne\u011fi:<\/p>\n<pre><code class=\"language-javascript\">const PQueue = require('p-queue');\n\/\/ ... (scrapePage fonksiyonu yukar\u0131daki gibi) ...\n\nasync function mainConcurrent() {\n    const urlsToScrape = [\n        'https:\/\/www.example.com\/page1',\n        'https:\/\/www.example.com\/page2',\n        'https:\/\/www.example.com\/page3',\n        'https:\/\/www.example.com\/page4',\n        'https:\/\/www.example.com\/page5',\n        \/\/ ... binlerce URL\n    ];\n\n    const concurrencyLimit = 5; \/\/ Ayn\u0131 anda \u00e7al\u0131\u015facak maksimum taray\u0131c\u0131 say\u0131s\u0131\n    const queue = new PQueue({ concurrency: concurrencyLimit });\n    const allScrapedData = [];\n\n    const promises = urlsToScrape.map(url =>\n        queue.add(() => scrapePage(url).then(data => allScrapedData.push(data)))\n    );\n\n    await Promise.all(promises); \/\/ T\u00fcm scraping g\u00f6revlerinin bitmesini bekle\n\n    await fs.writeFile('scraped_data_concurrent.json', JSON.stringify(allScrapedData, null, 2));\n    console.log(<code>T\u00fcm veriler ${concurrencyLimit} e\u015f zamanl\u0131 g\u00f6revle scraped_data_concurrent.json dosyas\u0131na kaydedildi.<\/code>);\n}\n\nmainConcurrent();\n<\/code><\/pre>\n<p>Bu yakla\u015f\u0131m, Puppeteer&#8217;\u0131n taray\u0131c\u0131 ba\u015flatma ve kapatma maliyetini her URL i\u00e7in tekrar tekrar \u00fcstlenir. Daha optimize bir yakla\u015f\u0131m, tek bir taray\u0131c\u0131 \u00f6rne\u011fi ba\u015flat\u0131p birden fazla sekme (page) kullanmakt\u0131r. Ancak bu, e\u015f zamanl\u0131l\u0131k y\u00f6netimini daha karma\u015f\u0131k hale getirebilir ve baz\u0131 sitelerde oturum y\u00f6netimi sorunlar\u0131na yol a\u00e7abilir. Genellikle, her g\u00f6rev i\u00e7in yeni bir taray\u0131c\u0131 ba\u015flatmak daha izole ve hataya dayan\u0131kl\u0131 bir yakla\u015f\u0131md\u0131r, ancak kaynak t\u00fcketimi daha y\u00fcksek olabilir.<\/p>\n<h4>\u0130\u015f Kuyruklar\u0131 ve Mesajla\u015fma<\/h4>\n<p>Uygulamam\u0131z\u0131n tek bir Node.js s\u00fcrecinin \u00f6tesine ge\u00e7ip birden fazla sunucuda veya Kubernetes Pod&#8217;unda \u00e7al\u0131\u015fmas\u0131n\u0131 istedi\u011fimizde, basit <code>p-queue<\/code> yeterli olmaz. Bu durumda, da\u011f\u0131t\u0131k bir i\u015f kuyru\u011fu sistemine ihtiyac\u0131m\u0131z vard\u0131r. Redis tabanl\u0131 <a href=\"https:\/\/github.com\/OptimalBits\/bull\">BullMQ<\/a> gibi k\u00fct\u00fcphaneler, scraping g\u00f6revlerini bir kuyru\u011fa atmak ve birden fazla i\u015f\u00e7i (worker) taraf\u0131ndan bu g\u00f6revlerin i\u015flenmesini sa\u011flamak i\u00e7in idealdir.<\/p>\n<p>Mimari \u015f\u00f6yle de\u011fi\u015fir:<\/p>\n<ol>\n<li>Bir &#8220;\u00fcretici&#8221; (producer) uygulamas\u0131, \u00e7ekilecek URL&#8217;leri bir Redis kuyru\u011funa ekler.<\/li>\n<li>Birden fazla &#8220;t\u00fcketici&#8221; (consumer\/worker) uygulamas\u0131, kuyruktan g\u00f6revleri al\u0131r ve Puppeteer ile scraping i\u015flemini ger\u00e7ekle\u015ftirir.<\/li>\n<li>\u0130\u015flenen veriler do\u011frudan bir veritaban\u0131na (MongoDB, PostgreSQL) veya bir depolama hizmetine (AWS S3) kaydedilir.<\/li>\n<\/ol>\n<p>Bu model, i\u015f y\u00fck\u00fcn\u00fc yatay olarak \u00f6l\u00e7eklendirmemize olanak tan\u0131r. Yeni bir i\u015f\u00e7i eklemek veya mevcut i\u015f\u00e7ileri kald\u0131rmak kolayd\u0131r. Kubernetes ortam\u0131nda bu, Pod&#8217;lar\u0131 \u00f6l\u00e7eklendirmek anlam\u0131na gelir.<\/p>\n<h3>Docker ile Konteynerle\u015ftirme<\/h3>\n<p>Scraper&#8217;\u0131m\u0131z\u0131 farkl\u0131 ortamlarda (geli\u015ftirme, test, \u00fcretim) tutarl\u0131 bir \u015fekilde \u00e7al\u0131\u015ft\u0131rmak i\u00e7in Docker kullanaca\u011f\u0131z. Puppeteer&#8217;\u0131n Chromium ba\u011f\u0131ml\u0131l\u0131\u011f\u0131 nedeniyle Dockerfile biraz daha karma\u015f\u0131k olabilir.<\/p>\n<h4>Dockerfile Olu\u015fturma<\/h4>\n<p>Projemizin k\u00f6k dizininde bir <code>Dockerfile<\/code> olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-dockerfile\"># Node.js i\u00e7in temel imaj\nFROM node:18-slim\n\n<h2>Uygulama dizini olu\u015ftur<\/h2>\nWORKDIR \/app\n\n<h2>Gerekli sistem ba\u011f\u0131ml\u0131l\u0131klar\u0131n\u0131 y\u00fckle<\/h2>\n<h2>Puppeteer'\u0131n Chromium'u \u00e7al\u0131\u015ft\u0131rmas\u0131 i\u00e7in gerekli paketler<\/h2>\nRUN apt-get update && apt-get install -y \\\n    chromium \\\n    # veya chromium-browser \\\n    # veya google-chrome-stable \\\n    # E\u011fer chromium'u do\u011frudan kullanmak isterseniz.\n    # Puppeteer kendi Chromium'unu indirir ancak baz\u0131 ba\u011f\u0131ml\u0131l\u0131klar\u0131 sistemde ister.\n    # A\u015fa\u011f\u0131daki liste genel olarak yeterlidir:\n    gconf-service \\\n    libasound2 \\\n    libatk1.0-0 \\\n    libcairo2 \\\n    libcups2 \\\n    libfontconfig1 \\\n    libgdk-pixbuf2.0-0 \\\n    libgtk-3-0 \\\n    libnspr4 \\\n    libpango-1.0-0 \\\n    libpangocairo-1.0-0 \\\n    libnss3 \\\n    libxss1 \\\n    libxtst6 \\\n    xauth \\\n    fonts-liberation \\\n    libappindicator1 \\\n    libnss3 \\\n    lsb-release \\\n    xdg-utils \\\n    wget \\\n    --no-install-recommends && rm -rf \/var\/lib\/apt\/lists\/*\n\n<h2>Puppeteer'\u0131n varsay\u0131lan Chromium'u yerine sistemde kurulu olan\u0131 kullanmas\u0131n\u0131 sa\u011flayal\u0131m (iste\u011fe ba\u011fl\u0131)<\/h2>\n<h2>ENV PUPPETEER_EXECUTABLE_PATH=\/usr\/bin\/chromium<\/h2>\n\n<h2>Node.js ba\u011f\u0131ml\u0131l\u0131klar\u0131n\u0131 kopyala ve y\u00fckle<\/h2>\nCOPY package*.json .\/\nRUN npm install\n\n<h2>Uygulama kodunu kopyala<\/h2>\nCOPY . .\n\n<h2>Scraper'\u0131 \u00e7al\u0131\u015ft\u0131rmak i\u00e7in komut<\/h2>\nCMD [\"node\", \"scraper.js\"]\n<\/code><\/pre>\n<p><strong>Not:<\/strong> <code>chromium<\/code> yerine <code>google-chrome-stable<\/code> veya <code>microsoft-edge-stable<\/code> gibi daha g\u00fcncel taray\u0131c\u0131lar da kullan\u0131labilir, ancak bu, Docker imaj\u0131n\u0131n boyutunu art\u0131rabilir. <code>PUPPETEER_EXECUTABLE_PATH<\/code> de\u011fi\u015fkeni, Puppeteer&#8217;\u0131n kendi indirdi\u011fi Chromium yerine sistemde kurulu olan\u0131 kullanmas\u0131n\u0131 sa\u011flar, bu da imaj boyutunu azaltabilir ve g\u00fcncellemeyi kolayla\u015ft\u0131rabilir. Ancak, Puppeteer&#8217;\u0131n kendi indirdi\u011fi Chromium s\u00fcr\u00fcm\u00fcyle uyumluluk sorunlar\u0131 ya\u015fanabilir. En g\u00fcvenli yol, Puppeteer&#8217;\u0131n kendi Chromium&#8217;unu indirmesine izin vermektir, ancak bu durumda <code>node:18-slim<\/code> yerine <code>node:18<\/code> gibi daha b\u00fcy\u00fck bir imaj kullanmak veya gerekli ba\u011f\u0131ml\u0131l\u0131klar\u0131 manuel olarak eklemek gerekebilir. Yukar\u0131daki <code>apt-get install<\/code> komutu, Puppeteer&#8217;\u0131n kendi Chromium&#8217;unu \u00e7al\u0131\u015ft\u0131rmas\u0131 i\u00e7in gerekli olan genel ba\u011f\u0131ml\u0131l\u0131klar\u0131 i\u00e7erir.<\/p>\n<h4>Docker Image Olu\u015fturma ve \u00c7al\u0131\u015ft\u0131rma<\/h4>\n<p>Dockerfile&#8217;\u0131 olu\u015fturduktan sonra, Docker imaj\u0131m\u0131z\u0131 in\u015fa edebiliriz:<\/p>\n<pre><code class=\"language-bash\">docker build -t my-scraper:1.0 .<\/code><\/pre>\n<p>\u0130maj olu\u015fturulduktan sonra, yerel makinemizde \u00e7al\u0131\u015ft\u0131rabiliriz:<\/p>\n<pre><code class=\"language-bash\">docker run --rm my-scraper:1.0<\/code><\/pre>\n<p><code>--rm<\/code> bayra\u011f\u0131, konteyner durdu\u011funda otomatik olarak kald\u0131r\u0131lmas\u0131n\u0131 sa\u011flar. E\u011fer Puppeteer <code>headless: false<\/code> ile \u00e7al\u0131\u015ft\u0131r\u0131l\u0131yorsa, X sunucusu gibi ek yap\u0131land\u0131rmalar gerekebilir, ancak \u00fcretim ortam\u0131nda genellikle headless mod tercih edilir.<\/p>\n<h4>Puppeteer ve Headless Chrome Sorunlar\u0131<\/h4>\n<p>Docker ortam\u0131nda Puppeteer ile \u00e7al\u0131\u015f\u0131rken baz\u0131 yayg\u0131n sorunlar ve \u00e7\u00f6z\u00fcmleri:<\/p>\n<ul>\n<li><strong>Eksik Ba\u011f\u0131ml\u0131l\u0131klar:<\/strong> <code>Dockerfile<\/code>&#8216;da listelenen <code>apt-get install<\/code> komutlar\u0131, Chromium&#8217;un \u00e7al\u0131\u015fmas\u0131 i\u00e7in gerekli temel k\u00fct\u00fcphaneleri sa\u011flar. Bu liste, kullan\u0131lan temel imaj ve Chromium s\u00fcr\u00fcm\u00fcne g\u00f6re de\u011fi\u015fiklik g\u00f6sterebilir.<\/li>\n<li><strong>Sandbox Modu:<\/strong> Linux konteynerlerinde g\u00fcvenlik nedeniyle Chromium&#8217;un sandbox modu bazen sorun \u00e7\u0131karabilir. Bu durumda Puppeteer&#8217;\u0131 <code>args: ['--no-sandbox', '--disable-setuid-sandbox']<\/code> se\u00e7enekleriyle ba\u015flatmak gerekebilir:\n<pre><code class=\"language-javascript\">await puppeteer.launch({\n            headless: true,\n            args: ['--no-sandbox', '--disable-setuid-sandbox']\n        });<\/code><\/pre>\n<p>        Ancak, <code>--no-sandbox<\/code> g\u00fcvenlik riski ta\u015f\u0131d\u0131\u011f\u0131 i\u00e7in dikkatli kullan\u0131lmal\u0131d\u0131r.<\/li>\n<li><strong>Payla\u015f\u0131lan Bellek (\/dev\/shm):<\/strong> Chromium, baz\u0131 durumlarda <code>\/dev\/shm<\/code> (payla\u015f\u0131lan bellek) kullan\u0131r ve Docker&#8217;\u0131n varsay\u0131lan boyutu (64MB) yetersiz kalabilir. Bu durumda Docker&#8217;\u0131 <code>--shm-size=1gb<\/code> gibi bir de\u011ferle \u00e7al\u0131\u015ft\u0131rmak gerekir:\n<pre><code class=\"language-bash\">docker run --rm --shm-size=1gb my-scraper:1.0<\/code><\/pre>\n<p>        Kubernetes&#8217;te bu ayar Pod tan\u0131m\u0131nda yap\u0131l\u0131r.<\/li>\n<\/ul>\n<h3>Kubernetes ile \u00d6l\u00e7eklendirme ve Orkestrasyon<\/h3>\n<p>Scraper&#8217;\u0131m\u0131z\u0131 Docker konteynerlerine d\u00f6n\u00fc\u015ft\u00fcrd\u00fckten sonra, bu konteynerleri b\u00fcy\u00fck \u00f6l\u00e7ekte y\u00f6netmek ve otomatikle\u015ftirmek i\u00e7in Kubernetes&#8217;i kullanaca\u011f\u0131z. Bu, scraping operasyonlar\u0131m\u0131z\u0131 daha dayan\u0131kl\u0131, \u00f6l\u00e7eklenebilir ve y\u00f6netilebilir hale getirecektir.<\/p>\n<h4>Kubernetes Temelleri<\/h4>\n<p>Kubernetes&#8217;in temel bile\u015fenleri:<\/p>\n<ul>\n<li><strong>Pod:<\/strong> Kubernetes&#8217;teki en k\u00fc\u00e7\u00fck da\u011f\u0131t\u0131labilir birimdir. Bir veya daha fazla konteyner i\u00e7erir (bizim durumumuzda bir Node.js\/Puppeteer konteyneri). Pod&#8217;lar ge\u00e7icidir ve yeniden ba\u015flat\u0131ld\u0131\u011f\u0131nda IP adresleri de\u011fi\u015febilir.<\/li>\n<li><strong>Deployment:<\/strong> Pod&#8217;lar\u0131n durumunu y\u00f6neten bir Kubernetes kayna\u011f\u0131d\u0131r. Belirli say\u0131da Pod&#8217;un \u00e7al\u0131\u015ft\u0131\u011f\u0131ndan emin olur, g\u00fcncelleme ve geri alma i\u015flemlerini y\u00f6netir.<\/li>\n<li><strong>Service:<\/strong> Bir grup Pod&#8217;a kararl\u0131 bir a\u011f eri\u015fimi sa\u011flar. Pod&#8217;lar yeniden ba\u015flat\u0131lsa bile Service&#8217;in IP adresi de\u011fi\u015fmez, bu da di\u011fer servislerin Pod&#8217;lara eri\u015fmesini kolayla\u015ft\u0131r\u0131r.<\/li>\n<li><strong>Job\/CronJob:<\/strong> Tek seferlik veya zamanlanm\u0131\u015f g\u00f6revler i\u00e7in kullan\u0131l\u0131r. Bizim e\u015f zamanl\u0131 scraper&#8217;\u0131m\u0131z i\u00e7in genellikle Deployment daha uygundur, \u00e7\u00fcnk\u00fc s\u00fcrekli \u00e7al\u0131\u015fan bir worker havuzu olu\u015fturmak isteriz. Ancak, belirli bir URL listesini bir kez taramak i\u00e7in Job kullan\u0131labilir.<\/li>\n<\/ul>\n<h4>Deployment ve Pod Tan\u0131mlar\u0131<\/h4>\n<p>Scraper uygulamam\u0131z\u0131 Kubernetes&#8217;e da\u011f\u0131tmak i\u00e7in bir Deployment tan\u0131m\u0131 olu\u015fturaca\u011f\u0131z. Bu, scraping g\u00f6revlerini yerine getirecek worker Pod&#8217;lar\u0131n\u0131 y\u00f6netecektir. <code>scraper-deployment.yaml<\/code>:<\/p>\n<pre><code class=\"language-yaml\">apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: scraper-worker\n  labels:\n    app: scraper\nspec:\n  replicas: 3 # Ba\u015flang\u0131\u00e7ta 3 worker Pod \u00e7al\u0131\u015ft\u0131r\n  selector:\n    matchLabels:\n      app: scraper\n  template:\n    metadata:\n      labels:\n        app: scraper\n    spec:\n      containers:\n      - name: scraper-container\n        image: my-scraper:1.0 # Docker imaj\u0131m\u0131z\u0131n ad\u0131\n        imagePullPolicy: IfNotPresent # \u0130maj yerel olarak varsa \u00e7ekme\n        resources:\n          requests:\n            memory: \"512Mi\" # Her Pod i\u00e7in minimum 512MB bellek iste\u011fi\n            cpu: \"500m\"    # Her Pod i\u00e7in minimum 0.5 CPU \u00e7ekirde\u011fi iste\u011fi\n          limits:\n            memory: \"1Gi\"  # Her Pod i\u00e7in maksimum 1GB bellek s\u0131n\u0131r\u0131\n            cpu: \"1\"       # Her Pod i\u00e7in maksimum 1 CPU \u00e7ekirde\u011fi s\u0131n\u0131r\u0131\n        env:\n          - name: CONCURRENCY_LIMIT # Scraper i\u00e7indeki e\u015f zamanl\u0131l\u0131k limiti\n            value: \"3\" # Her Pod i\u00e7inde ayn\u0131 anda 3 taray\u0131c\u0131 \u00e7al\u0131\u015fs\u0131n\n        # Puppeteer'\u0131n \/dev\/shm sorununu \u00e7\u00f6zmek i\u00e7in\n        volumeMounts:\n          - name: dshm\n            mountPath: \/dev\/shm\n      volumes:\n        - name: dshm\n          emptyDir:\n            medium: Memory\n            sizeLimit: \"1Gi\" # Payla\u015f\u0131lan bellek boyutu\n<\/code><\/pre>\n<p>Bu tan\u0131m, <code>my-scraper:1.0<\/code> imaj\u0131ndan 3 adet Pod \u00e7al\u0131\u015ft\u0131r\u0131r. Her Pod&#8217;un belirli bellek ve CPU kaynaklar\u0131 vard\u0131r ve Puppeteer i\u00e7in <code>\/dev\/shm<\/code> ayar\u0131 yap\u0131lm\u0131\u015ft\u0131r. <code>CONCURRENCY_LIMIT<\/code> ortam de\u011fi\u015fkeni, her Pod&#8217;un kendi i\u00e7inde ka\u00e7 e\u015f zamanl\u0131 scraping g\u00f6revi y\u00fcr\u00fctece\u011fini kontrol eder.<\/p>\n<p>Uygulamak i\u00e7in:<\/p>\n<pre><code class=\"language-bash\">kubectl apply -f scraper-deployment.yaml<\/code><\/pre>\n<h4>Servisler ve \u0130leti\u015fim<\/h4>\n<p>E\u011fer scraper&#8217;lar\u0131m\u0131z bir Redis kuyru\u011funa (BullMQ i\u00e7in) veya bir veritaban\u0131na ba\u011flanacaksa, bu servisleri de Kubernetes&#8217;te \u00e7al\u0131\u015ft\u0131rmak ve scraper Pod&#8217;lar\u0131n\u0131n bunlara eri\u015febilmesini sa\u011flamak gerekir. \u00d6rne\u011fin, bir Redis Deployment&#8217;\u0131 ve Service&#8217;i tan\u0131mlayabiliriz. Scraper Pod&#8217;lar\u0131, Redis Service&#8217;in ad\u0131n\u0131 kullanarak Redis&#8217;e ba\u011flanabilirler (\u00f6rne\u011fin, <code>redis-service:6379<\/code>).<\/p>\n<pre><code class=\"language-yaml\"># redis-deployment.yaml\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: redis\n  labels:\n    app: redis\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: redis\n  template:\n    metadata:\n      labels:\n        app: redis\n    spec:\n      containers:\n      - name: redis\n        image: redis:6-alpine\n        ports:\n        - containerPort: 6379\n---\n<h2>redis-service.yaml<\/h2>\napiVersion: v1\nkind: Service\nmetadata:\n  name: redis-service\nspec:\n  selector:\n    app: redis\n  ports:\n    - protocol: TCP\n      port: 6379\n      targetPort: 6379\n<\/code><\/pre>\n<p>Scraper Pod&#8217;lar\u0131 i\u00e7inde Redis&#8217;e ba\u011flan\u0131rken <code>redis-service<\/code> ana bilgisayar ad\u0131n\u0131 kullanabiliriz.<\/p>\n<h4>Horizontal Pod Autoscaler (HPA) ile Otomatik \u00d6l\u00e7eklendirme<\/h4>\n<p>Kubernetes&#8217;in en g\u00fc\u00e7l\u00fc \u00f6zelliklerinden biri, i\u015f y\u00fck\u00fcne g\u00f6re Pod&#8217;lar\u0131 otomatik olarak \u00f6l\u00e7eklendirebilmesidir. <code>Horizontal Pod Autoscaler<\/code> (HPA), Pod&#8217;lar\u0131n CPU veya bellek kullan\u0131m\u0131na (veya \u00f6zel metriklere) g\u00f6re Deployment&#8217;\u0131n <code>replicas<\/code> say\u0131s\u0131n\u0131 dinamik olarak ayarlar. Bu, scraping talebi artt\u0131\u011f\u0131nda otomatik olarak daha fazla worker Pod&#8217;unun ba\u015flat\u0131lmas\u0131n\u0131 ve talepler azald\u0131\u011f\u0131nda kaynak tasarrufu i\u00e7in Pod&#8217;lar\u0131n azalt\u0131lmas\u0131n\u0131 sa\u011flar.<\/p>\n<pre><code class=\"language-yaml\">apiVersion: autoscaling\/v2\nkind: HorizontalPodAutoscaler\nmetadata:\n  name: scraper-worker-hpa\nspec:\n  scaleTargetRef:\n    apiVersion: apps\/v1\n    kind: Deployment\n    name: scraper-worker\n  minReplicas: 3 # Minimum 3 Pod \u00e7al\u0131\u015fs\u0131n\n  maxReplicas: 10 # Maksimum 10 Pod'a kadar \u00f6l\u00e7eklenebilir\n  metrics:\n  - type: Resource\n    resource:\n      name: cpu\n      target:\n        type: Utilization\n        averageUtilization: 70 # CPU kullan\u0131m\u0131 %70'i a\u015ft\u0131\u011f\u0131nda \u00f6l\u00e7ekle\n  - type: Resource\n    resource:\n      name: memory\n      target:\n        type: Utilization\n        averageUtilization: 80 # Bellek kullan\u0131m\u0131 %80'i a\u015ft\u0131\u011f\u0131nda \u00f6l\u00e7ekle\n<\/code><\/pre>\n<p>Bu HPA tan\u0131m\u0131, <code>scraper-worker<\/code> Deployment&#8217;\u0131n\u0131n CPU kullan\u0131m\u0131 %70&#8217;i veya bellek kullan\u0131m\u0131 %80&#8217;i a\u015ft\u0131\u011f\u0131nda Pod say\u0131s\u0131n\u0131 art\u0131racak, minimum 3, maksimum 10 Pod aras\u0131nda \u00f6l\u00e7eklendirme yapacakt\u0131r.<\/p>\n<pre><code class=\"language-bash\">kubectl apply -f scraper-hpa.yaml<\/code><\/pre>\n<h4>Persistent Storage (Kal\u0131c\u0131 Depolama)<\/h4>\n<p>E\u011fer scraper&#8217;lar\u0131m\u0131z \u00e7ekilen verileri do\u011frudan Pod&#8217;un dosya sistemine kaydediyorsa (ki bu iyi bir uygulama de\u011fildir \u00e7\u00fcnk\u00fc Pod&#8217;lar ge\u00e7icidir), bu verilerin kaybolmamas\u0131 i\u00e7in kal\u0131c\u0131 depolama (Persistent Volume &#8211; PV ve Persistent Volume Claim &#8211; PVC) kullanmam\u0131z gerekir. Ancak, genellikle \u00e7ekilen veriler do\u011frudan bir veritaban\u0131na veya bulut depolama hizmetine (AWS S3, Google Cloud Storage) g\u00f6nderilir, bu da kal\u0131c\u0131 depolama karma\u015f\u0131kl\u0131\u011f\u0131n\u0131 azalt\u0131r.<\/p>\n<h4>Yap\u0131land\u0131rma Y\u00f6netimi<\/h4>\n<p>API anahtarlar\u0131, veritaban\u0131 ba\u011flant\u0131 dizeleri veya hedef sitelerin URL&#8217;leri gibi hassas veya s\u0131k de\u011fi\u015fen yap\u0131land\u0131rma verilerini do\u011frudan Docker imaj\u0131na g\u00f6mmek yerine Kubernetes&#8217;in <code>ConfigMaps<\/code> ve <code>Secrets<\/code> kaynaklar\u0131n\u0131 kullanmal\u0131y\u0131z. <code>ConfigMaps<\/code> hassas olmayan veriler i\u00e7in, <code>Secrets<\/code> ise hassas veriler i\u00e7in kullan\u0131l\u0131r ve Pod&#8217;lara ortam de\u011fi\u015fkenleri veya dosya olarak enjekte edilebilir.<\/p>\n<pre><code class=\"language-yaml\"># scraper-configmap.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: scraper-config\ndata:\n  TARGET_DOMAIN: \"example.com\"\n  CONCURRENCY_LIMIT: \"5\" # Pod ba\u015f\u0131na e\u015f zamanl\u0131 taray\u0131c\u0131 say\u0131s\u0131\n---\n<h2>scraper-secret.yaml<\/h2>\napiVersion: v1\nkind: Secret\nmetadata:\n  name: scraper-secrets\ntype: Opaque\nstringData:\n  API_KEY: \"your_api_key_here\"\n<\/code><\/pre>\n<p>Bu yap\u0131land\u0131rmalar\u0131 Pod tan\u0131m\u0131nda kullanmak i\u00e7in:<\/p>\n<pre><code class=\"language-yaml\"># ... (scraper-deployment.yaml i\u00e7inde container tan\u0131m\u0131) ...\n        env:\n          - name: TARGET_DOMAIN\n            valueFrom:\n              configMapKeyRef:\n                name: scraper-config\n                key: TARGET_DOMAIN\n          - name: CONCURRENCY_LIMIT\n            valueFrom:\n              configMapKeyRef:\n                name: scraper-config\n                key: CONCURRENCY_LIMIT\n          - name: API_KEY\n            valueFrom:\n              secretKeyRef:\n                name: scraper-secrets\n                key: API_KEY\n<\/code><\/pre>\n<h3>G\u00fcvenlik ve Etik Hususlar<\/h3>\n<p>Web scraping yaparken yasal ve etik s\u0131n\u0131rlamalara uymak \u00e7ok \u00f6nemlidir:<\/p>\n<ul>\n<li><strong><code>robots.txt<\/code> dosyas\u0131:<\/strong> Bir siteyi taramadan \u00f6nce her zaman <code>robots.txt<\/code> dosyas\u0131n\u0131 kontrol edin. Bu dosya, sitenin hangi b\u00f6l\u00fcmlerinin taran\u0131p taranamayaca\u011f\u0131n\u0131 belirtir. Bu kurallara uymak, yasal sorunlardan ka\u00e7\u0131nmak ve iyi bir &#8220;internet vatanda\u015f\u0131&#8221; olmak i\u00e7in \u00f6nemlidir.<\/li>\n<li><strong>Hizmet \u015eartlar\u0131:<\/strong> Taramay\u0131 d\u00fc\u015f\u00fcnd\u00fc\u011f\u00fcn\u00fcz web sitesinin hizmet \u015fartlar\u0131n\u0131 okuyun. Baz\u0131 siteler scraping&#8217;i a\u00e7\u0131k\u00e7a yasaklar.<\/li>\n<li><strong>Orant\u0131l\u0131l\u0131k ve Y\u00fck:<\/strong> Hedef sunuculara a\u015f\u0131r\u0131 y\u00fck bindirmemeye dikkat edin. Agresif scraping, sunucular\u0131 yava\u015flatabilir veya \u00e7\u00f6kertebilir. Scraping h\u0131z\u0131n\u0131z\u0131 ve e\u015f zamanl\u0131l\u0131k seviyenizi ayarlayarak sunucuya dostane davran\u0131n. Rate limiting (h\u0131z s\u0131n\u0131rlama) uygulay\u0131n.<\/li>\n<li><strong>IP Rotasyonu ve Proxy&#8217;ler:<\/strong> Ayn\u0131 IP adresinden \u00e7ok say\u0131da istek g\u00f6ndermek, IP adresinizin engellenmesine yol a\u00e7abilir. Proxy sunucular\u0131 veya IP rotasyon servisleri kullanmak bu sorunu a\u015fabilir.<\/li>\n<li><strong>Veri Gizlili\u011fi:<\/strong> Ki\u015fisel olarak tan\u0131mlanabilir bilgileri (PII) toplarken ve saklarken GDPR, KVKK gibi veri gizlili\u011fi d\u00fczenlemelerine kesinlikle uyun.<\/li>\n<\/ul>\n<h3>Sonu\u00e7 ve Gelecek Ad\u0131mlar<\/h3>\n<p>Bu makalede, Puppeteer ve Node.js&#8217;in g\u00fcc\u00fcn\u00fc Docker&#8217;\u0131n konteynerle\u015ftirme yetenekleri ve Kubernetes&#8217;in orkestrasyon kabiliyetleriyle birle\u015ftirerek e\u015f zamanl\u0131 ve \u00f6l\u00e7eklenebilir bir web scraper mimarisi in\u015fa etmeyi ele ald\u0131k. Temel bir scraper uygulamas\u0131ndan ba\u015flayarak, e\u015f zamanl\u0131l\u0131k y\u00f6netimi, Docker ile paketleme ve Kubernetes ile da\u011f\u0131t\u0131m, otomatik \u00f6l\u00e7eklendirme ve yap\u0131land\u0131rma y\u00f6netimi gibi konular\u0131 detayland\u0131rd\u0131k. Bu teknoloji y\u0131\u011f\u0131n\u0131, modern web&#8217;in dinamik ve karma\u015f\u0131k yap\u0131s\u0131yla ba\u015fa \u00e7\u0131kabilen, y\u00fcksek performansl\u0131 ve hataya dayan\u0131kl\u0131 bir scraping \u00e7\u00f6z\u00fcm\u00fc sunar.<\/p>\n<p>Gelecekte bu mimariyi daha da geli\u015ftirmek i\u00e7in at\u0131labilecek ad\u0131mlar \u015funlar olabilir:<\/p>\n<ul>\n<li><strong>Geli\u015fmi\u015f \u0130\u015f Kuyruklar\u0131:<\/strong> BullMQ gibi daha sofistike bir i\u015f kuyru\u011fu sistemi entegre etmek, g\u00f6revlerin \u00f6nceliklendirilmesi, gecikmeli g\u00f6revler ve ba\u015far\u0131s\u0131z g\u00f6revler i\u00e7in yeniden deneme mant\u0131\u011f\u0131 gibi geli\u015fmi\u015f \u00f6zellikler sunar.<\/li>\n<li><strong>Proxy Y\u00f6netimi:<\/strong> Geli\u015fmi\u015f bir proxy rotasyon ve y\u00f6netimi sistemi entegre etmek, IP engellemelerini daha etkili bir \u015fekilde atlatmaya yard\u0131mc\u0131 olabilir.<\/li>\n<li><strong>\u0130zleme ve G\u00fcnl\u00fckleme:<\/strong> Prometheus ve Grafana gibi ara\u00e7larla Kubernetes k\u00fcmesini ve scraper Pod&#8217;lar\u0131n\u0131 izlemek, performans darbo\u011fazlar\u0131n\u0131 ve hatalar\u0131 tespit etmek i\u00e7in kritik \u00f6neme sahiptir. Merkezi g\u00fcnl\u00fckleme (Elasticsearch, Fluentd, Kibana &#8211; EFK stack veya Loki) ile t\u00fcm Pod&#8217;lardan gelen g\u00fcnl\u00fckleri toplamak ve analiz etmek operasyonel verimlili\u011fi art\u0131r\u0131r.<\/li>\n<li><strong>Veritaban\u0131 Entegrasyonu:<\/strong> \u00c7ekilen verileri do\u011frudan bir veritaban\u0131na (MongoDB, PostgreSQL) kaydetmek, veri analizi ve kullan\u0131m\u0131 i\u00e7in daha esnek bir yap\u0131 sa\u011flar.<\/li>\n<li><strong>CI\/CD Entegrasyonu:<\/strong> Docker imajlar\u0131n\u0131n otomatik olarak olu\u015fturulmas\u0131 ve Kubernetes&#8217;e da\u011f\u0131t\u0131lmas\u0131 i\u00e7in bir S\u00fcrekli Entegrasyon\/S\u00fcrekli Da\u011f\u0131t\u0131m (CI\/CD) hatt\u0131 kurmak, geli\u015ftirme ve da\u011f\u0131t\u0131m s\u00fcre\u00e7lerini otomatikle\u015ftirecektir.<\/li>\n<\/ul>\n<p>Bu ad\u0131mlar, web scraping projenizi daha profesyonel, s\u00fcrd\u00fcr\u00fclebilir ve kurumsal d\u00fczeyde bir \u00e7\u00f6z\u00fcme d\u00f6n\u00fc\u015ft\u00fcrecektir.<\/p>\n<p><\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir?\nG\u00fcn\u00fcm\u00fcz\u00fcn veri odakl\u0131 d\u00fcnyas\u0131nda, web siteler","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[1407],"tags":[],"class_list":{"0":"post-32850","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-docker","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir?\" \/>\n<meta property=\"og:description\" content=\"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir? G\u00fcn\u00fcm\u00fcz\u00fcn veri odakl\u0131 d\u00fcnyas\u0131nda, web siteler\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-26T13:41:33+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"22 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir?\",\"datePublished\":\"2025-10-26T13:41:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/\"},\"wordCount\":3438,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"Docker\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/\",\"name\":\"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-10-26T13:41:33+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/","og_locale":"tr_TR","og_type":"article","og_title":"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir?","og_description":"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir? G\u00fcn\u00fcm\u00fcz\u00fcn veri odakl\u0131 d\u00fcnyas\u0131nda, web siteler","og_url":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-10-26T13:41:33+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"22 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir?","datePublished":"2025-10-26T13:41:33+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/"},"wordCount":3438,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["Docker"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/","url":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/","name":"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-10-26T13:41:33+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/puppeteer-node-js-docker-ve-kubernetes-ile-es-zamanli-bir-web-scraper-nasil-insa-edilir\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Puppeteer, Node.js, Docker ve Kubernetes ile E\u015f Zamanl\u0131 Bir Web Scraper Nas\u0131l \u0130n\u015fa Edilir?"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/32850","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=32850"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/32850\/revisions"}],"predecessor-version":[{"id":32851,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/32850\/revisions\/32851"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=32850"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=32850"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=32850"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}