JavaScript Ağırlıklı Web Sitelerini Nasıl Scrape Edersiniz

Ayaklanmış JavaScript-rendered content with headless browsers and agents. Puppeteer, Playwright ve kromdp kurulum kılavuzları performans optimizasyonu ve API Interception stratejileri ile.

JavaScript Ağırlıklı Web Sitelerini Nasıl Scrape Edersiniz

JavaScript-Rendered Content

Modern web siteleri giderek içeriği oluşturmak için JavaScript'e güveniyor. Tek sayfa uygulamaları (SPAs) Reakt, Vue veya Angular minimum HTML kabuğunu yükler, sonra veri müşteri tarafı getirir ve verir. Bu sitelere basit bir HTTP isteği yaptığınızda, boş veya eksik bir sayfa alırsınız, çünkü içerik yalnızca JavaScript infazından sonra var.

JavaScript-heavy web siteleri kurmak gerektirir Başsız tarayıcılar - JavaScript'i uygulayabilen görünür bir pencere olmadan çalışan gerçek tarayıcı motorları DOM'u oluşturur ve sayfa elementleriyle etkileşime girer. Referanslarla birlikte, başsız tarayıcılar verileri en dinamik web sitelerden bile açabilir.

Bu rehber bizim parçamızdır Web'e komple rehber ProxiesBaşsız tarayıcılar kullanırken algılamadan kaçınmak için, bakınız Anti-Bot Systems Proxies nasıl tespit edilir.

Headless Browser'a ihtiyacınız olduğunda?

Headless Browser'a ihtiyacınız olduğunda?
ScenarioBasit HTTPHeadless Browser
Statik HTML sayfalarıMükemmel işlerOverkill
API ile Server-rendered sayfalarWorks (API doğrudan)Gerekli değil
SPA (React, Vue, Angular)Boş kabuk alınGerekli Gerekli Gerekli Gerekli Gerekli Gerekli Gerekli
Sonsuz kaydırma / tembel yüklemeCannot triggerGerekli Gerekli Gerekli Gerekli Gerekli Gerekli Gerekli
Girişin Arkasındaki İçerik + JSZor Zor Zor Zor Zor ZorÖnerilen önerilen önerilen önerilen
Pages with anti-bot JS checksBaşarısızlık tespitiGerekli Gerekli Gerekli Gerekli Gerekli Gerekli Gerekli
Her zaman site bir kafasız tarayıcıya ulaşmadan önce bir API veya sunucu yönlendirme varsa kontrol edin. Birçok "JavaScript-heavy" siteleri aslında temiz JSON'u geri döndüren API uç noktalarına sahiptir - kazımak için çok daha hızlı ve daha ucuz.

Puppeteer + Proxies (Node.js)

Puppeteer Chrome/Chromium programınımatik olarak kontrol eder. Node.js için en olgun başsız tarayıcı aracıdır.

ProxyHat ile Temel Kurulum

const puppeteer = require('puppeteer');
async function scrapeWithPuppeteer(url) {
  const browser = await puppeteer.launch({
    headless: 'new',
    args: [
      '--proxy-server=http://gate.proxyhat.com:8080',
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-dev-shm-usage',
    ],
  });
  const page = await browser.newPage();
  // Authenticate with proxy
  await page.authenticate({
    username: 'USERNAME',
    password: 'PASSWORD',
  });
  // Set realistic viewport and user agent
  await page.setViewport({ width: 1920, height: 1080 });
  await page.setUserAgent(
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' +
    '(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
  );
  try {
    await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 });
    // Wait for specific content to render
    await page.waitForSelector('.product-list', { timeout: 10000 });
    const content = await page.content();
    const data = await page.evaluate(() => {
      return Array.from(document.querySelectorAll('.product-item')).map(el => ({
        name: el.querySelector('.product-name')?.textContent?.trim(),
        price: el.querySelector('.product-price')?.textContent?.trim(),
        url: el.querySelector('a')?.href,
      }));
    });
    return { html: content, data };
  } finally {
    await browser.close();
  }
}
// Usage
const result = await scrapeWithPuppeteer('https://example.com/products');
console.log(`Found ${result.data.length} products`);

Multi-Page Yararlandı

const puppeteer = require('puppeteer');
class PuppeteerScraper {
  constructor(concurrency = 3) {
    this.concurrency = concurrency;
    this.browser = null;
  }
  async init() {
    this.browser = await puppeteer.launch({
      headless: 'new',
      args: [
        '--proxy-server=http://gate.proxyhat.com:8080',
        '--no-sandbox',
        '--disable-setuid-sandbox',
        '--disable-dev-shm-usage',
        '--disable-gpu',
        '--disable-extensions',
      ],
    });
  }
  async scrapePage(url) {
    const page = await this.browser.newPage();
    await page.authenticate({ username: 'USERNAME', password: 'PASSWORD' });
    await page.setViewport({ width: 1920, height: 1080 });
    // Block unnecessary resources to speed up loading
    await page.setRequestInterception(true);
    page.on('request', (req) => {
      const type = req.resourceType();
      if (['image', 'stylesheet', 'font', 'media'].includes(type)) {
        req.abort();
      } else {
        req.continue();
      }
    });
    try {
      await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
      const content = await page.content();
      return { url, status: 'success', html: content };
    } catch (err) {
      return { url, status: 'error', error: err.message };
    } finally {
      await page.close();
    }
  }
  async scrapeMany(urls) {
    const results = [];
    for (let i = 0; i < urls.length; i += this.concurrency) {
      const batch = urls.slice(i, i + this.concurrency);
      const batchResults = await Promise.all(
        batch.map(url => this.scrapePage(url))
      );
      results.push(...batchResults);
      console.log(`Progress: ${results.length}/${urls.length}`);
    }
    return results;
  }
  async close() {
    if (this.browser) await this.browser.close();
  }
}
// Usage
const scraper = new PuppeteerScraper(3);
await scraper.init();
const results = await scraper.scrapeMany(urls);
await scraper.close();

Playwright + Proxies (Python)

Playwright, Chromium, Firefox ve WebKit'i destekleyen yeni bir alternatiftir. Python API'si temiz ve kazı için uygun.

Temel Kurulum

from playwright.sync_api import sync_playwright
def scrape_with_playwright(url: str) -> dict:
    """Scrape a JavaScript-heavy page using Playwright with ProxyHat proxy."""
    with sync_playwright() as p:
        browser = p.chromium.launch(
            headless=True,
            proxy={
                "server": "http://gate.proxyhat.com:8080",
                "username": "USERNAME",
                "password": "PASSWORD",
            }
        )
        context = browser.new_context(
            viewport={"width": 1920, "height": 1080},
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                       "AppleWebKit/537.36 (KHTML, like Gecko) "
                       "Chrome/120.0.0.0 Safari/537.36",
        )
        page = context.new_page()
        try:
            page.goto(url, wait_until="networkidle", timeout=60000)
            # Wait for dynamic content
            page.wait_for_selector(".product-list", timeout=10000)
            # Extract data using page.evaluate
            products = page.evaluate("""() => {
                return Array.from(document.querySelectorAll('.product-item')).map(el => ({
                    name: el.querySelector('.product-name')?.textContent?.trim(),
                    price: el.querySelector('.product-price')?.textContent?.trim(),
                    url: el.querySelector('a')?.href,
                }));
            }""")
            return {"url": url, "products": products, "html": page.content()}
        finally:
            browser.close()

Async Playwright for Paralel Haping

import asyncio
from playwright.async_api import async_playwright
async def scrape_batch(urls: list[str], concurrency: int = 3) -> list[dict]:
    """Scrape multiple JS-heavy pages in parallel using Playwright."""
    results = []
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=True,
            proxy={
                "server": "http://gate.proxyhat.com:8080",
                "username": "USERNAME",
                "password": "PASSWORD",
            }
        )
        semaphore = asyncio.Semaphore(concurrency)
        async def scrape_one(url: str) -> dict:
            async with semaphore:
                context = await browser.new_context(
                    viewport={"width": 1920, "height": 1080},
                )
                page = await context.new_page()
                # Block heavy resources
                await page.route("**/*.{png,jpg,jpeg,gif,svg,css,woff,woff2}",
                                 lambda route: route.abort())
                try:
                    await page.goto(url, wait_until="networkidle", timeout=30000)
                    html = await page.content()
                    return {"url": url, "status": "success", "html": html}
                except Exception as e:
                    return {"url": url, "status": "error", "error": str(e)}
                finally:
                    await context.close()
        tasks = [scrape_one(url) for url in urls]
        results = await asyncio.gather(*tasks)
        await browser.close()
    return results
# Usage
urls = [f"https://example.com/product/{i}" for i in range(50)]
results = asyncio.run(scrape_batch(urls, concurrency=5))

Go: Kromdp ile Proxies

package main
import (
    "context"
    "fmt"
    "log"
    "time"
    "github.com/chromedp/chromedp"
)
func scrapeJSPage(targetURL string) (string, error) {
    // Configure proxy
    opts := append(chromedp.DefaultExecAllocatorOptions[:],
        chromedp.ProxyServer("http://gate.proxyhat.com:8080"),
        chromedp.Flag("headless", true),
        chromedp.Flag("disable-gpu", true),
        chromedp.Flag("no-sandbox", true),
        chromedp.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) "+
            "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"),
    )
    allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
    defer cancel()
    ctx, cancel := chromedp.NewContext(allocCtx)
    defer cancel()
    ctx, cancel = context.WithTimeout(ctx, 60*time.Second)
    defer cancel()
    var htmlContent string
    err := chromedp.Run(ctx,
        chromedp.Navigate(targetURL),
        chromedp.WaitVisible(".product-list", chromedp.ByQuery),
        chromedp.OuterHTML("html", &htmlContent),
    )
    if err != nil {
        return "", fmt.Errorf("scrape failed: %w", err)
    }
    return htmlContent, nil
}
func main() {
    html, err := scrapeJSPage("https://example.com/products")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Got %d bytes of rendered HTML\n", len(html))
}

Performans Optimizasyon Stratejileri

Headless tarayıcılar basit HTTP isteklerinden 10-50x daha yavaştır. İşte performans boşluğunu en aza indirmek için stratejiler:

1. Gerekli Kaynaklar

Görüntüler, CSS, fontlar ve medya dosyaları veri ekstraksiyonu için gerekli değildir. Onları önemli ölçüde sayfa yüklerini engeller:

# Playwright resource blocking
async def fast_scrape(page, url):
    # Block images, CSS, fonts, media
    await page.route("**/*.{png,jpg,jpeg,gif,svg,css,woff,woff2,mp4,webm}",
                     lambda route: route.abort())
    # Also block tracking scripts
    await page.route("**/*google-analytics*", lambda route: route.abort())
    await page.route("**/*facebook*", lambda route: route.abort())
    await page.goto(url, wait_until="domcontentloaded")  # Faster than networkidle
    return await page.content()

2. Doğru Bekle Stratejisi Kullanın

2. Doğru Bekle Stratejisi Kullanın
Strateji StratejisiHız Hız Hız HızReliabilityVaka Kullanımı
domcontentloadedHızlı Hızlı Hızlı HızlıAsync verilerini kaçırabilirPages with inline data
loadMedium Medium Medium Medium Mediumİyi İyi İyi İyi İyiÇoğu sayfa
networkidleYavaş yavaş yavaş yavaş yavaş yavaşEn yüksekAğır SPAs, sonsuz kaydırma
Özel seçimciDeğişken Değişken Değişken DeğişkenEn yüksekHedef elementini bildiğinizde

3. Reuse Browser Instances

Bir tarayıcı kurmak 1-3 saniye sürer. Oylama için, bir kez açın ve her URL için yeni sayfalar / metinler oluşturun:

from playwright.sync_api import sync_playwright
class BrowserPool:
    """Reusable browser pool for efficient headless scraping."""
    def __init__(self, pool_size: int = 3):
        self.pool_size = pool_size
        self.playwright = None
        self.browsers = []
    def start(self):
        self.playwright = sync_playwright().start()
        for _ in range(self.pool_size):
            browser = self.playwright.chromium.launch(
                headless=True,
                proxy={
                    "server": "http://gate.proxyhat.com:8080",
                    "username": "USERNAME",
                    "password": "PASSWORD",
                }
            )
            self.browsers.append(browser)
    def get_browser(self, index: int):
        return self.browsers[index % self.pool_size]
    def stop(self):
        for browser in self.browsers:
            browser.close()
        self.playwright.stop()
# Usage
pool = BrowserPool(pool_size=3)
pool.start()
for i, url in enumerate(urls):
    browser = pool.get_browser(i)
    context = browser.new_context()
    page = context.new_page()
    page.goto(url, wait_until="networkidle")
    html = page.content()
    context.close()
pool.stop()

4. Intercept API Çağrıları Parsing DOM yerine

Birçok SPAs API'lerden veri getiriyor. Bu API aramalarını doğrudan kabul edin – HTML'yi parsing olmadan JSON'u temizleyebilirsiniz:

const puppeteer = require('puppeteer');
async function interceptAPIData(url) {
  const browser = await puppeteer.launch({
    headless: 'new',
    args: ['--proxy-server=http://gate.proxyhat.com:8080'],
  });
  const page = await browser.newPage();
  await page.authenticate({ username: 'USERNAME', password: 'PASSWORD' });
  const apiResponses = [];
  // Intercept XHR/fetch responses
  page.on('response', async (response) => {
    const url = response.url();
    if (url.includes('/api/') || url.includes('/graphql')) {
      try {
        const json = await response.json();
        apiResponses.push({ url, data: json });
      } catch {
        // Not JSON, skip
      }
    }
  });
  await page.goto(url, { waitUntil: 'networkidle2' });
  await browser.close();
  return apiResponses;
}
// Get clean API data instead of scraping DOM
const data = await interceptAPIData('https://example.com/products');
console.log(`Intercepted ${data.length} API calls`);

Headless Browser vs HTTP Karşılaştırma

Headless Browser vs HTTP Karşılaştırma
MetrikBasit HTTP + ProxyHeadless Browser + Proxy
Sayfa başına Hız0,5-2 saniye3-15 saniye
Örneğin bellek~50 MB200-500 MB
CPU kullanımıMinimal Minimal Minimal MinimalÖnemli Önemli Önemli Önemli
Sayfa başına Band genişlik50-200 KB2-10 MB ( kaynaklarla)
JavaScript oluşturma JavaScriptHayır hayır hayırFull Full Full Full Full Full Full Full Full Full Full
Anti-bot atSınırlı Sınırlı Sınırlı Sınırlı Sınırlı SınırlıBetter (real tarayıcı)
Eş zamanlı sayfalar100+3-10 makine başına

En İyi Uygulamaları

  • Her zaman önce HTTP'yi deneyin. API uç noktaları için kontrol edin, server-rendered content, veya JSON bir kafasız tarayıcı kullanmadan önce HTML'de gömülür.
  • Blok gereksiz kaynaklar. Görüntüler, CSS ve fontlar veri sağlamadan zaman ekler.
  • Beklemek için belirli seçiciler kullanın. networkidle Güvenli ama yavaş. İhtiyacınız olan belirli element için bekleyin.
  • Reuse tarayıcı örnekleri. Bir kez başlayın, sayfa başına yeni bağlamlar oluşturun.
  • Intercept API çağrıları. Birçok SPAs API'ler aracılığıyla veri yükler - JSON'u doğrudan ele alın.
  • Sınır tutarlılığı. Headless tarayıcılar hafıza yoğundur. RAM GB başına 3-5 eşzamanlı sayfa iyi bir kuraldır.
  • Ev sahibi kullanın. ProxyHat konut proxy En yüksek güven puanlarını sağlar, kafasız tarayıcılar çalışırken algılamayı azaltır.

CAPTCHAs that headless browsers karşılaşması için, bakınız CAPTCHAs Ne zaman avlanır.Kayıtsız tarayıcıyı yok etmek için, okuyun Nasıl Ölçeği Kaçmak.

Get started with the Python SDK, Node SDKYa da Go SDK Bütünleme için ve keşfedin Web için ProxyHat.

Sık Sorulan Sorular

JavaScript siteleri için daima kafasız bir tarayıcıya ihtiyacım var mı?

Hayır. Birçok JavaScript-heavy siteleri API uç noktalarından veri yükler. Tarayıcının XHR/fetch talepleri için Ağ sekmesini kontrol edin - eğer veriler bir API'den geliyorsa, API'yi doğrudan bir proxy aracılığıyla basit taleplerle çağırabilirsiniz, bu çok daha hızlı.

Puppeteer ya da Playwright – bu kazı için daha iyi?

Playwright genellikle yeni projeler için önerilir. Birden fazla tarayıcı motorunu destekliyor (Chromium, Firefox, WebKit), Python'da daha iyi bir oto beklenen desteği ve yerleşik proxy yapılandırmasını destekliyor. Puppeteer daha olgun ve Node.js dünyasındaysanız daha büyük bir ekosisteme sahiptir.

Kaç kafasız tarayıcı sayfası eş zamanlı olarak çalıştırabilir miyim?

Her sayfa 200-500 MB RAM tüketiyor. 8 GB RAM ile bir makinede, 3-10 eş zamanlı sayfalar gerçekçi. hafızayı azaltmak için kaynak engelleme (görüntüler, CSS) kullanın. Daha yüksek koncurrency için, kuyruk tabanlı bir mimari kullanarak birden fazla makineye dağıtın.

Neden başsız tarayıcılarla proxy kullanın?

Gerçek bir tarayıcı ile bile, aynı IP'den tekrarlanan istekler bloke edilir. Proxies IP'nizi döndürür, böylece her sayfa yükü farklı bir kullanıcıdan gelir. ProxyHat aracılığıyla ev sahipleri en yüksek güven puanlarını, minimiz bloklarını ve CAPTCHAs'yi sağlar.

Başlamaya hazır mısınız?

148+ ülkede 50M+ konut IP'sine AI destekli filtreleme ile erişin.

Fiyatlandırmayı GörüntüleKonut Proxy'leri
← Bloga Dön