🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

পাইথন ওয়েব স্ক্র্যাপিং 2026: নাট্যকার, স্ক্র্যাপি, সুন্দর স্যুপ গাইড

⏱️5 min read  ·  911 words

2026 সালে ওয়েব স্ক্র্যাপিংয়ের জন্য কাজের জন্য সঠিক টুলের প্রয়োজন: স্ট্যাটিক পৃষ্ঠাগুলির জন্য অনুরোধ + সুন্দর স্যুপ, জাভাস্ক্রিপ্ট-ভারী সাইটের জন্য নাট্যকার, বড় আকারের ক্রলিংয়ের জন্য স্ক্র্যাপি এবং সুরক্ষিত সাইটের জন্য অ্যান্টি-বট বাইপাস কৌশল। এই গাইড তাদের সব কভার.

2026 সালে ওয়েব স্ক্র্যাপিং স্ট্যাক

  • অনুরোধ + সুন্দর স্যুপ– স্ট্যাটিক HTML পৃষ্ঠাগুলির জন্য সহজ, দ্রুত
  • httpx— অ্যাসিঙ্ক অনুরোধ, HTTP/2 সমর্থন
  • নাট্যকার (পাইথন)— সম্পূর্ণ ব্রাউজার অটোমেশন, জেএস রেন্ডারিং
  • স্ক্র্যাপি— প্রোডাকশন-গ্রেড স্পাইডার ফ্রেমওয়ার্ক, বিল্ট-ইন পাইপলাইন
  • সেলেনিয়াম— উত্তরাধিকার, পরিবর্তে নাট্যকার ব্যবহার করুন
  • হামাগুড়ি— অটো-স্কেলিংয়ের সাথে আধুনিক নাট্যকার-ভিত্তিক কাঠামো

অনুরোধ + সুন্দর স্যুপ: স্ট্যাটিক পেজ

pip install requests beautifulsoup4 lxml

import requests
from bs4 import BeautifulSoup

# Basic scrape with headers (avoid 403 errors)
headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
}

response = requests.get("https://news.ycombinator.com", headers=headers, timeout=10)
response.raise_for_status()

soup = BeautifulSoup(response.text, "lxml")

# Extract Hacker News titles
stories = []
for item in soup.select(".athing"):
    title_tag = item.select_one(".titleline a")
    score_tag = item.find_next_sibling().select_one(".score")
    if title_tag:
        stories.append({
            "title": title_tag.get_text(strip=True),
            "url": title_tag.get("href"),
            "score": int(score_tag.get_text().split()[0]) if score_tag else 0
        })

# Sort by score
stories.sort(key=lambda x: x["score"], reverse=True)
for story in stories[:10]:
    print(f"{story['score']:4d} | {story['title'][:70]}")

httpx এর সাথে Async স্ক্র্যাপিং

import asyncio
import httpx
from bs4 import BeautifulSoup

async def scrape_page(client: httpx.AsyncClient, url: str) -> dict:
    response = await client.get(url)
    response.raise_for_status()
    soup = BeautifulSoup(response.text, "lxml")
    return {
        "url": url,
        "title": soup.find("h1").get_text(strip=True) if soup.find("h1") else "",
        "text": soup.get_text(separator=" ", strip=True)[:500]
    }

async def scrape_many(urls: list[str]) -> list[dict]:
    headers = {"User-Agent": "Mozilla/5.0 compatible"}
    limits = httpx.Limits(max_connections=10, max_keepalive_connections=5)

    async with httpx.AsyncClient(headers=headers, limits=limits, timeout=15) as client:
        tasks = [scrape_page(client, url) for url in urls]
        results = await asyncio.gather(*tasks, return_exceptions=True)

    return [r for r in results if not isinstance(r, Exception)]

urls = [
    "https://techpulsesite.com/python-asyncio-guide-2026/",
    "https://techpulsesite.com/docker-complete-guide-2026/",
]
data = asyncio.run(scrape_many(urls))
print(f"Scraped {len(data)} pages")

নাট্যকার: জাভাস্ক্রিপ্ট-রেন্ডার করা সাইট

pip install playwright
playwright install chromium

from playwright.async_api import async_playwright
import asyncio

async def scrape_spa(url: str) -> dict:
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        context = await browser.new_context(
            user_agent="Mozilla/5.0 compatible",
            viewport={"width": 1280, "height": 720}
        )
        page = await context.new_page()

        # Navigate and wait for content to load
        await page.goto(url, wait_until="networkidle")

        # Wait for specific element
        await page.wait_for_selector(".product-list", timeout=10000)

        # Extract data
        products = []
        items = await page.query_selector_all(".product-card")
        for item in items:
            title = await item.query_selector(".product-title")
            price = await item.query_selector(".product-price")
            products.append({
                "name": await title.inner_text() if title else "",
                "price": await price.inner_text() if price else ""
            })

        await browser.close()
        return {"url": url, "products": products}

# Screenshot for debugging
async def screenshot_page(url: str):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        await page.goto(url, wait_until="networkidle")
        await page.screenshot(path="page.png", full_page=True)
        await browser.close()

result = asyncio.run(scrape_spa("https://example-spa.com/products"))
print(f"Found {len(result['products'])} products")

স্ক্র্যাপি: বড় আকারের ক্রলিং

pip install scrapy
scrapy startproject techpulse_crawler
cd techpulse_crawler
scrapy genspider tech_spider techpulsesite.com

# spiders/tech_spider.py
import scrapy

class TechSpider(scrapy.Spider):
    name = "tech_spider"
    allowed_domains = ["techpulsesite.com"]
    start_urls = ["https://techpulsesite.com/"]
    custom_settings = {
        "DOWNLOAD_DELAY": 1,           # polite: 1s between requests
        "CONCURRENT_REQUESTS": 8,
        "ROBOTSTXT_OBEY": True,
        "USER_AGENT": "TechBot/1.0 (+https://techpulsesite.com)",
    }

    def parse(self, response):
        # Extract article links
        for link in response.css("article a::attr(href)").getall():
            yield response.follow(link, callback=self.parse_article)

        # Follow pagination
        next_page = response.css("a.next-page::attr(href)").get()
        if next_page:
            yield response.follow(next_page, callback=self.parse)

    def parse_article(self, response):
        yield {
            "url": response.url,
            "title": response.css("h1::text").get("").strip(),
            "author": response.css(".author-name::text").get(""),
            "date": response.css("time::attr(datetime)").get(""),
            "tags": response.css(".tag::text").getall(),
            "content": " ".join(response.css("article p::text").getall()),
        }

# Run spider
# scrapy crawl tech_spider -o output.json

অ্যান্টি-বট সুরক্ষা হ্যান্ডলিং

import time, random

# Random delays between requests
time.sleep(random.uniform(1, 3))

# Rotate user agents
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_1) AppleWebKit/605.1.15 Safari/605.1.15",
    "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0",
]

# Use sessions with cookies
session = requests.Session()
session.headers.update({"User-Agent": random.choice(USER_AGENTS)})

# For Cloudflare-protected sites: use Playwright (renders JS, handles challenges)
# Or commercial services: Bright Data, Oxylabs, ScraperAPI, ZenRows

# Playwright with stealth plugin
from playwright.async_api import async_playwright

async def scrape_protected(url: str):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)  # non-headless for better scores
        context = await browser.new_context(
            user_agent=random.choice(USER_AGENTS),
            locale="en-US",
            timezone_id="America/New_York",
        )
        page = await context.new_page()
        # Mask automation signals
        await page.add_init_script("delete Object.getPrototypeOf(navigator).webdriver")
        await page.goto(url)
        content = await page.content()
        await browser.close()
        return content

ডেটা স্টোরেজ

import json, csv
from pathlib import Path

# JSON
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(results, f, indent=2, ensure_ascii=False)

# CSV
with open("data.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["title", "url", "price", "date"])
    writer.writeheader()
    writer.writerows(results)

# SQLite via Python built-in
import sqlite3
conn = sqlite3.connect("scraped.db")
conn.execute("CREATE TABLE IF NOT EXISTS articles (id INTEGER PRIMARY KEY, title TEXT, url TEXT UNIQUE, content TEXT)")
conn.executemany("INSERT OR IGNORE INTO articles (title, url, content) VALUES (?,?,?)",
                 [(r["title"], r["url"], r["content"]) for r in results])
conn.commit()

আইনি ও নৈতিক নির্দেশিকা

  • robots.txt চেক করুন— সাইটের ক্রল নিয়মগুলিকে সম্মান করুন
  • আপনার অনুরোধ সীমিত হার– অনুরোধের মধ্যে ন্যূনতম 1-3 সেকেন্ড
  • সার্ভার ওভারলোড করবেন না– কম সমসাময়িক সংযোগ
  • পরিষেবার শর্তাবলী পরীক্ষা করুন— কিছু সাইট স্পষ্টভাবে স্ক্র্যাপিং নিষিদ্ধ করে
  • বাণিজ্যিকভাবে স্ক্র্যাপ করা ডেটা ব্যবহার করবেন না– যথাযথ লাইসেন্স ছাড়া
  • উপলব্ধ হলে অফিসিয়াল API ব্যবহার করুন– প্রথম পছন্দ, সর্বদা

2026 সালে পাইথন ওয়েব স্ক্র্যাপিং একটি বিস্তৃত বর্ণালী কভার করে। সাধারণ HTML-এর জন্য অনুরোধ + সুন্দর স্যুপ ব্যবহার করুন, জাভাস্ক্রিপ্ট-ভারী পৃষ্ঠাগুলির জন্য নাট্যকার এবং প্রোডাকশন-স্কেল ক্রলিংয়ের জন্য স্ক্র্যাপি ব্যবহার করুন। আপনি যে সাইটগুলিকে স্ক্র্যাপ করেন সেগুলির প্রতি সর্বদা শ্রদ্ধাশীল হন এবং উপলব্ধ হলে অফিসিয়াল API পছন্দ করেন৷

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা