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?
| Scenario | Basit HTTP | Headless Browser |
|---|---|---|
| Statik HTML sayfaları | Mükemmel işler | Overkill |
| API ile Server-rendered sayfalar | Works (API doğrudan) | Gerekli değil |
| SPA (React, Vue, Angular) | Boş kabuk alın | Gerekli Gerekli Gerekli Gerekli Gerekli Gerekli Gerekli |
| Sonsuz kaydırma / tembel yükleme | Cannot trigger | Gerekli Gerekli Gerekli Gerekli Gerekli Gerekli Gerekli |
| Girişin Arkasındaki İçerik + JS | Zor Zor Zor Zor Zor Zor | Önerilen önerilen önerilen önerilen |
| Pages with anti-bot JS checks | Başarısızlık tespiti | Gerekli 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
| Strateji Stratejisi | Hız Hız Hız Hız | Reliability | Vaka Kullanımı |
|---|---|---|---|
domcontentloaded | Hızlı Hızlı Hızlı Hızlı | Async verilerini kaçırabilir | Pages with inline data |
load | Medium Medium Medium Medium Medium | İyi İyi İyi İyi İyi | Çoğu sayfa |
networkidle | Yavaş yavaş yavaş yavaş yavaş yavaş | En yüksek | Ağır SPAs, sonsuz kaydırma |
| Özel seçimci | Değişken Değişken Değişken Değişken | En yüksek | Hedef 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
| Metrik | Basit HTTP + Proxy | Headless Browser + Proxy |
|---|---|---|
| Sayfa başına Hız | 0,5-2 saniye | 3-15 saniye |
| Örneğin bellek | ~50 MB | 200-500 MB |
| CPU kullanımı | Minimal Minimal Minimal Minimal | Önemli Önemli Önemli Önemli |
| Sayfa başına Band genişlik | 50-200 KB | 2-10 MB ( kaynaklarla) |
| JavaScript oluşturma JavaScript | Hayır hayır hayır | Full Full Full Full Full Full Full Full Full Full Full |
| Anti-bot at | Sınırlı Sınırlı Sınırlı Sınırlı Sınırlı Sınırlı | Better (real tarayıcı) |
| Eş zamanlı sayfalar | 100+ | 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.
networkidleGü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.






