# Technical Documentation: D4Vinci/Scrapling

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/D4Vinci/Scrapling)

### Overview (`README.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Scrapling Poster" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>Effortless Web Scraping for the Modern Web</small>
</h1>

<p align="center">
    <a href="https://trendshift.io/repositories/14244" target="_blank"><img src="https://trendshift.io/api/badge/repositories/14244" alt="D4Vinci%2FScrapling | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
    <a href="https://www.star-history.com/d4vinci/scrapling"><img src="https://api.star-history.com/badge?repo=D4Vinci/Scrapling&type=rank" alt="Star History Rank" style="height: 55px;" height="55"/></a>
    <br/>
    <a href="https://github.com/D4Vinci/Scrapling/blob/main/docs/README_AR.md"><img alt="README بالعربية" title="README بالعربية" src="https://img.shields.io/badge/Arabic-DFE0E5"></a>
    <a href="https://github.com/D4Vinci/Scrapling/blob/main/docs/README_ES.md"><img alt="README en Español" src="https://img.shields.io/badge/Español-DFE0E5"></a>
    <a href="https://github.com/D4Vinci/Scrapling/blob/main/docs/README_PT_BR.md"><img alt="README em Português (Brasil)" src="https://img.shields.io/badge/Português%20(Brasil)-DFE0E5"></a>
    <a href="https://github.com/D4Vinci/Scrapling/blob/main/docs/README_FR.md"><img alt="README en Français" src="https://img.shields.io/badge/Français-DFE0E5"></a>
    <a href="https://github.com/D4Vinci/Scrapling/blob/main/docs/README_DE.md"><img alt="README auf Deutsch" src="https://img.shields.io/badge/Deutsch-DFE0E5"></a>
    <a href="https://github.com/D4Vinci/Scrapling/blob/main/docs/README_CN.md"><img alt="简体中文版自述文件" src="https://img.shields.io/badge/简体中文-DFE0E5"></a>
    <a href="https://github.com/D4Vinci/Scrapling/blob/main/docs/README_JP.md"><img alt="日本語のREADME" src="https://img.shields.io/badge/日本語-DFE0E5"></a>
    <a href="https://github.com/D4Vinci/Scrapling/blob/main/docs/README_RU.md"><img alt="Русская версия README" src="https://img.shields.io/badge/Русский-DFE0E5"></a>
    <a href="https://github.com/D4Vinci/Scrapling/blob/main/docs/README_KR.md"><img alt="한국어 README" src="https://img.shields.io/badge/한국어-DFE0E5"></a>
    <br/>
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="Tests">
        <img alt="Tests" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="PyPI version">
        <img alt="PyPI version" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="PyPI package downloads"></a>
    <a href="https://scrapling.readthedocs.io/en/latest/ai/agent-skill.html" alt="AI Agent Skill">
        <img alt="Static Badge" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Fen%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="OpenClaw Skill">
        <img alt="OpenClaw Skill" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X (formerly Twitter)">
      <img alt="X (formerly Twitter) Follow" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="Supported Python versions">
        <img alt="Supported Python versions" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/en/latest/parsing/selection.html"><strong>Selection methods</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/en/latest/fetching/choosing.html"><strong>Fetchers</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/en/latest/spiders/architecture.html"><strong>Spiders</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/en/latest/spiders/proxy-blocking.html"><strong>Proxy Rotation</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/en/latest/cli/overview.html"><strong>CLI</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/en/latest/ai/mcp-server.html"><strong>MCP</strong></a>
</p>

Scrapling is a Python Web Scraping framework that brings fast HTTP requests, stealth browsers, powerful parsing, and concurrent crawling into one library.

Scrape static pages, render JavaScript, interact with websites, and extract data from the API calls behind them. Build crawlers with reusable sessions, proxy rotation, automatic retries, pause/resume, and built-in data exports.

Use it from Python, the terminal, or your AI agent through its MCP server and Agent Skill. From extracting a few fields to collecting a whole website as clean Markdown, Scrapling covers the full scraping workflow.

## What you can do with Scrapling

- **[Fetch & interact](https://scrapling.readthedocs.io/en/latest/fetching/choosing.html)**: Fast HTTP requests, stealth browsers, JavaScript rendering, Cloudflare Turnstile/Interstitial handling, persistent sessions, and background API capture.
- **[Parse & extract](https://scrapling.readthedocs.io/en/latest/parsing/selection.html)**: CSS, XPath, text and regex search, adaptive element tracking, similar-element matching, and clean Markdown output.
- **[Crawl & export](https://scrapling.readthedocs.io/en/latest/spiders/getting-started.html)**: Concurrent spiders, proxy rotation, retries, AutoThrottle, pause/resume, streaming, ready-made templates, and JSON/JSONL/CSV/XML exports.
- **[Scrape with AI or from your terminal](https://scrapling.readthedocs.io/en/latest/ai/mcp-server.html)**: An MCP server for AI agents to browse and extract data, an Agent Skill, CLI commands, and an interactive shell.

Start with a single page:

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

Or scale up with a spider:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

This prints `10` and saves the quotes and authors to `quotes.json`.

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# Platinum Sponsors
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> - The most efficient proxy provider for Web Scraping and Automation with the Highest Quality IP on the market. Use code SCRAPLING35 for 35% discount.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling handles Cloudflare Turnstile. For enterprise-grade protection, <a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a> provides API endpoints that generate valid antibot tokens for <b>Akamai</b>, <b>DataDome</b>, <b>Kasada</b>, and <b>Incapsula</b>. Simple API calls, no browser automation required. </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a>: residential proxies from $0.49/GB. Scraping browser with fully spoofed Chromium, residential IPs, auto CAPTCHA solving, and anti-bot bypass. </br>
      <b>Scraper API for hassle-free results. MCP and N8N integrations are available.</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    Read a full review of <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">Scrapling on The Web Scraping Club</a> (Nov 2025), the #1 newsletter dedicated to Web Scraping.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a> provides scalable residential proxies with 80M+ IPs across 195+ countries, delivering fast, reliable connections, automatic rotation, and strong anti-block performance. Free trial available.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a> supplies ethical residential, mobile, ISP, and datacenter proxies, plus scraping and AI automation tools. Use code SCRAPLING10: 10% off residential proxies.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a>: Reduce blocks and CAPTCHAs by 90%. 28M Premium Residential IPs for Heavy Web Scraping. 195 countries. City/ISP/ZIP targeting. Sticky/rotating sessions. Non-expiring traffic from $2/GB. Code <strong>SCRAPEANDTAKE</strong>: <em>25% off</em>.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a>: Stop paying per GB. Unlimited residential traffic, 100M+ IPs, 190+ countries. Pay by bandwidth. Request a free 50 Mbps residential proxies trial.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    $1/GB at <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a>. Ethical first-party proxies. 90M+ IPs, 195+ countries. Residential, datacenter, mobile. Pay-as-you-go = no subscription. Traffic never expires.
    </td>
  </tr>
</table>

<i><sub>Do you want to show your ad here? Click [here](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)</sub></i>
# Sponsors 



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>Do you want to show your ad here? Click [here](https://github.com/sponsors/D4Vinci) and choose the tier that suits you!</sub></i>

---

## Key Features

### Spiders - A Full Crawling Framework
- 🕷️ **Scrapy-like Spider API**: Define spiders with `start_urls`, async `parse` callbacks, and `Request`/`Response` objects.
- ⚡ **Concurrent Crawling**: Configurable concurrency limits, per-domain throttling, and download delays.
- 🔄 **Multi-Session Support**: Unified interface for HTTP requests, and stealthy headless browsers in a single spider - route requests to different sessions by ID.
- 💾 **Pause & Resume**: Save pending requests and seen URLs with `crawldir`. Press Ctrl+C to stop gracefully and restart with the same directory.
- 📡 **Streaming Mode**: Stream scraped items as they arrive via `async for item in spider.stream()` with real-time stats - ideal for UI, pipelines, and long-running crawls.
- 🛡️ **Blocked Request Detection**: Automatic detection and retry of blocked requests with customizable logic.
- 🚦 **AutoThrottle**: Stop guessing delays. The spider tunes the delay of each domain on its own from how fast the website responds, then doubles it (or waits what `Retry-After` asks) whenever the website starts blocking or rate-limiting you, and speeds back up once it stops.
- 🤖 **Robots.txt Compliance**: Optional `robots_txt_obey` flag that respects `Disallow`, `Crawl-delay`, and `Request-rate` directives with per-domain caching.
- 🧪 **Development Mode**: Cache responses to disk on the first run and replay them on subsequent runs - iterate on your `parse()` logic without re-hitting the target servers.
- 🧩 **Ready-made Spider Templates**: Skip the boilerplate with `CrawlSpider` for rule-based link following, `SitemapSpider` for sitemap/robots.txt-driven crawls, `XMLFeedSpider`/`CSVFeedSpider` for iterating XML/RSS and CSV feeds, and `ShopifySpider` to collect products from public Shopify stores, one item per variant.
- 🔗 **Link Extraction**: A standalone `LinkExtractor` primitive with allow/deny patterns, domain filters, CSS/XPath scoping, extension filtering, and canonicalization - use it inside the templates or on its own.
- 📦 **Built-in Export**: Export results through hooks and your own pipeline or the built-in JSON/JSONL/CSV/XML exporters with `result.items.to_json()`, `to_jsonl()`, `to_csv()`, and `to_xml()`.

### Advanced Websites Fetching with Session Support
- **HTTP Requests**: Fast and stealthy HTTP requests with the `Fetcher` class. Can impersonate browsers' TLS fingerprint, headers, and use HTTP/3.
- **Dynamic Loading**: Fetch dynamic websites with full browser automation through the `StealthyFetcher` class supporting Playwright's Chromium and Google's Chrome.
- **Anti-bot Bypass**: Advanced stealth capabilities with `StealthyFetcher` and fingerprint spoofing. Can easily bypass all types of Cloudflare's Turnstile/Interstitial with automation.
- **Session Management**: Persistent session support with `FetcherSession` and `StealthySession` classes for cookie and state management across requests.
- **Proxy Rotation**: Built-in `ProxyRotator` with cyclic or custom rotation strategies across all session types, plus per-request proxy overrides.
- **Domain & Ad Blocking**: Block requests to specific domains (and their subdomains) or enable built-in ad blocking (~3,500 known ad/tracker domains) in browser-based fetchers.
- **DNS Leak Prevention**: Optional DNS-over-HTTPS support to route DNS queries through Cloudflare's DoH, preventing DNS leaks when using proxies.
- **Remote Browsers**: Instead of launching a browser locally, connect to one that's already running through CDP with `cdp_url`, whether it's on the same machine, another host, or a managed browser provider. You can also point any browser fetcher at your own Chromium build with `executable_path`.
- **Background API Capture**: Enable `record_requests=True` on a browser session, then search its saved responses with `session.network.search(limit=None)`. Read API data and HTTP errors across page loads without sending requests again. History is bounded and saves text response bodies.
- **Async Support**: Complete async support across all fetchers and dedicated async session classes.

### Parsing and Data Extraction
- 🔄 **Smart Element Tracking**: Relocate elements after website changes using intelligent similarity algorithms.
- 🎯 **Smart Flexible Selection**: CSS selectors, XPath selectors, filter-based search, text search, regex search, and more.
- 🔍 **Find Similar Elements**: Automatically locate elements similar to found elements.

### AI Features
- 🤖 **MCP Server**: Let AI chatbots and agents (Claude/Cursor/etc) scrape through Scrapling with HTTP requests, browser actions, screenshots, saved login state, and background API responses. Uses our stealthy browser with the right tools to enable suitable AI models to bypass any CAPTCHA is faces while working (not to mention our Cloudflare solver). It uses a lot of methods to reduce the content sent to the model, block ads, and protect it against Prompt-Injection. Remote browsers over CDP and HTTP transport with authentication options are included. ([demo video](https://www.youtube.com/watch?v=qyFk3ZNwOxE))
- 🧠 **Agent Skill**: A ready-to-install [Agent Skill](https://scrapling.readthedocs.io/en/latest/ai/agent-skill.html) that teaches coding agents the whole library, so the code they write with Scrapling matches the current API instead of guessing.
- 📚 **RAG-ready Markdown**: Turn any page into clean, sanitized, LLM-ready Markdown with one line (`page.markdown()`), or crawl a whole website into a Markdown corpus with the `ContentSpider` template, all without an LLM in the loop. ([docs](https://scrapling.readthedocs.io/en/latest/ai/building-rag-systems.html))

### High-Performance & battle-tested Architecture
- 🚀 **Lightning Fast**: Optimized performance outperforming most Python scraping libraries.
- 🔋 **Memory Efficient**: Optimized data structures and lazy loading for a minimal memory footprint.
- ⚡ **Fast JSON Serialization**: 10x faster than the standard library.
- 🏗️ **Battle tested**: Not only does Scrapling have 92% test coverage and full type hints coverage, but it has been used daily by hundreds of Web Scrapers over the past year.

### Developer/Web Scraper Friendly Experience
- 🎯 **Interactive Web Scraping Shell**: Optional built-in IPython shell with Scrapling integration, shortcuts, and new tools to speed up Web Scraping scripts development, like converting curl requests to Scrapling requests and viewing requests results in your browser.
- 🚀 **Use it directly from the Terminal**: Optionally, you can use Scrapling to scrape a URL without writing a single line of code!
- 🛠️ **Rich Navigation API**: Advanced DOM traversal with parent, sibling, and child navigation methods.
- 🧬 **Enhanced Text Processing**: Built-in regex, cleaning methods, and optimized string operations.
- 📝 **Auto Selector Generation**: Generate robust CSS/XPath selectors for any element.
- 🔌 **Familiar API**: Similar to Scrapy/BeautifulSoup with the same pseudo-elements used in Scrapy/Parsel.
- 🤝 **Drop-in Scrapy Integration**: Already invested in Scrapy? Decorate any callback with `scrapling_response` to parse the responses you already fetch with Scrapling's parser, no rewrite needed.
- 📘 **Complete Type Coverage**: Full type hints for excellent IDE support and code completion. The entire codebase is automatically scanned with **PyRight** and **MyPy** with each change.
- 🔋 **Ready Docker image**: With each release, a Docker image containing all browsers is automatically built and pushed.

## Getting Started

Let's give you a quick glimpse of what Scrapling can do without deep diving.

### Basic Usage
HTTP requests with session support
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # Use latest version of Chrome's TLS fingerprint
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# Or use one-off requests
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
Advanced stealth mode
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # Keep the browser open until you finish
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# Or use one-off request style, it opens the browser for this request, then closes it after finishing
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
Full browser automation
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # Keep the browser open until you finish
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # XPath selector if you prefer it

# Or use one-off request style, it opens the browser for this request, then closes it after finishing
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### Spiders
Build full crawlers with concurrent requests, multiple session types, and pause/resume:
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10
    
    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }
            
        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"Scraped {len(result.items)} quotes")
result.items.to_json("quotes.json")
```
Use multiple session types in a single spider:
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]
    
    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)
    
    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # Route protected pages through the stealth session
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # explicit callback
```
Pause and resume long crawls with checkpoints by running the spider like this:
```python
QuotesSpider(crawldir="./crawl_data").start()
```
With `crawldir` set, press Ctrl+C to save pending requests and seen URLs. Restart with the same `crawldir` to resume. Save scraped items separately.

Or skip writing the crawling logic altogether with the ready-made templates, like pulling an entire Shopify store's catalog:
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # Every product in the store, one item per variant
```
The template reads products exposed through public collection endpoints, one item per variant.

### Advanced Parsing & Navigation
```python
from scrapling.fetchers import Fetcher

# Rich element selection and navigation
page = Fetcher.get('https://quotes.toscrape.com/')

# Get quotes with multiple selection methods
quotes = page.css('.quote')  # CSS selector
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # BeautifulSoup-style
# Same as
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # and so on...
# Find element by text content
quotes = page.find_by_text('Albert Einstein', first_match=False)

# Advanced navigation
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # Chained selectors
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# Element relationships and similarity
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
You can use the parser right away if you don't want to fetch websites like below:
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
And it works precisely the same way!

### Async Session Management Examples
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # `FetcherSession` is context-aware and can work in both sync/async patterns
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## CLI & Interactive Shell

Scrapling includes a powerful command-line interface:

[](https://asciinema.org/a/736339)

Launch the interactive Web Scraping shell
```bash
pip install "scrapling[shell]"
scrapling shell
```
Extract pages to a file directly without programming. Use `--css-selector` to pick the content, or `--ai-targeted` to select and sanitize the `body` content. Use `.txt` for text, `.md` for Markdown, or `.html` for HTML.
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> There are many additional features, but we want to keep this page concise, including the MCP server and the interactive Web Scraping Shell. Check out the full documentation [here](https://scrapling.readthedocs.io/en/latest/)

## Performance Benchmarks

Scrapling isn't just powerful-it's also blazing fast. The following benchmarks compare Scrapling's parser with the latest versions of other popular libraries.

### Text Extraction Speed Test (5000 nested elements)

| # |      Library      | Time (ms) | vs Scrapling | 
|---|:-----------------:|:---------:|:------------:|
| 1 |     Scrapling     |   1.99    |     1.0x     |
| 2 |   Parsel/Scrapy   |   2.06    |    1.035     |
| 3 |     Raw Lxml      |   2.56    |    1.286     |
| 4 |      PyQuery      |   23.98   |     ~12x     |
| 5 |    Selectolax     |  197.02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545.15  |   ~776.5x    |
| 7 |   BS4 with Lxml   |  1562.1   |   ~785.0x    |
| 8 | BS4 with html5lib |  3412.73  |   ~1714.9x   |


### Element Similarity & Text Search Performance

Scrapling's adaptive element finding capabilities significantly outperform alternatives:

| Library     | Time (ms) | vs Scrapling |
|-------------|:---------:|:------------:|
| Scrapling   |    2.3    |     1.0x     |
| AutoScraper |   12.58   |    5.47x     |


> All benchmarks represent averages of 100+ runs. See [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py) for methodology.

## Installation

Scrapling requires Python 3.10 or higher:

```bash
pip install scrapling
```

> [!IMPORTANT]
> This installation only includes the parser engine and its dependencies, without any fetchers or commandline dependencies. So importing anything from `scrapling.fetchers` or `scrapling.spiders`, like in the examples above, will raise `ModuleNotFoundError` with this installation alone. If you are going to use any of the fetchers or spiders, install the fetchers' dependencies first as shown below.

### Optional Dependencies

1. If you are going to use any of the extra features below, the fetchers, or their classes, you will need to install fetchers' dependencies and their browser dependencies as follows:
    ```bash
    pip install "scrapling[fetchers]"
    
    scrapling install           # normal install
    scrapling install  --force  # force reinstall
    ```

    This downloads all browsers, along with their system dependencies and fingerprint manipulation dependencies.

    Or you can install them from the code instead of running a command like this:
    ```python
    from scrapling.cli import install
    
    install([], standalone_mode=False)          # normal install
    install(["--force"], standalone_mode=False) # force reinstall
    ```

2. Extra features:
   - Install the MCP server feature:
       ```bash
       pip install "scrapling[ai]"
       ```
   - Install dependencies for ([building RAG systems](https://scrapling.readthedocs.io/en/latest/ai/building-rag-systems.html)):
       ```bash
       pip install "scrapling[rag]"
       ```
   - Install shell features (Web Scraping shell and the `extract` command): 
       ```bash
       pip install "scrapling[shell]"
       ```
   - Install everything: 
       ```bash
       pip install "scrapling[all]"
       ```
   Run `scrapling install` when you need browser fetchers. HTTP requests do not need a browser installation.

### Docker
You can also install a Docker image with all extras and browsers with the following command from DockerHub:
```bash
docker pull pyd4vinci/scrapling
```
Or download it from the GitHub registry:
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
This image is automatically built and pushed using GitHub Actions and the repository's main branch.

## Contributing

We welcome contributions! Please read our [contributing guidelines](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md) before getting started.

## Disclaimer

> [!CAUTION]
> This library is provided for educational and research purposes only. By using this library, you agree to comply with local and international data scraping and privacy laws. The authors and contributors are not responsible for any misuse of this software. Always respect the terms of service of websites and robots.txt files.

## 🎓 Citations
If you have used our library for research purposes please quote us with the following reference:
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## License

This work is licensed under the BSD-3-Clause License.

## Acknowledgments

This project includes code adapted from:
- Parsel (BSD License)-Used for [translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py) submodule

---
<div align="center"><small>Designed & crafted with ❤️ by Karim Shoair.</small></div><br>

---

### Overview (`agent-skill/README.md`)

# Scrapling Agent Skill

The skill follows the [AgentSkills](https://agentskills.io/specification) specification, so it's readable by [OpenClaw](https://github.com/openclaw/openclaw), [Claude Code](https://claude.com/product/claude-code), and other agentic tools. It gives your coding agent Scrapling guides and examples for HTTP requests, browser sessions, parsing, crawlers, and AI workflows, so it can use the current API instead of guessing from outdated training data.

Use it to look up the API or build a scraper from a complete task guide without leaving your editor. We tested it on [OpenClaw](https://github.com/openclaw/openclaw) and [Claude Code](https://claude.com/product/claude-code), but please open a [ticket](https://github.com/D4Vinci/Scrapling/issues/new/choose) if you face any issues or use our [Discord server](https://discord.gg/EMgGbDceNQ).

## Installation

You can use this [direct URL](https://github.com/D4Vinci/Scrapling/raw/refs/heads/main/agent-skill/Scrapling-Skill.zip) to download the ZIP file of the skill directly. We will try to update this page with all available methods.

### Clawhub
If you use [OpenClaw](https://github.com/openclaw/openclaw), you can install the skill using [Clawhub](https://docs.openclaw.ai/tools/clawhub) directly:
```bash
clawhub install scrapling-official
```

Or go to the [Clawhub](https://docs.openclaw.ai/tools/clawhub) page from [here](https://clawhub.ai/D4Vinci/scrapling-official).

### Skills.sh
You can install the skill from this repository using the [skills.sh](https://skills.sh) CLI directly:
```bash
npx skills add D4Vinci/Scrapling --skill scrapling-official
```

The CLI will detect the agents you have installed and add the skill to them.

---

### Overview (`agent-skill/Scrapling-Skill/examples/README.md`)

# Scrapling Examples

These examples scrape [quotes.toscrape.com](https://quotes.toscrape.com), a site built for scraping practice. They show HTTP sessions, browser sessions, and spiders.

The demo site has **100 quotes across 10 pages**. Each example follows pagination to collect them.

## Quick Start

Make sure Scrapling is installed:

```bash
pip install "scrapling[all]>=0.5"
scrapling install
```

## Examples

| File                     | Tool              | Type                        | Best For                              |
|--------------------------|-------------------|-----------------------------|---------------------------------------|
| `01_fetcher_session.py`  | `FetcherSession`  | Python - persistent HTTP    | APIs, fast multi-page scraping        |
| `02_browser_session.py`  | `StealthySession`  | Python - browser automation | Dynamic/SPA pages                     |
| `03_stealthy_session.py` | `StealthySession` | Python - stealth browser    | Cloudflare, fingerprint bypass        |
| `04_spider.py`           | `Spider`          | Python - auto-crawling      | Multi-page crawls, full-site scraping |

## Escalation Guide

Start with the fastest, lightest option and escalate only if needed:

```
get / FetcherSession
  └─ If JavaScript or anti-bot handling is needed → fetch / StealthySession
       └─ If multi-page → Spider
```

---

### Index (`docs/index.md`)

---
title: "Scrapling: Python Web Scraping Framework"
description: "Scrapling - Effortless Web Scraping for the Modern Web!"
---

<style>
.md-typeset h1 {
  display: none;
}
[data-md-color-scheme="default"] .only-dark { display: none; }
[data-md-color-scheme="slate"] .only-light { display: none; }
</style>

<br/>
<div align="center">
    <a href="https://scrapling.readthedocs.io/en/latest/" alt="poster">
        <img alt="Scrapling" src="assets/cover_light.svg" class="only-light">
        <img alt="Scrapling" src="assets/cover_dark.svg" class="only-dark">
    </a>
</div>

<h2 align="center"><i>Effortless Web Scraping for the Modern Web</i></h2><br>

Scrapling is a Python Web Scraping framework that brings fast HTTP requests, stealth browsers, powerful parsing, and concurrent crawling into one library.

Scrape static pages, render JavaScript, interact with websites, and extract data from the API calls behind them. Build crawlers with reusable sessions, proxy rotation, automatic retries, pause/resume, and built-in data exports.

Use it from Python, the terminal, or your AI agent through its MCP server and Agent Skill. From extracting a few fields to collecting a whole website as clean Markdown, Scrapling covers the full scraping workflow.

## What you can do with Scrapling

- **[Fetch & interact](fetching/choosing.md)**: Fast HTTP requests, stealth browsers, JavaScript rendering, Cloudflare Turnstile/Interstitial handling, persistent sessions, and background API capture.
- **[Parse & extract](parsing/selection.md)**: CSS, XPath, text and regex search, adaptive element tracking, similar-element matching, and clean Markdown output.
- **[Crawl & export](spiders/getting-started.md)**: Concurrent spiders, proxy rotation, retries, AutoThrottle, pause/resume, streaming, ready-made templates, and JSON/JSONL/CSV/XML exports.
- **[Scrape with AI or from your terminal](ai/mcp-server.md)**: An MCP server for AI agents to browse and extract data, an Agent Skill, CLI commands, and an interactive shell.

Start with a single page:

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

Or scale up with a spider:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

This prints `10` and saves the quotes and authors to `quotes.json`.

## Top Sponsors 

--8<-- "sponsors.html"

<i><sub>Do you want to show your ad here? Click [here](https://github.com/sponsors/D4Vinci), choose a plan, and enjoy the rest of the perks!</sub></i>

## Key Features

### Spiders - A Full Crawling Framework
- 🕷️ **Scrapy-like Spider API**: Define spiders with `start_urls`, async `parse` callbacks, and `Request`/`Response` objects.
- ⚡ **Concurrent Crawling**: Configurable concurrency limits, per-domain throttling, and download delays.
- 🔄 **Multi-Session Support**: Unified interface for HTTP requests, and stealthy headless browsers in a single spider - route requests to different sessions by ID.
- 💾 **Pause & Resume**: Save pending requests and seen URLs with `crawldir`. Press Ctrl+C to stop gracefully and restart with the same directory.
- 📡 **Streaming Mode**: Stream scraped items as they arrive via `async for item in spider.stream()` with real-time stats - ideal for UI, pipelines, and long-running crawls.
- 🛡️ **Blocked Request Detection**: Automatic detection and retry of blocked requests with customizable logic.
- 🚦 **AutoThrottle**: Stop guessing delays. The spider tunes the delay of each domain on its own from how fast the website responds, then doubles it (or waits what `Retry-After` asks) whenever the website starts blocking or rate-limiting you, and speeds back up once it stops.
- 🤖 **Robots.txt Compliance**: Optional `robots_txt_obey` flag that respects `Disallow`, `Crawl-delay`, and `Request-rate` directives with per-domain caching.
- 🧪 **Development Mode**: Cache responses to disk on the first run and replay them on subsequent runs - iterate on your `parse()` logic without re-hitting the target servers.
- 🧩 **Ready-made Spider Templates**: Skip the boilerplate with `CrawlSpider` for rule-based link following, `SitemapSpider` for sitemap/robots.txt-driven crawls, `XMLFeedSpider`/`CSVFeedSpider` for iterating XML/RSS and CSV feeds, and `ShopifySpider` to collect products from public Shopify stores, one item per variant.
- 🔗 **Link Extraction**: A standalone `LinkExtractor` primitive with allow/deny patterns, domain filters, CSS/XPath scoping, extension filtering, and canonicalization - use it inside the templates or on its own.
- 📦 **Built-in Export**: Export results through hooks and your own pipeline or the built-in JSON/JSONL/CSV/XML exporters with `result.items.to_json()`, `to_jsonl()`, `to_csv()`, and `to_xml()`.

### Advanced Websites Fetching with Session Support
- **HTTP Requests**: Fast and stealthy HTTP requests with the `Fetcher` class. Can impersonate browsers' TLS fingerprint, headers, and use HTTP/3.
- **Dynamic Loading**: Fetch dynamic websites with full browser automation through the `StealthyFetcher` class supporting Playwright's Chromium and Google's Chrome.
- **Anti-bot Bypass**: Advanced stealth capabilities with `StealthyFetcher` and fingerprint spoofing. Can easily bypass all types of Cloudflare's Turnstile/Interstitial with automation.
- **Session Management**: Persistent session support with `FetcherSession` and `StealthySession` classes for cookie and state management across requests.
- **Proxy Rotation**: Built-in `ProxyRotator` with cyclic or custom rotation strategies across all session types, plus per-request proxy overrides.
- **Domain & Ad Blocking**: Block requests to specific domains (and their subdomains) or enable built-in ad blocking (~3,500 known ad/tracker domains) in browser-based fetchers.
- **DNS Leak Prevention**: Optional DNS-over-HTTPS support to route DNS queries through Cloudflare's DoH, preventing DNS leaks when using proxies.
- **Remote Browsers**: Instead of launching a browser locally, connect to one that's already running through CDP with `cdp_url`, whether it's on the same machine, another host, or a managed browser provider. You can also point any browser fetcher at your own Chromium build with `executable_path`.
- **Background API Capture**: Enable `record_requests=True` on a browser session, then search its saved responses with `session.network.search(limit=None)`. Read API data and HTTP errors across page loads without sending requests again. History is bounded and saves text response bodies.
- **Async Support**: Complete async support across all fetchers and dedicated async session classes.

### Parsing and Data Extraction
- 🔄 **Smart Element Tracking**: Relocate elements after website changes using intelligent similarity algorithms.
- 🎯 **Smart Flexible Selection**: CSS selectors, XPath selectors, filter-based search, text search, regex search, and more.
- 🔍 **Find Similar Elements**: Automatically locate elements similar to found elements.

### AI Features
- 🤖 **MCP Server**: Let AI chatbots and agents (Claude/Cursor/etc) scrape through Scrapling with HTTP requests, browser actions, screenshots, saved login state, and background API responses. Uses our stealthy browser with the right tools to enable suitable AI models to bypass any CAPTCHA it faces while working (not to mention our Cloudflare solver). It uses a lot of methods to reduce the content sent to the model, block ads, and protect it against Prompt-Injection. Remote browsers over CDP and HTTP transport with authentication options are included. ([demo video](https://www.youtube.com/watch?v=qyFk3ZNwOxE))
- 🧠 **Agent Skill**: A ready-to-install [Agent Skill](ai/agent-skill.md) that teaches coding agents the whole library, so the code they write with Scrapling matches the current API instead of guessing.
- 📚 **RAG-ready Markdown**: Turn any page into clean, sanitized, LLM-ready Markdown with one line (`page.markdown()`), or crawl a whole website into a Markdown corpus with the `ContentSpider` template, all without an LLM in the loop. ([docs](ai/building-rag-systems.md))

### High-Performance & battle-tested Architecture
- 🚀 **Lightning Fast**: Optimized performance outperforming most Python scraping libraries.
- 🔋 **Memory Efficient**: Optimized data structures and lazy loading for a minimal memory footprint.
- ⚡ **Fast JSON Serialization**: 10x faster than the standard library.
- 🏗️ **Battle tested**: Not only does Scrapling have 92% test coverage and full type hints coverage, but it has been used daily by hundreds of Web Scrapers over the past year.

### Developer/Web Scraper Friendly Experience
- 🎯 **Interactive Web Scraping Shell**: Optional built-in IPython shell with Scrapling integration, shortcuts, and new tools to speed up Web Scraping scripts development, like converting curl requests to Scrapling requests and viewing requests results in your browser.
- 🚀 **Use it directly from the Terminal**: Optionally, you can use Scrapling to scrape a URL without writing a single line of code!
- 🛠️ **Rich Navigation API**: Advanced DOM traversal with parent, sibling, and child navigation methods.
- 🧬 **Enhanced Text Processing**: Built-in regex, cleaning methods, and optimized string operations.
- 📝 **Auto Selector Generation**: Generate robust CSS/XPath selectors for any element.
- 🔌 **Familiar API**: Similar to Scrapy/BeautifulSoup with the same pseudo-elements used in Scrapy/Parsel.
- 🤝 **Drop-in Scrapy Integration**: Already invested in Scrapy? Decorate any callback with `scrapling_response` to parse the responses you already fetch with Scrapling's parser, no rewrite needed.
- 📘 **Complete Type Coverage**: Full type hints for excellent IDE support and code completion. The entire codebase is automatically scanned with **PyRight** and **MyPy** with each change.
- 🔋 **Ready Docker image**: With each release, a Docker image containing all browsers is automatically built and pushed.


## Star History
Scrapling’s GitHub stars have grown steadily since its release (see chart below).

<div id="chartContainer">
  <a href="https://github.com/D4Vinci/Scrapling">
    <img id="chartImage" alt="Star History Chart" loading="lazy" src="https://api.star-history.com/svg?repos=D4Vinci/Scrapling&type=Date" height="400"/>
  </a>
</div>

<script>
const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.attributeName === 'data-md-color-media') {
      const colorMedia = document.body.getAttribute('data-md-color-media');
      const isDarkScheme = document.body.getAttribute('data-md-color-scheme') === 'slate';
      const chartImg = document.querySelector('#chartImage');
      const baseUrl = 'https://api.star-history.com/svg?repos=D4Vinci/Scrapling&type=Date';
      
      if (colorMedia === '(prefers-color-scheme)' ? isDarkScheme : colorMedia.includes('dark')) {
        chartImg.src = `${baseUrl}&theme=dark`;
      } else {
        chartImg.src = baseUrl;
      }
    }
  });
});

observer.observe(document.body, {
  attributes: true,
  attributeFilter: ['data-md-color-media', 'data-md-color-scheme']
});
</script>


## Installation
Scrapling requires Python 3.10 or higher:

```bash
pip install scrapling
```

!!! warning

    This installation only includes the parser engine and its dependencies, without any fetchers or commandline dependencies. So importing anything from `scrapling.fetchers` or `scrapling.spiders`, like in the examples above, will raise `ModuleNotFoundError` with this installation alone. If you are going to use any of the fetchers or spiders, install the fetchers' dependencies first as shown below.

### Optional Dependencies

1. If you are going to use any of the extra features below, the fetchers, or their classes, you will need to install fetchers' dependencies and their browser dependencies as follows:
    ```bash
    pip install "scrapling[fetchers]"
    
    scrapling install           # normal install
    scrapling install  --force  # force reinstall
    ```

    This downloads all browsers, along with their system dependencies and fingerprint manipulation dependencies.

    Or you can install them from the code instead of running a command like this:
    ```python
    from scrapling.cli import install
    
    install([], standalone_mode=False)          # normal install
    install(["--force"], standalone_mode=False) # force reinstall
    ```

2. Extra features:


     - Install the MCP server feature:
       ```bash
       pip install "scrapling[ai]"
       ```
     - Install dependencies for ([building RAG systems](ai/building-rag-systems.md)):
       ```bash
       pip install "scrapling[rag]"
       ```
     - Install shell features (Web Scraping shell and the `extract` command): 
         ```bash
         pip install "scrapling[shell]"
         ```
     - Install everything: 
         ```bash
         pip install "scrapling[all]"
         ```
   Run `scrapling install` when you need browser fetchers. HTTP requests do not need a browser installation.

### Docker
You can also install a Docker image with all extras and browsers with the following command from DockerHub:
```bash
docker pull pyd4vinci/scrapling
```
Or download it from the GitHub registry:
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
This image is automatically built and pushed using GitHub Actions and the repository's main branch.

## How the documentation is organized
Scrapling has extensive documentation, so we try to follow the [Diátaxis documentation framework](https://diataxis.fr/).

## Support

If you like Scrapling and want to support its development:

- ⭐ Star the [GitHub repository](https://github.com/D4Vinci/Scrapling)
- 🚀 Follow us on [Twitter](https://x.com/Scrapling_dev) and join the [discord server](https://discord.gg/EMgGbDceNQ)
- 💝 Consider [sponsoring the project or buying me a coffee](donate.md) :wink:
- 🐛 Report bugs and suggest features through [GitHub Issues](https://github.com/D4Vinci/Scrapling/issues)

## License

This project is licensed under the BSD-3 License. See the [LICENSE](https://github.com/D4Vinci/Scrapling/blob/main/LICENSE) file for details.

---

### Overview (`docs/overview.md`)

---
title: "Scrapling Overview: Parsing, HTTP Requests and Stealth Browsers"
description: "Explore Scrapling's parsing and fetching features with CSS, XPath, text search, HTTP requests and stealth browser examples."
---

# Get Started with Scrapling

## Pick Your Path

Not sure where to start? Pick the path that matches what you're trying to do:

| I want to... | Start here |
|:---|:---|
| **Parse HTML** I already have | [Querying elements](parsing/selection.md): CSS, XPath, and text-based selection |
| **Quickly scrape a page** and prototype | Pick a [fetcher](fetching/choosing.md) and test right away, or launch the [interactive shell](cli/interactive-shell.md) |
| **Build a crawler** that scales | [Spiders](spiders/getting-started.md): concurrent, multi-session crawls with pause/resume |
| **Scrape without writing code** | [CLI extract commands](cli/extract-commands.md) or hook up the [MCP server](ai/mcp-server.md) to your favourite AI tool |
| **Migrate** from another library | [From BeautifulSoup](tutorials/migrating_from_beautifulsoup.md) or [Scrapy comparison](spiders/architecture.md#comparison-with-scrapy) |

---

We will start by quickly reviewing the parsing capabilities. Then we will fetch websites using custom browsers, make requests, and parse the responses.

Here's an HTML document generated by ChatGPT that we will be using as an example throughout this page:
```
/* Detailed source-code truncated for AI context efficiency. */
```
Starting with loading raw HTML above like this
```python
import re
from scrapling.parser import Selector
page = Selector(html_doc)
page  # <data='<html><head><title>Complex Web Page</tit...'>
```
Get all text content on the page recursively
```python
page.get_all_text(ignore_tags=('script', 'style'))
# 'Complex Web Page\nHome\nAbout\nContact\nProducts\nProduct 1\nThis is product 1\n$10.99\nIn stock: 5\nProduct 2\nThis is product 2\n$20.99\nIn stock: 3\nProduct 3\nThis is product 3\n$15.99\nOut of stock\nCustomer Reviews\nGreat product!\nJohn Doe\nGood value for money.\nJane Smith'
```

## Finding elements
If there's an element you want to find on the page, you will find it! Your creativity level is the only limitation!

Finding the first HTML `section` element
```python
section_element = page.find('section')
# <data='<section id="products" schema='{"jsonabl...' parent='<main><section id="products" schema='{"j...'>
```
Find all `section` elements
```python
section_elements = page.find_all('section')
# [<data='<section id="products" schema='{"jsonabl...' parent='<main><section id="products" schema='{"j...'>, <data='<section id="reviews"><h2>Customer Revie...' parent='<main><section id="products" schema='{"j...'>]
```
Find all `section` elements whose `id` attribute value is `products`.
```python
section_elements = page.find_all('section', {'id':"products"})
# Same as
section_elements = page.find_all('section', id="products")
# [<data='<section id="products" schema='{"jsonabl...' parent='<main><section id="products" schema='{"j...'>]
```
Find all `section` elements whose `id` attribute value contains `product`.
```python
section_elements = page.find_all('section', {'id*':"product"})
```
Find all `h3` elements whose text content matches this regex `Product \d`
```python
page.find_all('h3', re.compile(r'Product \d'))
# [<data='<h3>Product 1</h3>' parent='<article class="product" data-id="1"><h3...'>, <data='<h3>Product 2</h3>' parent='<article class="product" data-id="2"><h3...'>, <data='<h3>Product 3</h3>' parent='<article class="product" data-id="3"><h3...'>]
```
Find all `h3` and `h2` elements whose text content matches the regex `Product` only
```python
page.find_all(['h3', 'h2'], re.compile(r'Product'))
# [<data='<h3>Product 1</h3>' parent='<article class="product" data-id="1"><h3...'>, <data='<h3>Product 2</h3>' parent='<article class="product" data-id="2"><h3...'>, <data='<h3>Product 3</h3>' parent='<article class="product" data-id="3"><h3...'>, <data='<h2>Products</h2>' parent='<section id="products" schema='{"jsonabl...'>]
```
Find all elements whose text content matches exactly `Products` (Whitespaces are not taken into consideration)
```python
page.find_by_text('Products', first_match=False)
# [<data='<h2>Products</h2>' parent='<section id="products" schema='{"jsonabl...'>]
```
Or find all elements whose text content matches regex `Product \d`
```python
page.find_by_regex(r'Product \d', first_match=False)
# [<data='<h3>Product 1</h3>' parent='<article class="product" data-id="1"><h3...'>, <data='<h3>Product 2</h3>' parent='<article class="product" data-id="2"><h3...'>, <data='<h3>Product 3</h3>' parent='<article class="product" data-id="3"><h3...'>]
```
Find all elements that are similar to the element you want
```python
target_element = page.find_by_regex(r'Product \d', first_match=True)
# <data='<h3>Product 1</h3>' parent='<article class="product" data-id="1"><h3...'>
target_element.find_similar()
# [<data='<h3>Product 2</h3>' parent='<article class="product" data-id="2"><h3...'>, <data='<h3>Product 3</h3>' parent='<article class="product" data-id="3"><h3...'>]
```
Find the first element that matches a CSS selector
```python
page.css('.product-list [data-id="1"]')[0]
# <data='<article class="product" data-id="1"><h3...' parent='<div class="product-list"> <article clas...'>
```
Find all elements that match a CSS selector
```python
page.css('.product-list article')
# [<data='<article class="product" data-id="1"><h3...' parent='<div class="product-list"> <article clas...'>, <data='<article class="product" data-id="2"><h3...' parent='<div class="product-list"> <article clas...'>, <data='<article class="product" data-id="3"><h3...' parent='<div class="product-list"> <article clas...'>]
```
Find the first element that matches an XPath selector
```python
page.xpath("//*[@id='products']/div/article")[0]
# <data='<article class="product" data-id="1"><h3...' parent='<div class="product-list"> <article clas...'>
```
Find all elements that match an XPath selector
```python
page.xpath("//*[@id='products']/div/article")
# [<data='<article class="product" data-id="1"><h3...' parent='<div class="product-list"> <article clas...'>, <data='<article class="product" data-id="2"><h3...' parent='<div class="product-list"> <article clas...'>, <data='<article class="product" data-id="3"><h3...' parent='<div class="product-list"> <article clas...'>]
```

With this, we just scratched the surface of these functions; more advanced options with these selection methods are shown later.
## Accessing elements' data
It's as simple as
```
/* Detailed source-code truncated for AI context efficiency. */
```

## Navigation
Using the elements we found above 

```pycon
>>> section_element.parent
<data='<main><section id="products" schema='{"j...' parent='<body> <header><nav><ul><li> <a href="#h...'>
>>> section_element.parent.tag
'main'
>>> section_element.parent.parent.tag
'body'
>>> section_element.children
[<data='<h2>Products</h2>' parent='<section id="products" schema='{"jsonabl...'>,
 <data='<div class="product-list"> <article clas...' parent='<section id="products" schema='{"jsonabl...'>]
>>> section_element.siblings
[<data='<section id="reviews"><h2>Customer Revie...' parent='<main><section id="products" schema='{"j...'>]
>>> section_element.next  # gets the next element, the same logic applies to `quote.previous`.
<data='<section id="reviews"><h2>Customer Revie...' parent='<main><section id="products" schema='{"j...'>
>>> section_element.children.css('h2::text').getall()
['Products']
>>> page.css('[data-id="1"]')[0].has_class('product')
True
```
If your case needs more than the element's parent, you can iterate over the whole ancestors' tree of any element, like the one below
```python
for ancestor in section_element.iterancestors():
    print(ancestor.tag)
```
You can search for a specific ancestor of an element that satisfies a function; all you need to do is pass a function that takes a `Selector` object as an argument and returns `True` if the condition is satisfied or `False` otherwise, like below:
```pycon
>>> section_element.find_ancestor(lambda ancestor: ancestor.css('nav'))
<data='<body> <header><nav><ul><li> <a href="#h...' parent='<html><head><title>Complex Web Page</tit...'>
```

## Fetching websites
Instead of passing the raw HTML to Scrapling, you can retrieve a website's response directly via HTTP requests or by fetching it in a browser.

A fetcher is made for every use case.

### HTTP Requests
For simple HTTP requests, there's a `Fetcher` class that can be imported and used as below:
```python
from scrapling.fetchers import Fetcher
page = Fetcher.get('https://scrapling.requestcatcher.com/get', impersonate="chrome")
```
With that out of the way, here's how to do all HTTP methods:
```python
from scrapling.fetchers import Fetcher
page = Fetcher.get('https://scrapling.requestcatcher.com/get', stealthy_headers=True)
page = Fetcher.post('https://scrapling.requestcatcher.com/post', data={'key': 'value'}, proxy='http://username:password@localhost:8030')
page = Fetcher.put('https://scrapling.requestcatcher.com/put', data={'key': 'value'})
page = Fetcher.delete('https://scrapling.requestcatcher.com/delete')
```
For Async requests, you will replace the import like below:
```python
from scrapling.fetchers import AsyncFetcher
page = await AsyncFetcher.get('https://scrapling.requestcatcher.com/get', stealthy_headers=True)
page = await AsyncFetcher.post('https://scrapling.requestcatcher.com/post', data={'key': 'value'}, proxy='http://username:password@localhost:8030')
page = await AsyncFetcher.put('https://scrapling.requestcatcher.com/put', data={'key': 'value'})
page = await AsyncFetcher.delete('https://scrapling.requestcatcher.com/delete')
```

!!! note "Notes:"

    1. You have the `stealthy_headers` argument, which, when enabled, makes requests to generate real browser headers and use them, including a Google referer header. It's enabled by default.
    2. The `impersonate` argument lets you fake the TLS fingerprint for a specific browser version.
    3. There's also the `http3` argument, which, when enabled, makes the fetcher use HTTP/3 for requests, which makes your requests more authentic

This is just the tip of the iceberg with this fetcher; check out the rest from [here](fetching/static.md)

### Dynamic loading
We have you covered if you deal with dynamic websites like most today!

The `StealthyFetcher` class offers many options for fetching and loading web pages using Chromium-based browsers.
```python
from scrapling.fetchers import StealthyFetcher
page = StealthyFetcher.fetch('https://quotes.toscrape.com/js/', disable_resources=True, block_ads=True, wait_selector='.quote')
print(len(page.css(".quote")))  # -> 10

# The async version of fetch
page = await StealthyFetcher.async_fetch('https://quotes.toscrape.com/js/', disable_resources=True, block_ads=True, wait_selector='.quote')
print(len(page.css(".quote")))  # -> 10
```
It's built on top of [Playwright](https://playwright.dev/python/) with stealth patches. Use the bundled Chromium browser, your installed Google Chrome with `real_chrome=True`, or a running browser through `cdp_url`.

### Anti-bot features

Some of the things it does:

1. It easily bypasses all types of Cloudflare's Turnstile/Interstitial automatically with `solve_cloudflare=True`.
2. It bypasses CDP runtime leaks and WebRTC leaks.
3. It isolates JS execution, removes many Playwright fingerprints, and stops detection through some of the known behaviors that bots do.
4. It generates canvas noise to prevent fingerprinting through canvas.
5. It automatically patches known methods to detect running in headless mode and provides an option to defeat timezone mismatch attacks.
6. and other anti-protection options...

```python
from scrapling.fetchers import StealthyFetcher
page = StealthyFetcher.fetch('https://www.browserscan.net/bot-detection')  # Running headless by default
page.status == 200  # -> True

page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)  # Solve Cloudflare captcha automatically if presented
page.status == 200  # -> True

page = StealthyFetcher.fetch('https://www.browserscan.net/bot-detection', block_webrtc=True, hide_canvas=True, dns_over_https=True) # and the rest of arguments...
# The async version of fetch
page = await StealthyFetcher.async_fetch('https://www.browserscan.net/bot-detection')
page.status == 200  # -> True
```

Again, this is just the tip of the iceberg with this fetcher. Check out the rest from [here](fetching/stealthy.md) for all details and the complete list of arguments.

---

That's Scrapling at a glance. If you want to learn more, continue to the next section.

---

### Cli Overview (`docs/cli/overview.md`)

---
title: "Scrapling CLI: Scrape from the Terminal"
description: "Install Scrapling terminal tools and choose between extract commands, the interactive shell and the MCP server. Follow the guide for your task."
---

# Command Line Interface

Since v0.3, Scrapling includes a powerful command-line interface that provides three main capabilities:

1. **Interactive Shell**: An interactive Web Scraping shell based on IPython that provides many shortcuts and useful tools
2. **Extract Commands**: Scrape websites from the terminal without any programming
3. **Utility Commands**: Installation and management tools

```bash
# Launch interactive shell
scrapling shell

# Convert the content of a page to markdown and save it to a file
scrapling extract get "https://example.com" content.md

# Get help for any command
scrapling --help
scrapling extract --help
```

## Requirements
This section requires you to install the extra `shell` dependency group, like the following:
```bash
pip install "scrapling[shell]"
```
For browser fetching, also install the browser dependencies:
```bash
scrapling install
```
This downloads Chromium and its system dependencies, and updates the TLD list. HTTP requests do not need this step.

---

### Spiders Getting Started (`docs/spiders/getting-started.md`)

---
title: "Build Your First Python Web Crawler with Scrapling"
description: "Build a spider that extracts items, follows pagination and exports results. Learn start URLs, callbacks, domain limits and robots.txt settings."
---

# Getting started

## Introduction

!!! success "Prerequisites"

    1. You've completed or read the [Fetchers basics](../fetching/choosing.md) page to understand the different fetcher types and when to use each one.
    2. You've completed or read the [Main classes](../parsing/main_classes.md) page to understand the [Selector](../parsing/main_classes.md#selector) and [Response](../fetching/choosing.md#response-object) classes.
    3. You've read the [Architecture](architecture.md) page for a high-level overview of how the spider system works.

The spider system lets you build concurrent, multi-page crawlers in just a few lines of code. If you've used Scrapy before, the patterns will feel familiar. If not, this guide will walk you through everything you need to get started.

## Your First Spider

A spider is a class that defines how to crawl and extract data from websites. Here's the simplest possible spider:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com"]

    async def parse(self, response: Response):
        for quote in response.css("div.quote"):
            yield {
                "text": quote.css("span.text::text").get(""),
                "author": quote.css("small.author::text").get(""),
            }
```

Every spider needs three things:

1. **`name`** - A unique identifier for the spider.
2. **`start_urls`** - A list of URLs to start crawling from.
3. **`parse()`** - An async generator method that processes each response and yields results.

The `parse()` method is where the magic happens. You use the same selection methods you'd use with Scrapling's [Selector](../parsing/main_classes.md#selector)/[Response](../fetching/choosing.md#response-object), and `yield` dictionaries to output scraped items.

## Running the Spider

To run your spider, create an instance and call `start()`:

```python
result = QuotesSpider().start()
```

The `start()` method handles all the async machinery internally, so no need to worry about event loops. While the spider is running, everything that happens is logged to the terminal, and at the end of the crawl, you get very detailed stats.

Those stats are in the returned `CrawlResult` object, which gives you everything you need:

```python
result = QuotesSpider().start()

# Access scraped items
for item in result.items:
    print(item["text"], "-", item["author"])

# Check statistics
print(f"Scraped {result.stats.items_scraped} items")
print(f"Made {result.stats.requests_count} requests")
print(f"Took {result.stats.elapsed_seconds:.1f} seconds")

# Did the crawl finish or was it paused?
print(f"Completed: {result.completed}")
```

## Following Links

Most crawls need to follow links across multiple pages. Use `response.follow()` to create follow-up requests:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com"]

    async def parse(self, response: Response):
        # Extract items from the current page
        for quote in response.css("div.quote"):
            yield {
                "text": quote.css("span.text::text").get(""),
                "author": quote.css("small.author::text").get(""),
            }

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

`response.follow()` handles relative URLs automatically by joining them with the current page's URL. It also sets the current page as the `Referer` header by default.

You can point follow-up requests at different callback methods for different page types:

```python
async def parse(self, response: Response):
    for link in response.css("a.product-link::attr(href)").getall():
        yield response.follow(link, callback=self.parse_product)

async def parse_product(self, response: Response):
    yield {
        "name": response.css("h1::text").get(""),
        "price": response.css(".price::text").get(""),
    }
```

!!! note

    All callback methods must be async generators (using `async def` and `yield`).

## Exporting Data

The `ItemList` returned in `result.items` has built-in export methods:

```python
result = QuotesSpider().start()

# Export as JSON
result.items.to_json("quotes.json")

# Export as JSON with pretty-printing
result.items.to_json("quotes.json", indent=True)

# Export as JSON Lines (one JSON object per line)
result.items.to_jsonl("quotes.jsonl")

# Export as CSV or XML
result.items.to_csv("quotes.csv")
result.items.to_xml("quotes.xml")
```

All of them create parent directories automatically if they don't exist.

`to_csv()` writes a column for every key found across your items, so items that don't all share the same keys are still exported with the missing cells left empty. Pass `fields=[...]` to pick the columns and their order yourself, or `delimiter="\t"` for a TSV file. `to_xml()` wraps each item in an `<item>` element inside an `<items>` root, both renameable through `root_tag` and `item_tag`.

In both formats, values that aren't simple scalars (a nested dictionary or a list) are written as JSON so nothing is silently dropped.

## Filtering Domains

Use `allowed_domains` to restrict the spider to specific domains. This prevents it from accidentally following links to external websites:

```python
class MySpider(Spider):
    name = "my_spider"
    start_urls = ["https://example.com"]
    allowed_domains = {"example.com"}

    async def parse(self, response: Response):
        for link in response.css("a::attr(href)").getall():
            # Links to other domains are silently dropped
            yield response.follow(link, callback=self.parse)
```

Subdomains are matched automatically, so setting `allowed_domains = {"example.com"}` also allows `sub.example.com`, `blog.example.com`, etc.

When a request is filtered out, it's counted in `stats.offsite_requests_count` so you can see how many were dropped.

## Robots.txt Compliance

Set `robots_txt_obey = True` to make the spider respect robots.txt rules before crawling any domain:

```python
class PoliteSpider(Spider):
    name = "polite"
    start_urls = ["https://example.com"]
    robots_txt_obey = True

    async def parse(self, response: Response):
        for link in response.css("a::attr(href)").getall():
            yield response.follow(link, callback=self.parse)
```

When enabled, the spider will:

1. **Pre-fetch robots.txt** for all domains in `start_urls` before the crawl begins (concurrently).
2. **Check every request** against the domain's robots.txt `Disallow` rules. Disallowed requests are silently dropped and counted in `stats.robots_disallowed_count`.
3. **Respect `Crawl-delay` and `Request-rate` directives** by taking the maximum of the directive and your configured `download_delay`. This means robots.txt delays never reduce your configured delay, only increase it when needed. When AutoThrottle is enabled, its maximum delay also caps this value. Set `autothrottle_max_delay` high enough to honor the required delay.

Robots.txt files are fetched using the spider's default session and cached per domain for the entire crawl. Domains discovered mid-crawl (not in `start_urls`) have their robots.txt fetched on the first request to that domain.

**Note:** `robots_txt_obey` is turned off by default to avoid surprising behavior. If you enable it, it does not affect your concurrency settings (`concurrent_requests`, `concurrent_requests_per_domain`) -- only the delay between requests is adjusted.

If you don't want to pick a `download_delay` by hand, set `autothrottle_enabled = True` and the spider will tune the delay of every domain on its own from how fast it responds, backing off when it gets blocked. See [AutoThrottle](advanced.md#autothrottle).

## What's Next

Now that you have the basics, you can explore:

- [Requests & Responses](requests-responses.md) - learn about request priority, deduplication, metadata, and more.
- [Sessions](sessions.md) - use multiple fetcher types (HTTP, browser, stealth) in a single spider.
- [Proxy management & blocking](proxy-blocking.md) - rotate proxies across requests and how to handle blocking in the spider.
- [Advanced features](advanced.md) - concurrency control, AutoThrottle, pause/resume, streaming, lifecycle hooks, and logging.

---

### README AR (`docs/README_AR.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io/ar/latest/">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Scrapling Poster" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>اجمع بيانات الويب الحديث بسهولة</small>
</h1>

<p align="center">
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="Tests">
        <img alt="Tests" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="PyPI version">
        <img alt="PyPI version" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="PyPI package downloads"></a>
    <a href="https://scrapling.readthedocs.io/ar/latest/ai/agent-skill.html" alt="AI Agent Skill">
        <img alt="Static Badge" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Far%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="OpenClaw Skill">
        <img alt="OpenClaw Skill" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X (formerly Twitter)">
      <img alt="X (formerly Twitter) Follow" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="Supported Python versions">
        <img alt="Supported Python versions" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/ar/latest/parsing/selection.html"><strong>اختيار العناصر</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ar/latest/fetching/choosing.html"><strong>اختيار Fetcher</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ar/latest/spiders/architecture.html"><strong>Spiders</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ar/latest/spiders/proxy-blocking.html"><strong>تبديل البروكسي</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ar/latest/cli/overview.html"><strong>واجهة سطر الأوامر</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ar/latest/ai/mcp-server.html"><strong>خادم MCP</strong></a>
</p>

Scrapling إطار عمل بلغة Python لجمع بيانات الويب. يجمع طلبات HTTP السريعة، والمتصفحات الخفية، وتحليل الصفحات، والزحف المتزامن في مكتبة واحدة.

اجمع بيانات الصفحات الثابتة، وشغّل JavaScript، وتفاعل مع المواقع، واستخرج البيانات من طلبات API التي تعمل خلفها. أنشئ برامج زحف بجلسات قابلة لإعادة الاستخدام، وتبديل البروكسي، وإعادة المحاولة تلقائيًا، والإيقاف والاستئناف، وتصدير البيانات بأدوات مدمجة.

استخدمه من Python أو الطرفية أو وكيل الذكاء الاصطناعي عبر خادم MCP وAgent Skill. يغطي Scrapling خطوات جمع البيانات كاملة، من استخراج بضعة حقول إلى جمع موقع كامل في ملفات Markdown نظيفة.

## ما الذي يمكنك فعله باستخدام Scrapling؟

- **[الجلب والتفاعل](https://scrapling.readthedocs.io/ar/latest/fetching/choosing.html)**: طلبات HTTP سريعة، ومتصفحات خفية، وتشغيل JavaScript، والتعامل مع Cloudflare Turnstile وInterstitial، وجلسات مستمرة، وحفظ ردود طلبات API في الخلفية.
- **[التحليل والاستخراج](https://scrapling.readthedocs.io/ar/latest/parsing/selection.html)**: البحث باستخدام CSS وXPath والنص والتعبيرات المنتظمة، وتتبع العناصر عند تغير الصفحة، والعثور على العناصر المتشابهة، وإخراج Markdown نظيف.
- **[الزحف والتصدير](https://scrapling.readthedocs.io/ar/latest/spiders/getting-started.html)**: برامج Spider متزامنة، وتبديل البروكسي، وإعادة المحاولة، وAutoThrottle، والإيقاف والاستئناف، وبث النتائج، وقوالب جاهزة، وتصدير JSON وJSONL وCSV وXML.
- **[جمع البيانات بالذكاء الاصطناعي أو من الطرفية](https://scrapling.readthedocs.io/ar/latest/ai/mcp-server.html)**: خادم MCP لوكلاء الذكاء الاصطناعي لتصفح المواقع واستخراج البيانات، وAgent Skill، وأوامر CLI، وواجهة تفاعلية.

ابدأ بصفحة واحدة:

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

أو اجمع بيانات أكثر باستخدام Spider:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

يطبع هذا المثال `10` ويحفظ الاقتباسات وأسماء المؤلفين في `quotes.json`.

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# الرعاة البلاتينيون
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> - أكفأ مزود بروكسيات لجمع بيانات الويب والأتمتة، مع أعلى جودة لعناوين IP في السوق. استخدم الكود SCRAPLING35 للحصول على خصم 35%.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling يتعامل مع Cloudflare Turnstile. لتجاوز أنظمة الحماية التي تستخدمها المؤسسات، توفر <a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a> واجهات API تولّد رموز antibot صالحة لـ <b>Akamai</b>، <b>DataDome</b>، <b>Kasada</b> و <b>Incapsula</b>. طلبات API بسيطة دون الحاجة إلى أتمتة المتصفح. </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a>: بروكسيات سكنية تبدأ من 0.49$/جيجابايت. متصفح لجمع البيانات يستخدم Chromium مع تمويه كامل لبصمته، وعناوين IP سكنية، وحل تلقائي لـ CAPTCHA، وتجاوز أنظمة كشف البوتات. </br>
      <b>واجهة Scraper API لنتائج بدون عناء. يدعم الربط مع MCP و N8N.</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    اقرأ مراجعة كاملة عن <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">Scrapling على The Web Scraping Club</a> (نوفمبر 2025)، النشرة الإخبارية الأولى المخصصة لجمع بيانات الويب.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    يوفر <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a> بروكسيات سكنية تناسب زيادة حجم العمل، مع أكثر من 80 مليون عنوان IP في أكثر من 195 دولة. يقدم اتصالات سريعة وموثوقة، وتبديلًا تلقائيًا للبروكسي، وقدرة عالية على تجنب الحظر. تجربة مجانية متاحة.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    توفر <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a> بروكسيات سكنية ومحمولة وبروكسيات ISP ومراكز بيانات من مصادر أخلاقية، إلى جانب أدوات لاستخراج بيانات الويب وأتمتة الذكاء الاصطناعي. استخدم الكود SCRAPLING10 للحصول على خصم 10% على البروكسيات السكنية.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a>: قلّل الحظر واختبارات CAPTCHA بنسبة 90%. 28 مليون عنوان IP سكني عالي الجودة لاستخراج بيانات الويب بكثافة. 195 دولة. استهداف حسب المدينة/ISP/الرمز البريدي (ZIP). جلسات بعنوان IP ثابت أو متغير. رصيد بيانات لا تنتهي صلاحيته يبدأ من $2/GB. الكود <strong>SCRAPEANDTAKE</strong>: <em>خصم 25%</em>.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a>: توقّف عن الدفع لكل GB. نقل بيانات بلا حد عبر بروكسيات سكنية، وأكثر من 100 مليون عنوان IP في أكثر من 190 دولة. ادفع حسب سرعة الاتصال (bandwidth). اطلب تجربة مجانية للبروكسيات السكنية بسرعة 50 Mbps.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    $1/GB لدى <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a>. بروكسيات من شبكة الشركة نفسها، وبمصادر أخلاقية. أكثر من 90 مليون عنوان IP في أكثر من 195 دولة. بروكسيات سكنية ومراكز بيانات ومحمولة. الدفع حسب الاستخدام = بدون اشتراك. رصيد البيانات لا تنتهي صلاحيته.
    </td>
  </tr>
</table>

<i><sub>هل تريد عرض إعلانك هنا؟ اضغط [هنا](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)</sub></i>
# الرعاة



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>هل تريد عرض إعلانك هنا؟ اضغط [هنا](https://github.com/sponsors/D4Vinci) واختر الخطة التي تناسبك!</sub></i>

---

## الميزات الأساسية

### Spiders: إطار عمل كامل للزحف
- 🕷️ **واجهة Spider تشبه Scrapy**: عرّف برامج Spider باستخدام `start_urls`، ودوال `parse` غير المتزامنة، وكائنات `Request` و`Response`.
- ⚡ **زحف متزامن**: اضبط عدد الطلبات المتزامنة، وحدود كل نطاق، ومدة الانتظار بين التنزيلات.
- 🔄 **دعم عدة جلسات**: واجهة واحدة لطلبات HTTP والمتصفحات الخفية بلا واجهة ضمن Spider واحد. وجّه الطلبات إلى جلسات مختلفة باستخدام المعرّف.
- 💾 **الإيقاف والاستئناف**: احفظ الطلبات المعلقة والروابط التي زرتها باستخدام `crawldir`. اضغط Ctrl+C للإيقاف الآمن، ثم أعد التشغيل مع المجلد نفسه.
- 📡 **بث النتائج**: استقبل العناصر فور جمعها عبر `async for item in spider.stream()`، مع إحصاءات مباشرة. يناسب الواجهات وخطوات معالجة البيانات وعمليات الزحف الطويلة.
- 🛡️ **كشف الطلبات المحظورة**: كشف الطلبات المحظورة وإعادة محاولتها تلقائيًا، مع إمكانية تخصيص السلوك.
- 🚦 **AutoThrottle**: لا تحتاج إلى تخمين مدة الانتظار. يضبط Spider المدة لكل نطاق حسب سرعة رد الموقع، ثم يضاعفها، أو ينتظر المدة التي يطلبها `Retry-After`، عندما يبدأ الموقع في الحظر أو تقييد معدل الطلبات. ويعود إلى السرعة الأعلى عند توقف ذلك.
- 🤖 **الالتزام بملف robots.txt**: خيار `robots_txt_obey` يحترم تعليمات `Disallow` و`Crawl-delay` و`Request-rate`، مع تخزين مؤقت لكل نطاق.
- 🧪 **وضع التطوير**: احفظ الردود على القرص في أول تشغيل، ثم أعد استخدامها في التشغيلات التالية. عدّل دالة `parse()` دون إرسال طلبات جديدة إلى الخوادم.
- 🧩 **قوالب Spider جاهزة**: استخدم `CrawlSpider` لتتبع الروابط وفق قواعد، و`SitemapSpider` للزحف من خرائط الموقع أو robots.txt، و`XMLFeedSpider` و`CSVFeedSpider` لقراءة خلاصات XML وRSS وCSV، و`ShopifySpider` لجمع منتجات متاجر Shopify العامة، بعنصر مستقل لكل نوع من المنتج (variant).
- 🔗 **استخراج الروابط**: أداة `LinkExtractor` مستقلة تدعم أنماط السماح والمنع، وتصفية النطاقات والامتدادات، وحصر البحث باستخدام CSS وXPath، وتوحيد صيغة الروابط. استخدمها داخل القوالب أو وحدها.
- 📦 **تصدير مدمج**: صدّر النتائج عبر hooks وخط معالجة خاص بك، أو استخدم أدوات JSON وJSONL وCSV وXML المدمجة: `result.items.to_json()` و`to_jsonl()` و`to_csv()` و`to_xml()`.

### جلب متقدم للمواقع مع دعم الجلسات
- **طلبات HTTP**: طلبات HTTP سريعة وخفية باستخدام `Fetcher`. تدعم محاكاة بصمة TLS وترويسات المتصفح واستخدام HTTP/3.
- **التحميل الديناميكي**: اجلب المواقع الديناميكية مع أتمتة كاملة للمتصفح عبر `StealthyFetcher`، الذي يدعم Chromium الخاص بـPlaywright وGoogle Chrome.
- **تجاوز كشف البوتات**: إخفاء متقدم للأتمتة ومحاكاة البصمات باستخدام `StealthyFetcher`. يمكنه تجاوز أنواع Cloudflare Turnstile وInterstitial تلقائيًا.
- **إدارة الجلسات**: تدعم `FetcherSession` و`StealthySession` الجلسات المستمرة لإدارة ملفات تعريف الارتباط وحالة المتصفح بين الطلبات.
- **تبديل البروكسي**: أداة `ProxyRotator` مدمجة تدعم التبديل الدوري أو المخصص في كل أنواع الجلسات، مع إمكانية تحديد بروكسي مستقل لكل طلب.
- **حظر النطاقات والإعلانات**: امنع الطلبات إلى نطاقات محددة ونطاقاتها الفرعية، أو فعّل حظر الإعلانات المدمج في أدوات جلب المتصفح، الذي يشمل نحو 3,500 نطاق إعلانات وتتبع معروف.
- **منع تسريب DNS**: دعم اختياري لـDNS-over-HTTPS لتوجيه استعلامات DNS عبر DoH من Cloudflare، ومنع تسريبها عند استخدام البروكسي.
- **متصفحات بعيدة**: اتصل بمتصفح يعمل بالفعل عبر CDP باستخدام `cdp_url`، سواء كان على جهازك أو جهاز آخر أو لدى مزود متصفحات، بدلًا من تشغيل متصفح محلي. ويمكنك استخدام نسخة Chromium الخاصة بك مع أي أداة جلب متصفح عبر `executable_path`.
- **حفظ ردود API في الخلفية**: فعّل `record_requests=True` في جلسة المتصفح، ثم ابحث في الردود المحفوظة عبر `session.network.search(limit=None)`. اقرأ بيانات API وأخطاء HTTP عبر عمليات تحميل الصفحات دون إعادة الطلبات. للسجل حد أقصى، ويحفظ محتوى الردود النصية.
- **الدعم غير المتزامن**: دعم كامل في كل أدوات الجلب، مع فئات جلسات مخصصة للعمل غير المتزامن.

### تحليل الصفحات واستخراج البيانات
- 🔄 **تتبع ذكي للعناصر**: اعثر على العناصر بعد تغير الموقع باستخدام خوارزميات مقارنة التشابه.
- 🎯 **اختيار مرن للعناصر**: محددات CSS وXPath، والبحث بالشروط أو بالنص أو بالتعبيرات المنتظمة، والمزيد.
- 🔍 **العثور على العناصر المتشابهة**: ابحث تلقائيًا عن عناصر تشبه العناصر التي وجدتها.

### ميزات الذكاء الاصطناعي
- 🤖 **خادم MCP**: يتيح لوكلاء ومساعدي الذكاء الاصطناعي، مثل Claude وCursor، جمع البيانات عبر Scrapling باستخدام طلبات HTTP، والتفاعل مع المتصفح، ولقطات الشاشة، وحالة تسجيل دخول محفوظة، وردود API في الخلفية. يستخدم متصفحنا الخفي مع أدوات تساعد النماذج المناسبة على تجاوز CAPTCHA أثناء العمل، إلى جانب أداة حل Cloudflare. ويقلل المحتوى المرسل إلى النموذج، ويحظر الإعلانات، ويحميه من حقن التعليمات Prompt Injection. يدعم أيضًا المتصفحات البعيدة عبر CDP والاتصال عبر HTTP مع خيارات المصادقة. ([فيديو توضيحي](https://www.youtube.com/watch?v=qyFk3ZNwOxE))
- 🧠 **Agent Skill**: [مهارة جاهزة للتثبيت](https://scrapling.readthedocs.io/ar/latest/ai/agent-skill.html) تعرّف وكلاء البرمجة على المكتبة كاملة، ليكتبوا كودًا يطابق واجهتها الحالية بدلًا من التخمين.
- 📚 **Markdown جاهز لأنظمة RAG**: حوّل أي صفحة إلى Markdown نظيف ومنقّى وجاهز لنماذج اللغة بسطر واحد (`page.markdown()`)، أو اجمع موقعًا كاملًا في مجموعة ملفات Markdown باستخدام قالب `ContentSpider`، دون الحاجة إلى نموذج لغة أثناء العملية. ([التوثيق](https://scrapling.readthedocs.io/ar/latest/ai/building-rag-systems.html))

### أداء عالٍ وتصميم مجرّب
- 🚀 **سرعة عالية**: أداء محسّن يتفوق على معظم مكتبات جمع بيانات الويب في Python.
- 🔋 **استهلاك قليل للذاكرة**: هياكل بيانات محسّنة وتحميل عند الحاجة لتقليل استخدام الذاكرة.
- ⚡ **تحويل سريع إلى JSON**: أسرع بعشر مرات من المكتبة القياسية.
- 🏗️ **مجرّب عمليًا**: تغطي الاختبارات 92% من Scrapling، وتوجد تلميحات أنواع للكود كله. كما استخدمه مئات العاملين في جمع بيانات الويب يوميًا خلال العام الماضي.

### تجربة مناسبة للمطورين وجمع البيانات
- 🎯 **واجهة تفاعلية لجمع البيانات**: واجهة IPython اختيارية مدمجة مع Scrapling، واختصارات وأدوات تسرّع كتابة البرامج، مثل تحويل طلبات curl إلى طلبات Scrapling وعرض نتائج الطلبات في المتصفح.
- 🚀 **استخدام مباشر من الطرفية**: يمكنك جمع بيانات رابط دون كتابة أي كود.
- 🛠️ **طرق كثيرة للتنقل**: تنقل في شجرة DOM بين الآباء والأشقاء والأبناء.
- 🧬 **معالجة نصوص محسّنة**: تعبيرات منتظمة وطرق لتنظيف النص وعمليات نصية محسّنة مدمجة.
- 📝 **إنشاء محددات تلقائيًا**: أنشئ محددات CSS وXPath موثوقة لأي عنصر.
- 🔌 **واجهة مألوفة**: تشبه Scrapy وBeautifulSoup، وتستخدم pseudo-elements نفسها الموجودة في Scrapy وParsel.
- 🤝 **تكامل مباشر مع Scrapy**: إذا كنت تستخدم Scrapy، أضف decorator باسم `scrapling_response` إلى أي callback لتحليل الردود التي تجلبها بالفعل بمحلّل Scrapling، دون إعادة كتابة البرنامج.
- 📘 **تلميحات أنواع كاملة**: دعم جيد لمحرر الكود والإكمال التلقائي. يُفحص الكود كله تلقائيًا باستخدام **PyRight** و**MyPy** مع كل تغيير.
- 🔋 **صورة Docker جاهزة**: تُبنى صورة Docker تحتوي كل المتصفحات وتُنشر تلقائيًا مع كل إصدار.

## البدء

إليك أمثلة سريعة على استخدام Scrapling.

### الاستخدام الأساسي
طلبات HTTP مع دعم الجلسات
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # استخدم أحدث إصدار من بصمة TLS لـ Chrome
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# أو استخدم طلبات لمرة واحدة
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
وضع التخفي المتقدم
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # أبقِ المتصفح مفتوحاً حتى تنتهي
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# أو استخدم نمط الطلب لمرة واحدة، يفتح المتصفح لهذا الطلب، ثم يغلقه بعد الانتهاء
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
أتمتة المتصفح الكاملة
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # أبقِ المتصفح مفتوحاً حتى تنتهي
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # محدد XPath إذا كنت تفضله

# أو استخدم نمط الطلب لمرة واحدة، يفتح المتصفح لهذا الطلب، ثم يغلقه بعد الانتهاء
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### Spiders
أنشئ برامج Spider ترسل عدة طلبات في الوقت نفسه، وتستخدم أنواع جلسات مختلفة، وتدعم الإيقاف والاستئناف:
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"Scraped {len(result.items)} quotes")
result.items.to_json("quotes.json")
```
استخدم أنواع جلسات متعددة في Spider واحد:
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]

    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)

    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # وجّه الصفحات المحمية عبر جلسة التخفي
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # callback صريح
```
لحفظ تقدم الزحف وإكماله لاحقًا، شغّل Spider هكذا:
```python
QuotesSpider(crawldir="./crawl_data").start()
```
عند استخدام `crawldir`، اضغط Ctrl+C لحفظ الطلبات المعلقة والروابط التي زرتها. أعد التشغيل مع `crawldir` نفسه لإكمال الزحف. احفظ البيانات التي جمعتها بشكل منفصل.

أو استخدم قالبًا جاهزًا بدلًا من كتابة كود الزحف بنفسك، مثل هذا القالب لجمع كل منتجات متجر Shopify:
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # كل منتج في المتجر، مع عنصر لكل variant
```
يجمع القالب المنتجات المتاحة عبر واجهات API العامة للمجموعات، ويحفظ نتيجة منفصلة لكل نوع من المنتج (variant).

### التحليل المتقدم والتنقل
```python
from scrapling.fetchers import Fetcher

# اختيار عناصر غني وتنقل
page = Fetcher.get('https://quotes.toscrape.com/')

# احصل على الاقتباسات بطرق اختيار متعددة
quotes = page.css('.quote')  # محدد CSS
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # بأسلوب BeautifulSoup
# نفس الشيء مثل
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # وهكذا...
# البحث عن عنصر بمحتوى النص
quotes = page.find_by_text('Albert Einstein', first_match=False)

# التنقل المتقدم
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # محددات متسلسلة
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# علاقات العناصر والتشابه
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
إذا كان لديك محتوى HTML بالفعل، يمكنك تحليله مباشرة:
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
يمكنك استخدام طرق اختيار العناصر نفسها.

### إدارة الجلسات باستخدام Async
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # تتكيف `FetcherSession` مع السياق وتعمل بالنمطين المتزامن وغير المتزامن
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## سطر الأوامر وShell التفاعلي

يمكنك استخدام Scrapling من سطر الأوامر:

[](https://asciinema.org/a/736339)

لتشغيل Shell التفاعلي لجمع البيانات:
```bash
pip install "scrapling[shell]"
scrapling shell
```
احفظ محتوى الصفحات في ملف مباشرة دون كتابة كود. استخدم `--css-selector` لاختيار المحتوى، أو `--ai-targeted` لاختيار محتوى `body` وإزالة الأجزاء غير المطلوبة. استخدم `.txt` للنص، أو `.md` لصيغة Markdown، أو `.html` لصيغة HTML.
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> هذه أمثلة مختصرة. للمزيد من الميزات والتفاصيل، بما فيها خادم MCP وShell التفاعلي، اقرأ التوثيق الكامل [هنا](https://scrapling.readthedocs.io/ar/latest/)

## اختبارات الأداء

Scrapling سريع أيضًا. تقارن الاختبارات التالية محلّل Scrapling بأحدث إصدارات مكتبات شائعة أخرى.

### اختبار سرعة استخراج النص (5000 عنصر متداخل)

| # |      المكتبة      | الوقت (ms) | vs Scrapling |
|---|:-----------------:|:----------:|:------------:|
| 1 |     Scrapling     |    1.99    |     1.0x     |
| 2 |   Parsel/Scrapy   |    2.06    |     1.035    |
| 3 |     Raw Lxml      |    2.56    |    1.286     |
| 4 |      PyQuery      |   23.98    |     ~12x     |
| 5 |    Selectolax     |   197.02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545.15   |   ~776.5x    |
| 7 |   BS4 with Lxml   |  1562.1   |   ~785.0x    |
| 8 | BS4 with html5lib |  3412.73   |   ~1714.9x   |


### أداء تشابه العناصر والبحث النصي

يعثر Scrapling على العناصر بعد تغير الصفحة بسرعة أكبر من البدائل:

| المكتبة     | الوقت (ms) | vs Scrapling |
|-------------|:----------:|:------------:|
| Scrapling   |    2.3    |     1.0x     |
| AutoScraper |   12.58    |    5.47x    |


> كل نتيجة هي متوسط أكثر من 100 تشغيل. لمعرفة طريقة الاختبار، راجع [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py).

## التثبيت

يتطلب Scrapling إصدار Python 3.10 أو أحدث:

```bash
pip install scrapling
```

> [!IMPORTANT]
> يثبّت هذا الأمر محلّل الصفحات ومتطلباته فقط، دون أدوات الجلب أو متطلبات سطر الأوامر. إذا اكتفيت بهذا التثبيت، سيظهر الخطأ `ModuleNotFoundError` عند استيراد أي شيء من `scrapling.fetchers` أو `scrapling.spiders`، كما في الأمثلة السابقة. لاستخدام أدوات الجلب أو Spiders، ثبّت متطلبات أدوات الجلب أولًا كما يلي.

### المتطلبات الاختيارية

1. لاستخدام أدوات الجلب أو فئاتها أو الميزات الإضافية التالية، ثبّت متطلبات أدوات الجلب والمتصفحات كما يلي:
    ```bash
    pip install "scrapling[fetchers]"

    scrapling install           # normal install
    scrapling install  --force  # force reinstall
    ```

    ينزّل هذا كل المتصفحات، ومتطلبات النظام، ومتطلبات تعديل بصمات المتصفح.

    ويمكنك تثبيتها من الكود بدلًا من تشغيل أمر:
    ```python
    from scrapling.cli import install

    install([], standalone_mode=False)          # normal install
    install(["--force"], standalone_mode=False) # force reinstall
    ```

2. ميزات إضافية:
   - تثبيت خادم MCP:
       ```bash
       pip install "scrapling[ai]"
       ```
   - تثبيت متطلبات [بناء أنظمة RAG](https://scrapling.readthedocs.io/ar/latest/ai/building-rag-systems.html):
       ```bash
       pip install "scrapling[rag]"
       ```
   - تثبيت Shell التفاعلي وأمر `extract`:
       ```bash
       pip install "scrapling[shell]"
       ```
   - تثبيت كل شيء:
       ```bash
       pip install "scrapling[all]"
       ```
   شغّل `scrapling install` عند استخدام أدوات جلب المتصفح. طلبات HTTP لا تحتاج إلى تثبيت متصفح.

### Docker
يمكنك تنزيل صورة Docker تحتوي كل الإضافات والمتصفحات من DockerHub:
```bash
docker pull pyd4vinci/scrapling
```
أو تنزيلها من سجل GitHub:
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
تُبنى هذه الصورة من الفرع الرئيسي للمستودع وتُنشر تلقائيًا باستخدام GitHub Actions.

## المساهمة

نرحب بالمساهمات! يرجى قراءة [إرشادات المساهمة](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md) قبل البدء.

## إخلاء المسؤولية

> [!CAUTION]
> هذه المكتبة للتعليم والبحث فقط. باستخدامها، توافق على الالتزام بقوانين جمع البيانات والخصوصية المحلية والدولية. المؤلفون والمساهمون غير مسؤولين عن أي إساءة استخدام لهذا البرنامج. احترم دائماً شروط خدمة المواقع وملفات robots.txt.

## 🎓 الاستشهادات
إذا استخدمت المكتبة في بحث، أضف المرجع التالي:
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## الترخيص

هذا العمل مرخص بموجب ترخيص BSD-3-Clause.

## الشكر والتقدير

يتضمن هذا المشروع كوداً معدلاً من:
- Parsel (ترخيص BSD) - يُستخدم للوحدة الفرعية [translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py)

---
<div align="center"><small>مصمم ومصنوع بـ ❤️ بواسطة كريم شعير.</small></div><br>

---

### README CN (`docs/README_CN.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io/zh-cn/latest/">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Scrapling 封面" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>轻松抓取现代网站</small>
</h1>

<p align="center">
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="测试">
        <img alt="测试" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="PyPI 版本">
        <img alt="PyPI 版本" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Docker 下载次数" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="PyPI 包下载次数"></a>
    <a href="https://scrapling.readthedocs.io/zh-cn/latest/ai/agent-skill.html" alt="AI 智能体技能">
        <img alt="Agent Skill 徽章" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Fzh-cn%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="OpenClaw 技能">
        <img alt="OpenClaw 技能" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X（原 Twitter）">
      <img alt="在 X（原 Twitter）上关注" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="支持的 Python 版本">
        <img alt="支持的 Python 版本" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/zh-cn/latest/parsing/selection.html"><strong>选择方法</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/zh-cn/latest/fetching/choosing.html"><strong>选择 Fetcher</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/zh-cn/latest/spiders/architecture.html"><strong>爬虫</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/zh-cn/latest/spiders/proxy-blocking.html"><strong>代理轮换</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/zh-cn/latest/cli/overview.html"><strong>CLI</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/zh-cn/latest/ai/mcp-server.html"><strong>MCP 模式</strong></a>
</p>

Scrapling 是一个 Python 网页抓取框架。它将快速 HTTP 请求、隐身浏览器、页面解析和并发爬取整合在一个库中。

抓取静态页面、运行 JavaScript、操作网站，并从网站的 API 中提取数据。构建爬虫时，可以复用会话、轮换代理、自动重试、暂停和恢复任务，还能直接导出数据。

可以在 Python 和终端中使用 Scrapling，也可以通过 MCP 服务器和 Agent Skill 让 AI 智能体使用它。从提取几个字段到将整个网站保存为整洁的 Markdown 文件，Scrapling 都能完成。

## 用 Scrapling 能做什么

- **[获取和操作页面](https://scrapling.readthedocs.io/zh-cn/latest/fetching/choosing.html)**：快速 HTTP 请求、隐身浏览器、JavaScript 渲染、处理 Cloudflare Turnstile 和 Interstitial、持久会话，以及记录后台 API 响应。
- **[解析页面和提取数据](https://scrapling.readthedocs.io/zh-cn/latest/parsing/selection.html)**：使用 CSS、XPath、文本和正则表达式搜索，跟踪页面变化后的元素，查找相似元素，并输出整洁的 Markdown。
- **[爬取和导出](https://scrapling.readthedocs.io/zh-cn/latest/spiders/getting-started.html)**：并发爬虫、代理轮换、重试、AutoThrottle、暂停和恢复、流式输出、现成的模板，以及 JSON、JSONL、CSV 和 XML 导出。
- **[使用 AI 或终端抓取](https://scrapling.readthedocs.io/zh-cn/latest/ai/mcp-server.html)**：供 AI 智能体浏览网页和提取数据的 MCP 服务器、Agent Skill、CLI 命令和交互式 Shell。

从单个页面开始：

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

也可以用 Spider 抓取更多页面：

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

输出 `10`，并将名言和作者保存到 `quotes.json`。

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# 铂金赞助商
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> - 最高效的网页抓取与自动化代理提供商，拥有市场上质量最高的 IP。使用优惠码 SCRAPLING35 可享 35% 折扣。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling 可处理 Cloudflare Turnstile。对于企业级保护，<a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a> 提供 API 端点，生成适用于 <b>Akamai</b>、<b>DataDome</b>、<b>Kasada</b> 和 <b>Incapsula</b> 的有效 antibot 令牌。简单的 API 调用，无需浏览器自动化。 </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a>：住宅代理低至 0.49 美元/GB。提供指纹全面伪装的 Chromium 抓取浏览器，配备住宅 IP，并支持自动处理验证码和绕过反机器人防护。</br>
      <b>Scraper API 轻松获取结果。支持 MCP 和 N8N 集成。</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    阅读 <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">The Web Scraping Club 上关于 Scrapling 的完整评测</a>（2025 年 11 月），这是排名第一的网页抓取专业通讯。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a> 提供可扩展的住宅代理，覆盖 195+ 国家/地区的 8000 万+ IP，提供快速可靠的连接、自动轮换和强大的防封禁功能。提供免费试用。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a> 提供符合道德规范的住宅、移动、ISP 和数据中心代理，以及网页抓取和 AI 自动化工具。使用优惠码 SCRAPLING10，住宅代理可享 10% 折扣。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a>：将封禁和 CAPTCHA 验证码减少 90%。提供 2800 万个优质住宅 IP，适用于大规模网页抓取。覆盖 195 个国家。支持城市、ISP、邮政编码（ZIP）定向。支持使用固定 IP 或轮换 IP 的会话。流量永不过期，低至 $2/GB。使用优惠码 <strong>SCRAPEANDTAKE</strong> 可享 <em>25% 折扣</em>。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a>：无需再按 GB 付费。住宅代理流量不限量，1 亿+ IP，覆盖 190+ 个国家。按带宽付费。申请免费试用 50 Mbps 住宅代理。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a>，价格为 $1/GB。符合道德规范的第一方代理。9000 万+ IP，覆盖 195+ 个国家。住宅、数据中心、移动代理。按量付费 = 无需订阅。流量永不过期。
    </td>
  </tr>
</table>

<i><sub>想在这里投放广告？点击[这里](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)</sub></i>
# 赞助商



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>想在这里投放广告？点击[这里](https://github.com/sponsors/D4Vinci)，选择合适的方案！</sub></i>

---

## 主要功能

### Spider：完整的爬虫框架

- 🕷️ **类似 Scrapy 的 Spider API**：使用 `start_urls`、异步 `parse` 回调，以及 `Request` 和 `Response` 对象定义爬虫。
- ⚡ **并发爬取**：设置并发请求数、每个域名的并发上限，以及下载间隔。
- 🔄 **多种会话**：在同一个爬虫中使用 HTTP 请求和隐身无头浏览器。按会话 ID 将请求交给不同的会话处理。
- 💾 **暂停和恢复**：用 `crawldir` 保存待处理请求和已访问的 URL。按 Ctrl+C 安全暂停，再用同一个目录启动即可继续。
- 📡 **流式输出**：通过 `async for item in spider.stream()` 在数据提取后立即接收它，并查看实时统计信息。适合界面、数据处理流程和长时间运行的任务。
- 🛡️ **识别被拦截的请求**：自动检测并重试被拦截的请求，也可以自定义处理逻辑。
- 🚦 **AutoThrottle**：根据网站的响应速度，自动调整每个域名的请求间隔。如果网站拦截请求或限制频率，就将间隔加倍，或遵守 `Retry-After` 指定的等待时间。之后再逐步加快。
- 🤖 **遵守 robots.txt**：启用 `robots_txt_obey`，即可遵守 `Disallow`、`Crawl-delay` 和 `Request-rate`。规则按域名缓存。
- 🧪 **开发模式**：首次运行时将响应保存到磁盘，之后直接复用。这样可以修改 `parse()`，而不必再次请求服务器。
- 🧩 **现成的爬虫模板**：使用 `CrawlSpider` 按规则跟踪链接，使用 `SitemapSpider` 从 sitemap 或 robots.txt 开始爬取，使用 `XMLFeedSpider` 和 `CSVFeedSpider` 读取 XML、RSS 和 CSV 数据源，或使用 `ShopifySpider` 获取公开 Shopify 商店的商品，每个商品变体生成一条数据。
- 🔗 **提取链接**：`LinkExtractor` 可用模式允许或排除链接，过滤域名和文件扩展名，用 CSS 或 XPath 限定范围，并规范化 URL。它既可配合模板使用，也可单独使用。
- 📦 **内置导出**：用钩子和自己的处理流程导出数据，或使用内置的 JSON、JSONL、CSV 和 XML 方法：`result.items.to_json()`、`to_jsonl()`、`to_csv()` 和 `to_xml()`。

### 使用会话获取页面

- **HTTP 请求**：用 `Fetcher` 发送快速、隐蔽的 HTTP 请求。支持模拟浏览器的 TLS 指纹和请求头，也支持 HTTP/3。
- **动态加载**：用 `StealthyFetcher` 的完整浏览器自动化功能抓取动态网站。支持 Playwright 的 Chromium 和 Google Chrome。
- **绕过反爬检测**：`StealthyFetcher` 隐藏自动化特征并模拟浏览器指纹，能自动处理多种 Cloudflare Turnstile 和 Interstitial 验证。
- **会话管理**：`FetcherSession` 和 `StealthySession` 可在多次请求之间保留 Cookie 和状态。
- **代理轮换**：`ProxyRotator` 支持在所有会话类型中按顺序或自定义规则切换代理，也可以为单次请求指定代理。
- **拦截域名和广告**：拦截指定域名及其子域名的请求，或启用浏览器 Fetcher 的广告拦截功能。内置列表包含约 3,500 个已知广告和跟踪域名。
- **防止 DNS 泄漏**：启用 DNS-over-HTTPS，通过 Cloudflare 的 DoH 服务发送 DNS 查询，防止使用代理时泄漏 DNS。
- **远程浏览器**：通过 CDP 和 `cdp_url` 连接已运行的浏览器，包括本机、远程服务器和浏览器服务商提供的浏览器。也可以用 `executable_path` 为任意浏览器 Fetcher 指定自己的 Chromium 程序。
- **记录后台 API 响应**：在浏览器会话中启用 `record_requests=True`，再用 `session.network.search(limit=None)` 搜索已保存的响应。无需重复请求，即可读取多次页面访问中的 API 数据和 HTTP 错误。历史记录有大小上限，只保存文本响应的内容。
- **异步支持**：所有 Fetcher 都支持异步操作，并提供专用的异步会话类。

### 解析页面和提取数据

- 🔄 **重新定位元素**：网站结构改变后，用相似度算法重新找到元素。
- 🎯 **灵活选择**：支持 CSS、XPath、过滤器、文本、正则表达式等方式。
- 🔍 **相似元素**：自动查找与已选元素相似的元素。

### AI 功能

- 🤖 **MCP 服务器**：让 Claude、Cursor 等 AI 助手和智能体通过 Scrapling 提取数据。支持 HTTP 请求、浏览器操作、截图、保存的登录状态和后台 API 响应。它使用我们的隐身浏览器，并提供工具，让具备相应能力的模型处理 CAPTCHA，补充内置的 Cloudflare 验证处理功能。它还减少发送给模型的内容、拦截广告，并防护提示词注入。支持通过 CDP 连接远程浏览器，也支持带身份验证选项的 HTTP 连接。（[演示视频](https://www.youtube.com/watch?v=qyFk3ZNwOxE)）
- 🧠 **Agent Skill**：可安装的 [Agent Skill](https://scrapling.readthedocs.io/zh-cn/latest/ai/agent-skill.html)，帮助编程智能体了解这个库，并编写符合当前 API 的代码。
- 📚 **用于 RAG 的 Markdown**：用一行代码（`page.markdown()`）将页面转成适合语言模型的整洁 Markdown，或用 `ContentSpider` 模板将整个网站保存为 Markdown 文件。无需语言模型。（[文档](https://scrapling.readthedocs.io/zh-cn/latest/ai/building-rag-systems.html)）

### 快速且经过实际使用

- 🚀 **速度快**：经过优化，性能超过大多数 Python 网页抓取库。
- 🔋 **内存占用低**：使用优化的数据结构，并按需加载。
- ⚡ **快速输出 JSON**：速度是标准库的 10 倍。
- 🏗️ **经过实际检验**：测试覆盖率达 92%，全部代码都有类型注解。过去一年中，数百人每天用它提取数据。

### 开发和数据提取工具

- 🎯 **交互式 Shell**：可选的 IPython Shell，内置 Scrapling、快捷命令和工具，方便快速开发抓取脚本。可将 curl 请求转成 Scrapling 请求，并在浏览器中查看结果。
- 🚀 **命令行使用**：无需写代码，就能提取 URL 的内容。
- 🛠️ **DOM 导航**：访问父元素、同级元素和子元素。
- 🧬 **文本处理**：支持正则表达式、文本清理和优化的字符串操作。
- 📝 **生成选择器**：为任意元素生成可靠的 CSS 和 XPath 选择器。
- 🔌 **熟悉的 API**：与 Scrapy 和 BeautifulSoup 相似，并支持 Scrapy 和 Parsel 使用的伪元素。
- 🤝 **直接集成 Scrapy**：给回调加上 `scrapling_response` 装饰器，就能用 Scrapling 解析器处理已有的 Scrapy 响应，无需重写程序。
- 📘 **完整的类型注解**：帮助编辑器检查和补全代码。每次修改都会用 **PyRight** 和 **MyPy** 自动检查全部代码。
- 🔋 **现成的 Docker 镜像**：每次发布新版本时，自动构建并发布包含所有浏览器的 Docker 镜像。

## 入门

下面是一些常见用法。

### 基本用法
使用会话发送 HTTP 请求
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # 使用 Chrome 的最新版本 TLS fingerprint
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# 或使用一次性请求
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
隐身模式
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # 保持浏览器打开直到完成
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# 或使用一次性请求样式，为此请求打开浏览器，完成后关闭
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
完整的浏览器自动化
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # 保持浏览器打开直到完成
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # 如果您偏好 XPath 选择器

# 或使用一次性请求样式，为此请求打开浏览器，完成后关闭
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### Spider
构建支持并发请求、多种会话、暂停和恢复的完整爬虫：
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"抓取了 {len(result.items)} 条引用")
result.items.to_json("quotes.json")
```
在同一个 Spider 中使用多种会话：
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]

    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)

    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # 将受保护的页面路由到隐秘 Session
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # 显式 callback
```
保存进度，就能暂停和恢复长时间运行的任务。这样启动 Spider：
```python
QuotesSpider(crawldir="./crawl_data").start()
```
设置 `crawldir` 后，按 Ctrl+C 保存待处理请求和已访问 URL。使用同一个 `crawldir` 重启即可继续。请单独保存提取的数据。

也可以使用现成的模板，例如获取整个 Shopify 商店的商品目录：
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # 店铺中的所有商品，每个变体一条记录
```
模板从公开的商品集合接口读取商品，每个商品变体生成一条数据。

### 高级解析与导航
```python
from scrapling.fetchers import Fetcher

# 丰富的元素选择和导航
page = Fetcher.get('https://quotes.toscrape.com/')

# 使用多种选择方法获取引用
quotes = page.css('.quote')  # CSS 选择器
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # BeautifulSoup 风格
# 等同于
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # 等等...
# 按文本内容查找元素
quotes = page.find_by_text('Albert Einstein', first_match=False)

# 高级导航
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # 链式选择器
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# 元素关系和相似性
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
也可以直接使用解析器，无需先获取网页：
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
用法相同。

### 异步会话示例
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # `FetcherSession` 能识别上下文，同时支持同步和异步用法
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## CLI 和交互式 Shell

也可以在终端中使用 Scrapling：

[](https://asciinema.org/a/736339)

启动交互式网页抓取 Shell：
```bash
pip install "scrapling[shell]"
scrapling shell
```
无需编程即可将页面直接提取到文件。使用 `--css-selector` 选择内容，或用 `--ai-targeted` 选择并清理 `body` 内容。使用 `.txt` 输出文本、`.md` 输出 Markdown，或 `.html` 输出 HTML。
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> 更多功能，包括 MCP 服务器和交互式 Shell，请查看[完整文档](https://scrapling.readthedocs.io/zh-cn/latest/)。

## 性能测试

Scrapling 的速度也很出色。下面对比它的解析器和其他常用库的最新版本。

### 文本提取速度（5,000 个嵌套元素）

| # |         库         | 时间（毫秒）  | 相对 Scrapling |
|---|:-----------------:|:---------:|:------------:|
| 1 |     Scrapling     |   1.99    |     1.0x     |
| 2 |   Parsel/Scrapy   |   2.06    |    1.035     |
| 3 |     原生 Lxml      |   2.56    |    1.286     |
| 4 |      PyQuery      |   23.98   |     ~12x     |
| 5 |    Selectolax     |  197.02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545.15  |   ~776.5x    |
| 7 |   BS4 + Lxml   |  1562.1   |   ~785.0x    |
| 8 | BS4 + html5lib |  3412.73  |   ~1714.9x   |


### 相似元素和文本搜索

Scrapling 的自适应元素查找比其他方案更快：

| 库           | 时间（毫秒） | 相对 Scrapling |
|-------------|:---------:|:------------:|
| Scrapling   |    2.3    |     1.0x     |
| AutoScraper |   12.58   |    5.47x     |


> 每项结果都是至少 100 次运行的平均值。测试方法见 [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py)。

## 安装

Scrapling 需要 Python 3.10 或更高版本：

```bash
pip install scrapling
```

> [!IMPORTANT]
> 这个命令只安装解析器及其依赖，不包含 Fetcher 或命令行工具。仅安装这些依赖后，像上面的示例那样从 `scrapling.fetchers` 或 `scrapling.spiders` 导入内容，会出现 `ModuleNotFoundError`。要使用 Fetcher 或 Spider，请先按下文安装 Fetcher 的依赖。

### 可选依赖

1. 要使用 Fetcher、相关类或下列扩展功能，请先安装 Fetcher 和浏览器的依赖：
    ```bash
    pip install "scrapling[fetchers]"

    scrapling install           # normal install
    scrapling install  --force  # force reinstall
    ```

    这会下载所有浏览器、所需的系统依赖，以及修改浏览器指纹的工具。

    也可以在 Python 代码中安装，无需运行命令：
    ```python
    from scrapling.cli import install

    install([], standalone_mode=False)          # normal install
    install(["--force"], standalone_mode=False) # force reinstall
    ```

2. 扩展功能：
   - 安装 MCP 服务器：
       ```bash
       pip install "scrapling[ai]"
       ```
   - 安装[构建 RAG 系统](https://scrapling.readthedocs.io/zh-cn/latest/ai/building-rag-systems.html)所需的依赖：
       ```bash
       pip install "scrapling[rag]"
       ```
   - 安装交互式 Shell 和 `extract` 命令：
       ```bash
       pip install "scrapling[shell]"
       ```
   - 安装所有功能：
       ```bash
       pip install "scrapling[all]"
       ```
   如果要使用浏览器 Fetcher，请运行 `scrapling install`。HTTP 请求不需要安装浏览器。

### Docker
也可以从 DockerHub 下载包含所有扩展功能和浏览器的 Docker 镜像：
```bash
docker pull pyd4vinci/scrapling
```
或从 GitHub 容器仓库下载：
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
镜像基于仓库的主分支构建，由 GitHub Actions 自动发布。

## 贡献

欢迎参与项目！开始前，请阅读[贡献指南](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md)。

## 免责声明

> [!CAUTION]
> 本库仅用于学习和研究。使用本库即表示同意遵守当地和国际上的数据抓取及隐私法律。作者和贡献者不对软件被滥用承担责任。请遵守网站的服务条款和 robots.txt 文件。

## 🎓 引用
如果在研究中使用本库，请按以下格式引用：
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## 许可证

本项目使用 BSD-3-Clause 许可证。

## 致谢

本项目包含改编自以下项目的代码：
- Parsel（BSD 许可证）：用于 [translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py) 子模块

---
<div align="center"><small>由 Karim Shoair 用❤️设计和制作。</small></div><br>

---

### README DE (`docs/README_DE.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io/de/latest/">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Scrapling-Titelbild" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>Daten aus dem modernen Web einfach extrahieren</small>
</h1>

<p align="center">
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="Tests">
        <img alt="Tests" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="Version auf PyPI">
        <img alt="Version auf PyPI" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Docker-Downloads" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="Paket-Downloads auf PyPI"></a>
    <a href="https://scrapling.readthedocs.io/de/latest/ai/agent-skill.html" alt="Skill für KI-Agenten">
        <img alt="Agent-Skill-Badge" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Fde%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="Skill für OpenClaw">
        <img alt="Skill für OpenClaw" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X (ehemals Twitter)">
      <img alt="Auf X (ehemals Twitter) folgen" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="Unterstützte Python-Versionen">
        <img alt="Unterstützte Python-Versionen" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/de/latest/parsing/selection.html"><strong>Auswahlmethoden</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/de/latest/fetching/choosing.html"><strong>Einen Fetcher wählen</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/de/latest/spiders/architecture.html"><strong>Spider</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/de/latest/spiders/proxy-blocking.html"><strong>Proxy-Rotation</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/de/latest/cli/overview.html"><strong>CLI</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/de/latest/ai/mcp-server.html"><strong>MCP-Modus</strong></a>
</p>

Scrapling ist ein Web-Scraping-Framework für Python. Es vereint schnelle HTTP-Anfragen, Stealth-Browser, die Auswertung von Seiten und paralleles Crawling in einer Bibliothek.

Extrahieren Sie Daten aus statischen Seiten, führen Sie JavaScript aus, bedienen Sie Websites und greifen Sie auf deren APIs zu. Erstellen Sie Crawler mit wiederverwendbaren Sitzungen, Proxy-Rotation, automatischen Wiederholungsversuchen, Pause und Fortsetzung sowie integriertem Datenexport.

Nutzen Sie Scrapling in Python, im Terminal oder mit Ihrem KI-Agenten über den MCP-Server und den Agent Skill. Es deckt den ganzen Ablauf ab: von wenigen Feldern bis zum Speichern einer ganzen Website als saubere Markdown-Dateien.

## Was Sie mit Scrapling machen können

- **[Seiten abrufen und bedienen](https://scrapling.readthedocs.io/de/latest/fetching/choosing.html)**: Schnelle HTTP-Anfragen, Stealth-Browser, JavaScript-Ausführung, Umgang mit Cloudflare Turnstile und Interstitial, dauerhafte Sitzungen und Aufzeichnung von API-Antworten im Hintergrund.
- **[Seiten auswerten und Daten extrahieren](https://scrapling.readthedocs.io/de/latest/parsing/selection.html)**: Suche mit CSS, XPath, Text und regulären Ausdrücken, Wiederfinden von Elementen nach Änderungen der Seite, Suche nach ähnlichen Elementen und saubere Markdown-Ausgabe.
- **[Crawlen und exportieren](https://scrapling.readthedocs.io/de/latest/spiders/getting-started.html)**: Parallele Spider, Proxy-Rotation, Wiederholungsversuche, AutoThrottle, Pause und Fortsetzung, Streaming, fertige Vorlagen und Export nach JSON, JSONL, CSV und XML.
- **[Daten mit KI oder im Terminal extrahieren](https://scrapling.readthedocs.io/de/latest/ai/mcp-server.html)**: Ein MCP-Server zum Browsen und Extrahieren von Daten mit KI-Agenten, ein Agent Skill, CLI-Befehle und eine interaktive Shell.

Beginnen Sie mit einer einzelnen Seite:

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

Oder extrahieren Sie mehr Daten mit einem Spider:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

Das gibt `10` aus und speichert Zitate und Autoren in `quotes.json`.

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# Platin-Sponsoren
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> - der effizienteste Proxy-Anbieter für Web Scraping und Automatisierung mit der höchsten IP-Qualität auf dem Markt. Nutzen Sie den Code SCRAPLING35 für 35 % Rabatt.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling bewältigt Cloudflare Turnstile. Für Schutz auf Unternehmensebene bietet <a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a> API-Endpunkte, die gültige Antibot-Tokens für <b>Akamai</b>, <b>DataDome</b>, <b>Kasada</b> und <b>Incapsula</b> generieren. Einfache API-Aufrufe, keine Browser-Automatisierung nötig. </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a>: Residential-Proxys ab 0,49 $/GB. Scraping-Browser auf Chromium-Basis mit vollständig veränderten Fingerprints, Residential-IPs, automatischer CAPTCHA-Lösung und Anti-Bot-Umgehung. </br>
      <b>Scraper-API für problemlose Ergebnisse. MCP- und N8N-Integrationen verfügbar.</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    Lesen Sie eine vollständige Rezension von <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">Scrapling auf The Web Scraping Club</a> (Nov. 2025), dem führenden Newsletter für Web Scraping.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a> bietet skalierbare Residential-Proxys mit über 80 Mio. IPs in mehr als 195 Ländern und liefert schnelle, zuverlässige Verbindungen, automatische Rotation und wirksamen Schutz vor Sperren. Kostenlose Testversion verfügbar.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a> bietet ethisch beschaffte Residential-, Mobil-, ISP- und Datacenter-Proxys sowie Tools für Web Scraping und KI-Automatisierung. Mit dem Code SCRAPLING10 erhalten Sie 10 % Rabatt auf Residential-Proxys.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a>: Reduzieren Sie Sperren und CAPTCHAs um 90 %. 28 Mio. Premium-Residential-IPs für umfangreiches Web Scraping. 195 Länder. Gezielte Auswahl nach Stadt/ISP/Postleitzahl. Sitzungen mit fester oder rotierender IP. Datenvolumen ohne Ablaufdatum ab $2/GB. Code <strong>SCRAPEANDTAKE</strong>: <em>25 % Rabatt</em>.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a>: Zahlen Sie nicht länger pro GB. Unbegrenzter Residential-Traffic, über 100 Mio. IPs, mehr als 190 Länder. Zahlen Sie nach Bandbreite. Fordern Sie einen kostenlosen Test der Residential-Proxys mit 50 Mbps an.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    $1/GB bei <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a>. Ethisch bezogene Proxys aus erster Hand. Über 90 Mio. IPs, mehr als 195 Länder. Residential-, Datacenter- und Mobilproxys. Nutzungsabhängige Zahlung = kein Abo. Datenvolumen verfällt nie.
    </td>
  </tr>
</table>

<i><sub>Möchten Sie Ihre Anzeige hier zeigen? Klicken Sie [hier](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)</sub></i>
# Sponsoren



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>Möchten Sie Ihre Anzeige hier zeigen? Klicken Sie [hier](https://github.com/sponsors/D4Vinci) und wählen Sie die Stufe, die zu Ihnen passt!</sub></i>

---

## Wichtige Funktionen

### Spider: ein vollständiges Crawling-Framework

- 🕷️ **Spider-API ähnlich wie Scrapy**: Definieren Sie Spider mit `start_urls`, asynchronen `parse`-Callbacks sowie `Request`- und `Response`-Objekten.
- ⚡ **Paralleles Crawling**: Legen Sie die Anzahl gleichzeitiger Anfragen, die Grenzen pro Domain und die Wartezeit zwischen Downloads fest.
- 🔄 **Mehrere Sitzungen**: Nutzen Sie HTTP-Anfragen und Stealth-Browser ohne grafische Oberfläche im selben Spider. Leiten Sie Anfragen über die ID an unterschiedliche Sitzungen weiter.
- 💾 **Pause und Fortsetzung**: Speichern Sie ausstehende Anfragen und besuchte URLs mit `crawldir`. Drücken Sie Strg+C, um sicher anzuhalten, und starten Sie mit demselben Ordner erneut.
- 📡 **Ergebnisse als Stream**: Empfangen Sie Elemente direkt nach dem Extrahieren mit `async for item in spider.stream()`, zusammen mit Statistiken in Echtzeit. Das eignet sich für Oberflächen, Datenverarbeitung und lange Crawls.
- 🛡️ **Blockierte Anfragen erkennen**: Erkennen und wiederholen Sie blockierte Anfragen automatisch. Sie können das Verhalten anpassen.
- 🚦 **AutoThrottle**: Der Spider passt die Wartezeit pro Domain an die Antwortgeschwindigkeit der Website an. Blockiert oder begrenzt die Website Anfragen, verdoppelt er die Wartezeit oder hält die von `Retry-After` angegebene Zeit ein. Danach beschleunigt er wieder.
- 🤖 **robots.txt beachten**: Aktivieren Sie `robots_txt_obey`, um die Vorgaben `Disallow`, `Crawl-delay` und `Request-rate` zu beachten. Die Angaben werden pro Domain zwischengespeichert.
- 🧪 **Entwicklungsmodus**: Speichern Sie Antworten beim ersten Lauf auf der Festplatte und nutzen Sie sie danach erneut. So können Sie `parse()` anpassen, ohne neue Anfragen an die Server zu senden.
- 🧩 **Fertige Spider-Vorlagen**: Nutzen Sie `CrawlSpider`, um Links nach Regeln zu folgen, `SitemapSpider` für Crawls über Sitemaps oder robots.txt, `XMLFeedSpider` und `CSVFeedSpider` zum Lesen von XML-, RSS- und CSV-Feeds sowie `ShopifySpider` zum Sammeln von Produkten aus öffentlichen Shopify-Shops, mit einem Element pro Variante.
- 🔗 **Links extrahieren**: `LinkExtractor` erlaubt oder verwirft Links anhand von Mustern, filtert Domains und Dateiendungen, begrenzt die Suche mit CSS oder XPath und vereinheitlicht URLs. Nutzen Sie ihn mit den Vorlagen oder einzeln.
- 📦 **Integrierter Export**: Exportieren Sie Ergebnisse mit Hooks und Ihrer eigenen Datenverarbeitung oder mit den integrierten Formaten JSON, JSONL, CSV und XML: `result.items.to_json()`, `to_jsonl()`, `to_csv()` und `to_xml()`.

### Seiten mit Sitzungen abrufen

- **HTTP-Anfragen**: Senden Sie schnelle und unauffällige HTTP-Anfragen mit `Fetcher`. Sie können TLS-Fingerprints und Header eines Browsers nachbilden und HTTP/3 nutzen.
- **Dynamisches Laden**: Rufen Sie dynamische Websites mit vollständiger Browserautomatisierung über `StealthyFetcher` ab. Er unterstützt das Chromium von Playwright und Google Chrome.
- **Antibot-Systeme umgehen**: `StealthyFetcher` verbirgt die Automatisierung und bildet Browser-Fingerprints nach. Er kann verschiedene Arten von Cloudflare Turnstile und Interstitial automatisch lösen.
- **Sitzungen verwalten**: `FetcherSession` und `StealthySession` behalten Cookies und den Zustand zwischen Anfragen bei.
- **Proxy-Rotation**: `ProxyRotator` wechselt Proxys zyklisch oder nach eigenen Regeln in allen Sitzungstypen. Sie können auch einen Proxy für eine einzelne Anfrage wählen.
- **Domains und Werbung blockieren**: Blockieren Sie Anfragen an bestimmte Domains und deren Subdomains, oder aktivieren Sie den Werbeblocker der Browser-Fetcher. Er umfasst etwa 3.500 bekannte Werbe- und Tracking-Domains.
- **DNS-Lecks verhindern**: Aktivieren Sie DNS-over-HTTPS, um DNS-Anfragen über den DoH-Dienst von Cloudflare zu senden und Lecks bei der Nutzung von Proxys zu verhindern.
- **Entfernte Browser**: Verbinden Sie sich über CDP und `cdp_url` mit einem laufenden Browser, auf Ihrem Computer, einem anderen Server oder bei einem Browserdienst. Mit `executable_path` können Sie auch Ihre eigene Chromium-Version für jeden Browser-Fetcher verwenden.
- **API-Antworten im Hintergrund aufzeichnen**: Aktivieren Sie `record_requests=True` in einer Browsersitzung und suchen Sie gespeicherte Antworten mit `session.network.search(limit=None)`. Lesen Sie API-Daten und HTTP-Fehler aus mehreren Seitenaufrufen, ohne die Anfragen zu wiederholen. Der Verlauf ist in seiner Größe begrenzt und speichert den Inhalt von Textantworten.
- **Asynchroner Betrieb**: Alle Fetcher lassen sich asynchron nutzen. Dafür gibt es eigene Sitzungsklassen.

### Seiten auswerten und Daten extrahieren

- 🔄 **Elemente wiederfinden**: Finden Sie Elemente nach Änderungen der Website mit Algorithmen zur Ähnlichkeitssuche wieder.
- 🎯 **Flexible Auswahl**: Nutzen Sie CSS, XPath, Filter, Text, reguläre Ausdrücke und mehr.
- 🔍 **Ähnliche Elemente**: Finden Sie automatisch Elemente, die den bereits gefundenen ähneln.

### KI-Funktionen

- 🤖 **MCP-Server**: Ermöglicht Assistenten und KI-Agenten wie Claude und Cursor, Daten mit Scrapling zu extrahieren. Dazu dienen HTTP-Anfragen, Browseraktionen, Screenshots, ein gespeicherter Anmeldezustand und API-Antworten im Hintergrund. Er nutzt unseren Stealth-Browser und Werkzeuge, mit denen geeignete Modelle CAPTCHAs lösen können, zusätzlich zum Cloudflare-Löser. Er verringert den an das Modell gesendeten Inhalt, blockiert Werbung und schützt vor Prompt Injection. Entfernte Browser über CDP und HTTP-Verbindungen mit Authentifizierungsoptionen sind ebenfalls möglich. ([Demovideo](https://www.youtube.com/watch?v=qyFk3ZNwOxE))
- 🧠 **Agent Skill**: Ein [Agent Skill](https://scrapling.readthedocs.io/de/latest/ai/agent-skill.html) zum Installieren, der Coding-Agenten die Bibliothek erklärt. So schreiben sie Code, der zur aktuellen API passt.
- 📚 **Markdown für RAG**: Wandeln Sie eine Seite mit einer Zeile (`page.markdown()`) in sauberes Markdown für Sprachmodelle um, oder speichern Sie mit der Vorlage `ContentSpider` eine ganze Website als Markdown-Dateien. Dafür ist kein Sprachmodell nötig. ([Dokumentation](https://scrapling.readthedocs.io/de/latest/ai/building-rag-systems.html))

### Schnell und im Alltag erprobt

- 🚀 **Hohe Geschwindigkeit**: Optimierte Leistung, die die meisten Web-Scraping-Bibliotheken für Python übertrifft.
- 🔋 **Geringer Speicherbedarf**: Optimierte Datenstrukturen und Laden bei Bedarf.
- ⚡ **Schnelle JSON-Ausgabe**: 10-mal schneller als die Standardbibliothek.
- 🏗️ **In der Praxis getestet**: Tests decken 92 % von Scrapling ab, und der gesamte Code hat Typannotationen. Hunderte Menschen haben es im letzten Jahr täglich zur Datenextraktion verwendet.

### Werkzeuge für Entwicklung und Datenextraktion

- 🎯 **Interaktive Shell**: Eine optionale IPython-Shell mit Scrapling, Kurzbefehlen und Werkzeugen für die schnelle Entwicklung von Skripten. Wandeln Sie curl-Anfragen in Scrapling-Anfragen um und zeigen Sie Ergebnisse im Browser an.
- 🚀 **Nutzung im Terminal**: Extrahieren Sie die Daten einer URL, ohne Code zu schreiben.
- 🛠️ **Navigation im DOM**: Greifen Sie auf Eltern-, Geschwister- und Kindelemente zu.
- 🧬 **Textverarbeitung**: Reguläre Ausdrücke, Textbereinigung und optimierte Arbeit mit Zeichenketten.
- 📝 **Selektoren erzeugen**: Erstellen Sie zuverlässige CSS- und XPath-Selektoren für jedes Element.
- 🔌 **Vertraute API**: Ähnlich wie Scrapy und BeautifulSoup, mit denselben Pseudoelementen wie Scrapy und Parsel.
- 🤝 **Direkte Integration mit Scrapy**: Ergänzen Sie einen Callback um den Dekorator `scrapling_response`, um die bereits abgerufenen Antworten mit dem Scrapling-Parser auszuwerten. Sie müssen Ihr Programm nicht neu schreiben.
- 📘 **Vollständige Typannotationen**: Sie helfen dem Editor, Code zu prüfen und zu vervollständigen. Der gesamte Code wird bei jeder Änderung automatisch mit **PyRight** und **MyPy** geprüft.
- 🔋 **Fertiges Docker-Image**: Bei jeder Version wird automatisch ein Docker-Image mit allen Browsern erstellt und veröffentlicht.

## Erste Schritte

Hier sehen Sie einige Beispiele für Scrapling.

### Grundlegende Verwendung
HTTP-Anfragen mit Sitzungen
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # Neueste Version von Chromes TLS-Fingerprint verwenden
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# Oder einmalige Anfragen verwenden
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
Erweiterter Stealth-Modus
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # Browser offen halten, bis Sie fertig sind
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# Oder einmaligen Anfragenstil verwenden: öffnet den Browser für diese Anfrage und schließt ihn nach Abschluss
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
Vollständige Browser-Automatisierung
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # Browser offen halten, bis Sie fertig sind
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # XPath-Selektor, falls bevorzugt

# Oder einmaligen Anfragenstil verwenden: öffnet den Browser für diese Anfrage und schließt ihn nach Abschluss
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### Spider
Erstellen Sie vollständige Crawler mit parallelen Anfragen, mehreren Sitzungstypen, Pause und Fortsetzung:
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"{len(result.items)} Zitate gescrapt")
result.items.to_json("quotes.json")
```
Verwenden Sie mehrere Sitzungstypen im selben Spider:
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]

    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)

    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # Geschützte Seiten über die Stealth-Session leiten
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # Expliziter Callback
```
Speichern Sie den Fortschritt, um lange Crawls zu pausieren und fortzusetzen. Starten Sie den Spider so:
```python
QuotesSpider(crawldir="./crawl_data").start()
```
Mit gesetztem `crawldir` speichert Strg+C ausstehende Anfragen und bereits besuchte URLs. Starten Sie mit demselben `crawldir` neu, um fortzufahren. Speichern Sie extrahierte Daten separat.

Sie können auch eine fertige Vorlage verwenden. Rufen Sie zum Beispiel den ganzen Katalog eines Shopify-Shops ab:
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # Alle Produkte im Shop, ein Item pro Variante
```
Die Vorlage liest Produkte aus den öffentlichen Endpunkten der Kollektionen, mit einem Element pro Variante.

### Erweiterte Auswertung und Navigation
```python
from scrapling.fetchers import Fetcher

# Umfangreiche Elementauswahl und Navigation
page = Fetcher.get('https://quotes.toscrape.com/')

# Zitate mit verschiedenen Auswahlmethoden abrufen
quotes = page.css('.quote')  # CSS-Selektor
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # BeautifulSoup-Stil
# Gleich wie
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # und so weiter...
# Element nach Textinhalt finden
quotes = page.find_by_text('Albert Einstein', first_match=False)

# Erweiterte Navigation
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # Verkettete Selektoren
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# Elementbeziehungen und Ähnlichkeit
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
Sie können den Parser direkt verwenden, ohne eine Webseite abzurufen:
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
Er funktioniert auf dieselbe Weise.

### Beispiele für asynchrone Sitzungen
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # `FetcherSession` passt sich dem Kontext an und funktioniert synchron wie asynchron
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## CLI und interaktive Shell

Sie können Scrapling auch im Terminal verwenden:

[](https://asciinema.org/a/736339)

Starten Sie die interaktive Web-Scraping-Shell:
```bash
pip install "scrapling[shell]"
scrapling shell
```
Seiten direkt ohne Programmierung in eine Datei extrahieren. Wählen Sie Inhalte mit `--css-selector` aus oder verwenden Sie `--ai-targeted`, um den `body`-Inhalt auszuwählen und zu bereinigen. Nutzen Sie `.txt` für Text, `.md` für Markdown oder `.html` für HTML.
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> Weitere Funktionen, darunter der MCP-Server und die interaktive Shell, stehen in der [vollständigen Dokumentation](https://scrapling.readthedocs.io/de/latest/).

## Leistungstests

Scrapling zeichnet sich auch durch seine Geschwindigkeit aus. Diese Tests vergleichen seinen Parser mit den neuesten Versionen anderer bekannter Bibliotheken.

### Geschwindigkeit der Textextraktion (5.000 verschachtelte Elemente)

| # |    Bibliothek     | Zeit (ms) | Im Vergleich zu Scrapling |
|---|:-----------------:|:---------:|:------------:|
| 1 |     Scrapling     |   1,99    |     1,0x     |
| 2 |   Parsel/Scrapy   |   2,06    |    1,035     |
| 3 |     Lxml allein      |   2,56    |    1,286     |
| 4 |      PyQuery      |   23,98   |     ~12x     |
| 5 |    Selectolax     |  197,02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545,15  |   ~776,5x    |
| 7 |   BS4 mit Lxml   |  1562,1  |   ~785,0x    |
| 8 | BS4 mit html5lib |  3412,73  |   ~1714,9x   |


### Suche nach ähnlichen Elementen und Text

Die adaptive Elementsuche von Scrapling ist schneller als die Alternativen:

| Bibliothek  | Zeit (ms) | Im Vergleich zu Scrapling |
|-------------|:---------:|:------------:|
| Scrapling   |   2,3    |     1,0x     |
| AutoScraper |   12,58   |    5,47x    |


> Jedes Ergebnis ist der Durchschnitt aus mindestens 100 Durchläufen. Die Methode steht in [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py).

## Installation

Scrapling benötigt Python 3.10 oder neuer:

```bash
pip install scrapling
```

> [!IMPORTANT]
> Dieser Befehl installiert nur den Parser und seine Abhängigkeiten, ohne Fetcher oder Werkzeuge für die Kommandozeile. Wenn Sie nur das installieren, führt ein Import aus `scrapling.fetchers` oder `scrapling.spiders`, wie in den Beispielen oben, zu `ModuleNotFoundError`. Für Fetcher oder Spider müssen Sie zuerst die Fetcher-Abhängigkeiten wie unten gezeigt installieren.

### Optionale Abhängigkeiten

1. Für Fetcher, deren Klassen oder die folgenden Zusatzfunktionen installieren Sie die Abhängigkeiten der Fetcher und Browser:
    ```bash
    pip install "scrapling[fetchers]"

    scrapling install           # normal install
    scrapling install  --force  # force reinstall
    ```

    Dadurch werden alle Browser, ihre Systemabhängigkeiten und die Werkzeuge zum Ändern der Browser-Fingerprints heruntergeladen.

    Sie können sie auch aus Python installieren, statt einen Befehl auszuführen:
    ```python
    from scrapling.cli import install

    install([], standalone_mode=False)          # normal install
    install(["--force"], standalone_mode=False) # force reinstall
    ```

2. Zusatzfunktionen:
   - Den MCP-Server installieren:
       ```bash
       pip install "scrapling[ai]"
       ```
   - Die Abhängigkeiten zum [Aufbau von RAG-Systemen](https://scrapling.readthedocs.io/de/latest/ai/building-rag-systems.html) installieren:
       ```bash
       pip install "scrapling[rag]"
       ```
   - Die interaktive Shell und den Befehl `extract` installieren:
       ```bash
       pip install "scrapling[shell]"
       ```
   - Alles installieren:
       ```bash
       pip install "scrapling[all]"
       ```
   Führen Sie `scrapling install` aus, wenn Sie Browser-Fetcher nutzen möchten. HTTP-Anfragen benötigen keinen Browser.

### Docker
Sie können auch ein Docker-Image mit allen Extras und Browsern von DockerHub herunterladen:
```bash
docker pull pyd4vinci/scrapling
```
Oder aus der GitHub-Registry herunterladen:
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
Das Image wird aus dem Hauptbranch des Repositorys erstellt und von GitHub Actions automatisch veröffentlicht.

## Mitwirken

Wir freuen uns über Beiträge! Bitte lesen Sie unsere [Beitragsrichtlinien](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md), bevor Sie beginnen.

## Haftungsausschluss

> [!CAUTION]
> Diese Bibliothek dient nur der Bildung und Forschung. Mit ihrer Nutzung stimmen Sie zu, die lokalen und internationalen Gesetze zur Datenextraktion und zum Datenschutz einzuhalten. Die Autoren und Mitwirkenden sind nicht für den Missbrauch dieser Software verantwortlich. Beachten Sie die Nutzungsbedingungen der Websites und die robots.txt-Dateien.

## 🎓 Zitieren
Wenn Sie diese Bibliothek in Ihrer Forschung verwendet haben, zitieren Sie sie mit dieser Referenz:
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## Lizenz

Dieses Projekt nutzt die BSD-3-Clause-Lizenz.

## Danksagungen

Dieses Projekt enthält angepassten Code von:
- Parsel (BSD-Lizenz): verwendet für das Submodul [translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py)

---
<div align="center"><small>Entworfen und hergestellt mit ❤️ von Karim Shoair.</small></div><br>

---

### README ES (`docs/README_ES.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io/es/latest/">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Scrapling Poster" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>Extrae datos de la web moderna de forma sencilla</small>
</h1>

<p align="center">
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="Tests">
        <img alt="Tests" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="PyPI version">
        <img alt="PyPI version" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="PyPI package downloads"></a>
    <a href="https://scrapling.readthedocs.io/es/latest/ai/agent-skill.html" alt="AI Agent Skill">
        <img alt="Static Badge" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Fes%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="OpenClaw Skill">
        <img alt="OpenClaw Skill" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X (formerly Twitter)">
      <img alt="X (formerly Twitter) Follow" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="Supported Python versions">
        <img alt="Supported Python versions" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/es/latest/parsing/selection.html"><strong>Métodos de selección</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/es/latest/fetching/choosing.html"><strong>Elegir un fetcher</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/es/latest/spiders/architecture.html"><strong>Spiders</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/es/latest/spiders/proxy-blocking.html"><strong>Rotación de proxy</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/es/latest/cli/overview.html"><strong>CLI</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/es/latest/ai/mcp-server.html"><strong>Servidor MCP</strong></a>
</p>

Scrapling es un framework de web scraping para Python. Reúne solicitudes HTTP rápidas, navegadores sigilosos, análisis de páginas y rastreo concurrente en una sola biblioteca.

Extrae datos de páginas estáticas, ejecuta JavaScript, interactúa con sitios web y accede a las API que usan. Crea crawlers con sesiones reutilizables, rotación de proxies, reintentos automáticos, pausa y reanudación, y exportación de datos integrada.

Úsalo desde Python, la terminal o tu agente de IA mediante el servidor MCP y Agent Skill. Scrapling cubre todo el proceso, desde extraer unos campos hasta guardar un sitio completo como archivos Markdown limpios.

## Qué puedes hacer con Scrapling

- **[Obtener páginas e interactuar](https://scrapling.readthedocs.io/es/latest/fetching/choosing.html)**: Solicitudes HTTP rápidas, navegadores sigilosos, ejecución de JavaScript, gestión de Cloudflare Turnstile e Interstitial, sesiones persistentes y captura de respuestas de API en segundo plano.
- **[Analizar y extraer](https://scrapling.readthedocs.io/es/latest/parsing/selection.html)**: Búsqueda con CSS, XPath, texto y expresiones regulares, seguimiento de elementos cuando cambia la página, búsqueda de elementos similares y salida en Markdown limpio.
- **[Rastrear y exportar](https://scrapling.readthedocs.io/es/latest/spiders/getting-started.html)**: Spiders concurrentes, rotación de proxies, reintentos, AutoThrottle, pausa y reanudación, resultados en streaming, plantillas listas para usar y exportación a JSON, JSONL, CSV y XML.
- **[Extraer datos con IA o desde la terminal](https://scrapling.readthedocs.io/es/latest/ai/mcp-server.html)**: Un servidor MCP para que los agentes de IA naveguen y extraigan datos, un Agent Skill, comandos CLI y una consola interactiva.

Empieza con una sola página:

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

O escala con un Spider:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

Imprime `10` y guarda las citas y sus autores en `quotes.json`.

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# Patrocinadores Platino
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> - el proveedor de proxies más eficiente para Web Scraping y automatización, con la mayor calidad de IP del mercado. Usa el código SCRAPLING35 para obtener un 35% de descuento.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling maneja Cloudflare Turnstile. Para protección de nivel empresarial, <a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a> proporciona endpoints API que generan tokens antibot válidos para <b>Akamai</b>, <b>DataDome</b>, <b>Kasada</b> e <b>Incapsula</b>. Simples llamadas API, sin automatización de navegador. </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a>: proxies residenciales desde 0,49 $/GB. Navegador de scraping con Chromium con la huella completamente modificada, IPs residenciales, resolución automática de CAPTCHA y evasión anti-bot. </br>
      <b>API Scraper para resultados sin complicaciones. Integraciones MCP y N8N disponibles.</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    Lee una reseña completa de <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">Scrapling en The Web Scraping Club</a> (nov. 2025), el boletín número uno dedicado al Web Scraping.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a> ofrece proxies residenciales escalables con más de 80 millones de IPs en más de 195 países, brindando conexiones rápidas y fiables, rotación automática y un sólido rendimiento anti-bloqueo. Prueba gratuita disponible.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a> ofrece proxies residenciales, móviles, ISP y de centros de datos de origen ético, además de herramientas de scraping y automatización con IA. Usa el código SCRAPLING10 para obtener un 10% de descuento en proxies residenciales.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a>: Reduce los bloqueos y los CAPTCHAs en un 90%. 28 millones de IPs residenciales premium para scraping web intensivo. 195 países. Segmentación por ciudad/ISP/código postal. Sesiones persistentes o rotativas. Tráfico sin caducidad desde $2/GB. Código <strong>SCRAPEANDTAKE</strong>: <em>25% de descuento</em>.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a>: Deja de pagar por GB. Tráfico residencial ilimitado, más de 100 millones de IPs, más de 190 países. Paga según el ancho de banda. Solicita una prueba gratuita de proxies residenciales de 50 Mbps.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    $1/GB en <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a>. Proxies de primera mano de origen ético. Más de 90 millones de IPs, más de 195 países. Residenciales, de centros de datos y móviles. Pago por uso = sin suscripción. El tráfico nunca caduca.
    </td>
  </tr>
</table>

<i><sub>¿Quieres mostrar tu anuncio aquí? Haz clic [aquí](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)</sub></i>
# Patrocinadores



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>¿Quieres mostrar tu anuncio aquí? ¡Haz clic [aquí](https://github.com/sponsors/D4Vinci) y elige el nivel que te convenga!</sub></i>

---

## Funciones principales

### Spiders: un framework completo de rastreo
- 🕷️ **API de Spider similar a Scrapy**: Define spiders con `start_urls`, callbacks `parse` asíncronos y objetos `Request` y `Response`.
- ⚡ **Rastreo concurrente**: Configura el número de solicitudes simultáneas, los límites por dominio y la espera entre descargas.
- 🔄 **Varias sesiones**: Usa solicitudes HTTP y navegadores sigilosos sin interfaz gráfica en un mismo spider. Envía las solicitudes a distintas sesiones mediante su ID.
- 💾 **Pausa y reanudación**: Guarda las solicitudes pendientes y las URL visitadas con `crawldir`. Pulsa Ctrl+C para detener el proceso de forma segura y vuelve a iniciarlo con el mismo directorio.
- 📡 **Resultados en streaming**: Recibe los elementos a medida que se extraen con `async for item in spider.stream()`, junto con estadísticas en tiempo real. Es útil para interfaces, procesos de datos y rastreos largos.
- 🛡️ **Detección de solicitudes bloqueadas**: Detecta y reintenta las solicitudes bloqueadas de forma automática. Puedes personalizar este comportamiento.
- 🚦 **AutoThrottle**: El spider ajusta la espera de cada dominio según la velocidad de respuesta del sitio. Si el sitio bloquea o limita las solicitudes, duplica la espera o respeta el tiempo indicado por `Retry-After`. Vuelve a acelerar cuando termina la limitación.
- 🤖 **Respeto de robots.txt**: Activa `robots_txt_obey` para respetar las directivas `Disallow`, `Crawl-delay` y `Request-rate`, con caché por dominio.
- 🧪 **Modo de desarrollo**: Guarda las respuestas en disco durante la primera ejecución y reutilízalas después. Así puedes ajustar `parse()` sin enviar nuevas solicitudes a los servidores.
- 🧩 **Plantillas de spider listas para usar**: Usa `CrawlSpider` para seguir enlaces según reglas, `SitemapSpider` para rastrear desde sitemaps o robots.txt, `XMLFeedSpider` y `CSVFeedSpider` para leer fuentes XML, RSS y CSV, y `ShopifySpider` para recoger productos de tiendas públicas de Shopify, con un elemento por variante.
- 🔗 **Extracción de enlaces**: `LinkExtractor` permite aceptar o rechazar enlaces con patrones, filtrar dominios y extensiones, limitar la búsqueda con CSS o XPath y normalizar las URL. Úsalo con las plantillas o por separado.
- 📦 **Exportación integrada**: Exporta los resultados con hooks y tu propio proceso de datos, o usa los formatos JSON, JSONL, CSV y XML integrados: `result.items.to_json()`, `to_jsonl()`, `to_csv()` y `to_xml()`.

### Obtención de páginas con soporte de sesiones
- **Solicitudes HTTP**: Envía solicitudes HTTP rápidas y sigilosas con `Fetcher`. Puedes imitar la huella TLS y las cabeceras de un navegador, y usar HTTP/3.
- **Carga dinámica**: Obtén sitios dinámicos con automatización completa del navegador mediante `StealthyFetcher`, compatible con Chromium de Playwright y Google Chrome.
- **Evasión de sistemas antibot**: `StealthyFetcher` oculta la automatización e imita huellas del navegador. Puede superar automáticamente los distintos tipos de Cloudflare Turnstile e Interstitial.
- **Gestión de sesiones**: `FetcherSession` y `StealthySession` mantienen las cookies y el estado entre solicitudes.
- **Rotación de proxies**: `ProxyRotator` permite rotar los proxies de forma cíclica o personalizada en todos los tipos de sesión. También puedes elegir un proxy para una solicitud concreta.
- **Bloqueo de dominios y anuncios**: Bloquea solicitudes a dominios y subdominios concretos, o activa el bloqueo de anuncios integrado en los fetchers de navegador. Incluye unos 3500 dominios conocidos de anuncios y seguimiento.
- **Prevención de fugas DNS**: Activa DNS-over-HTTPS para enviar las consultas DNS mediante el servicio DoH de Cloudflare y evitar fugas al usar proxies.
- **Navegadores remotos**: Conecta con un navegador que ya esté en ejecución mediante CDP y `cdp_url`, en tu equipo, en otro servidor o en un servicio de navegadores. También puedes usar tu propia versión de Chromium con cualquier fetcher de navegador mediante `executable_path`.
- **Captura de API en segundo plano**: Activa `record_requests=True` en una sesión de navegador y busca las respuestas guardadas con `session.network.search(limit=None)`. Lee datos de API y errores HTTP de distintas cargas de página sin repetir las solicitudes. El historial tiene un tamaño limitado y guarda el contenido de las respuestas de texto.
- **Soporte asíncrono**: Todos los fetchers admiten el uso asíncrono, con clases de sesión dedicadas.

### Análisis de páginas y extracción de datos
- 🔄 **Seguimiento de elementos**: Encuentra los elementos después de que cambie el sitio mediante algoritmos de similitud.
- 🎯 **Selección flexible**: Usa selectores CSS y XPath, filtros, texto, expresiones regulares y más.
- 🔍 **Elementos similares**: Encuentra automáticamente elementos parecidos a los que ya has localizado.

### Funciones de IA
- 🤖 **Servidor MCP**: Permite que los asistentes y agentes de IA, como Claude y Cursor, extraigan datos con Scrapling mediante solicitudes HTTP, acciones del navegador, capturas de pantalla, estado de inicio de sesión guardado y respuestas de API en segundo plano. Usa nuestro navegador sigiloso y herramientas que ayudan a los modelos adecuados a resolver CAPTCHA, además del solucionador de Cloudflare. Reduce el contenido enviado al modelo, bloquea anuncios y lo protege de la inyección de instrucciones (prompt injection). También admite navegadores remotos por CDP y conexiones HTTP con opciones de autenticación. ([Vídeo de demostración](https://www.youtube.com/watch?v=qyFk3ZNwOxE))
- 🧠 **Agent Skill**: Un [Agent Skill](https://scrapling.readthedocs.io/es/latest/ai/agent-skill.html) listo para instalar que enseña la biblioteca a los agentes de programación, para que escriban código que coincida con la API actual.
- 📚 **Markdown listo para RAG**: Convierte una página en Markdown limpio y preparado para modelos de lenguaje con una línea (`page.markdown()`), o guarda un sitio completo como archivos Markdown con la plantilla `ContentSpider`. No requiere un modelo de lenguaje durante el proceso. ([Documentación](https://scrapling.readthedocs.io/es/latest/ai/building-rag-systems.html))

### Alto rendimiento y uso probado
- 🚀 **Alta velocidad**: Rendimiento optimizado que supera a la mayoría de las bibliotecas de web scraping para Python.
- 🔋 **Bajo consumo de memoria**: Estructuras de datos optimizadas y carga solo cuando se necesita.
- ⚡ **Conversión rápida a JSON**: 10 veces más rápida que la biblioteca estándar.
- 🏗️ **Probado en la práctica**: Las pruebas cubren el 92% de Scrapling y todo el código tiene anotaciones de tipos. Cientos de personas lo han usado a diario para extraer datos durante el último año.

### Herramientas para desarrollar y extraer datos
- 🎯 **Consola interactiva**: Consola IPython opcional integrada con Scrapling, con atajos y herramientas para escribir scripts más rápido. Convierte solicitudes curl en solicitudes de Scrapling y muestra los resultados en el navegador.
- 🚀 **Uso desde la terminal**: Extrae los datos de una URL sin escribir código.
- 🛠️ **Navegación por el DOM**: Recorre los elementos padre, hermanos e hijos.
- 🧬 **Procesamiento de texto**: Expresiones regulares, limpieza de texto y operaciones de cadenas optimizadas.
- 📝 **Generación de selectores**: Genera selectores CSS y XPath fiables para cualquier elemento.
- 🔌 **API conocida**: Similar a Scrapy y BeautifulSoup, con los mismos pseudoelementos que Scrapy y Parsel.
- 🤝 **Integración directa con Scrapy**: Añade el decorador `scrapling_response` a un callback para analizar las respuestas que ya obtienes con el parser de Scrapling, sin reescribir tu programa.
- 📘 **Anotaciones de tipos completas**: Ayudan al editor a comprobar y completar el código. Todo el código se revisa automáticamente con **PyRight** y **MyPy** en cada cambio.
- 🔋 **Imagen Docker lista para usar**: Con cada versión se crea y publica automáticamente una imagen Docker que contiene todos los navegadores.

## Primeros pasos

Estos ejemplos muestran cómo empezar con Scrapling.

### Uso básico
Solicitudes HTTP con soporte de sesión
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # Usa la última versión del fingerprint TLS de Chrome
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# O usa solicitudes de una sola vez
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
Modo sigiloso avanzado
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # Mantén el navegador abierto hasta que termines
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# O usa el estilo de solicitud de una sola vez, abre el navegador para esta solicitud, luego lo cierra después de terminar
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
Automatización completa del navegador
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # Mantén el navegador abierto hasta que termines
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # Selector XPath si lo prefieres

# O usa el estilo de solicitud de una sola vez, abre el navegador para esta solicitud, luego lo cierra después de terminar
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### Spiders
Crea spiders con solicitudes concurrentes, varios tipos de sesión, pausa y reanudación:
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"Se extrajeron {len(result.items)} citas")
result.items.to_json("quotes.json")
```
Usa varios tipos de sesión en un mismo spider:
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]

    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)

    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # Enruta las páginas protegidas a través de la sesión sigilosa
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # callback explícito
```
Para guardar el progreso y continuar un rastreo más tarde, inicia el spider así:
```python
QuotesSpider(crawldir="./crawl_data").start()
```
Con `crawldir` configurado, pulsa Ctrl+C para guardar las solicitudes pendientes y las URL ya vistas. Reinicia con el mismo `crawldir` para continuar. Guarda los datos extraídos por separado.

O usa una plantilla lista para usar, como esta para extraer el catálogo completo de una tienda Shopify:
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # Todos los productos de la tienda, un elemento por variante
```
La plantilla obtiene los productos mediante las API públicas de las colecciones y devuelve un elemento por variante.

### Análisis avanzado y navegación
```python
from scrapling.fetchers import Fetcher

# Selección rica de elementos y navegación
page = Fetcher.get('https://quotes.toscrape.com/')

# Obtén citas con múltiples métodos de selección
quotes = page.css('.quote')  # Selector CSS
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # Estilo BeautifulSoup
# Igual que
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # y así sucesivamente...
# Encuentra elementos por contenido de texto
quotes = page.find_by_text('Albert Einstein', first_match=False)

# Navegación avanzada
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # Selectores encadenados
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# Relaciones y similitud de elementos
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
Si ya tienes el HTML, puedes usar el parser directamente:
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
Puedes usar los mismos métodos de selección.

### Gestión de sesiones asíncronas
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # `FetcherSession` se adapta al contexto y funciona tanto con sync como con async
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## Línea de comandos y consola interactiva

Puedes usar Scrapling desde la línea de comandos:

[](https://asciinema.org/a/736339)

Para abrir la consola interactiva de web scraping:
```bash
pip install "scrapling[shell]"
scrapling shell
```
Extrae páginas directamente a un archivo sin programar. Usa `--css-selector` para elegir el contenido o `--ai-targeted` para seleccionar y limpiar el contenido de `body`. Usa `.txt` para texto, `.md` para Markdown o `.html` para HTML.
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> Estos son ejemplos breves. Para conocer más funciones, incluido el servidor MCP y la consola interactiva, consulta la documentación completa [aquí](https://scrapling.readthedocs.io/es/latest/)

## Pruebas de rendimiento

Scrapling no solo es potente, también es ultrarrápido. Los siguientes benchmarks comparan el parser de Scrapling con las últimas versiones de otras bibliotecas populares.

### Velocidad de extracción de texto (5000 elementos anidados)

| # |    Biblioteca     | Tiempo (ms) | vs Scrapling |
|---|:-----------------:|:-----------:|:------------:|
| 1 |     Scrapling     |    1,99     |     1,0x     |
| 2 |   Parsel/Scrapy   |    2,06     |     1,035    |
| 3 |     Raw Lxml      |    2,56     |    1,286     |
| 4 |      PyQuery      |    23,98    |     ~12x     |
| 5 |    Selectolax     |    197,02   |     ~99x     |
| 6 |  MechanicalSoup   |   1545,15   |   ~776,5x    |
| 7 |   BS4 with Lxml   |   1562,1    |   ~785,0x    |
| 8 | BS4 with html5lib |   3412,73   |   ~1714,9x   |


### Rendimiento de similitud de elementos y búsqueda de texto

Las capacidades de búsqueda adaptativa de elementos de Scrapling superan significativamente a las alternativas:

| Biblioteca  | Tiempo (ms) | vs Scrapling |
|-------------|:-----------:|:------------:|
| Scrapling   |     2,3     |     1,0x     |
| AutoScraper |    12,58    |    5,47x     |


> Todos los benchmarks representan promedios de más de 100 ejecuciones. Ver [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py) para la metodología.

## Instalación

Scrapling requiere Python 3.10 o superior:

```bash
pip install scrapling
```

> [!IMPORTANT]
> Este comando solo instala el parser y sus dependencias, sin fetchers ni herramientas de línea de comandos. Si no instalas nada más, importar desde `scrapling.fetchers` o `scrapling.spiders`, como en los ejemplos anteriores, produce `ModuleNotFoundError`. Para usar fetchers o spiders, instala primero sus dependencias como se indica a continuación.

### Dependencias opcionales

1. Para usar los fetchers, sus clases o las funciones adicionales siguientes, instala las dependencias de los fetchers y los navegadores:
    ```bash
    pip install "scrapling[fetchers]"

    scrapling install           # normal install
    scrapling install  --force  # force reinstall
    ```

    Esto descarga todos los navegadores, sus dependencias del sistema y las herramientas para modificar las huellas del navegador.

    O puedes instalarlos desde el código en lugar de ejecutar un comando:
    ```python
    from scrapling.cli import install

    install([], standalone_mode=False)          # normal install
    install(["--force"], standalone_mode=False) # force reinstall
    ```

2. Características adicionales:
   - Instalar el servidor MCP:
       ```bash
       pip install "scrapling[ai]"
       ```
   - Instalar dependencias para ([construir sistemas RAG](https://scrapling.readthedocs.io/es/latest/ai/building-rag-systems.html)):
       ```bash
       pip install "scrapling[rag]"
       ```
   - Instalar la consola interactiva y el comando `extract`:
       ```bash
       pip install "scrapling[shell]"
       ```
   - Instalar todo:
       ```bash
       pip install "scrapling[all]"
       ```
   Ejecuta `scrapling install` cuando necesites fetchers de navegador. Las solicitudes HTTP no requieren instalar un navegador.

### Docker
También puedes instalar una imagen Docker con todos los extras y navegadores con el siguiente comando desde DockerHub:
```bash
docker pull pyd4vinci/scrapling
```
O descárgala desde el registro de GitHub:
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
Esta imagen se construye y publica automáticamente usando GitHub Actions y la rama principal del repositorio.

## Contribuir

¡Damos la bienvenida a las contribuciones! Por favor lee nuestras [pautas de contribución](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md) antes de comenzar.

## Descargo de responsabilidad

> [!CAUTION]
> Esta biblioteca se proporciona solo con fines educativos y de investigación. Al usar esta biblioteca, aceptas cumplir con las leyes locales e internacionales de scraping de datos y privacidad. Los autores y contribuyentes no son responsables de ningún mal uso de este software. Respeta siempre los términos de servicio de los sitios web y los archivos robots.txt.

## 🎓 Citas
Si has utilizado nuestra biblioteca con fines de investigación, por favor cítanos con la siguiente referencia:
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## Licencia

Este trabajo está licenciado bajo la Licencia BSD-3-Clause.

## Agradecimientos

Este proyecto incluye código adaptado de:
- Parsel (Licencia BSD), usado para el submódulo [translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py)

---
<div align="center"><small>Diseñado y elaborado con ❤️ por Karim Shoair.</small></div><br>

---

### README FR (`docs/README_FR.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io/fr/latest/">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Couverture de Scrapling" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>Extrayez simplement les données du web moderne</small>
</h1>

<p align="center">
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="Tests">
        <img alt="Tests" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="Version sur PyPI">
        <img alt="Version sur PyPI" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Téléchargements Docker" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="Téléchargements du paquet sur PyPI"></a>
    <a href="https://scrapling.readthedocs.io/fr/latest/ai/agent-skill.html" alt="Skill pour agents IA">
        <img alt="Badge Agent Skill" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Ffr%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="Skill pour OpenClaw">
        <img alt="Skill pour OpenClaw" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X (anciennement Twitter)">
      <img alt="Suivre sur X (anciennement Twitter)" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="Versions de Python compatibles">
        <img alt="Versions de Python compatibles" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/fr/latest/parsing/selection.html"><strong>Méthodes de sélection</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/fr/latest/fetching/choosing.html"><strong>Fetchers</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/fr/latest/spiders/architecture.html"><strong>Spiders</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/fr/latest/spiders/proxy-blocking.html"><strong>Rotation des proxies</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/fr/latest/cli/overview.html"><strong>CLI</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/fr/latest/ai/mcp-server.html"><strong>MCP</strong></a>
</p>

Scrapling est un framework de web scraping pour Python. Il réunit des requêtes HTTP rapides, des navigateurs furtifs, l’analyse de pages et l’exploration simultanée de sites dans une seule bibliothèque.

Extrayez les données de pages statiques, exécutez JavaScript, interagissez avec les sites et accédez aux API qu’ils utilisent. Créez des crawlers avec des sessions réutilisables, la rotation des proxies, de nouvelles tentatives automatiques, la pause et la reprise, et des exports intégrés.

Utilisez Scrapling depuis Python, le terminal ou votre agent IA grâce au serveur MCP et à l’Agent Skill. Il couvre tout le processus, de l’extraction de quelques champs à l’enregistrement d’un site entier en fichiers Markdown propres.

## Ce que vous pouvez faire avec Scrapling

- **[Récupérer des pages et interagir](https://scrapling.readthedocs.io/fr/latest/fetching/choosing.html)** : Requêtes HTTP rapides, navigateurs furtifs, exécution de JavaScript, gestion de Cloudflare Turnstile et Interstitial, sessions persistantes et capture des réponses des API en arrière-plan.
- **[Analyser et extraire](https://scrapling.readthedocs.io/fr/latest/parsing/selection.html)** : Recherche par CSS, XPath, texte et expressions régulières, suivi des éléments après un changement de page, recherche d’éléments similaires et sortie en Markdown propre.
- **[Explorer et exporter](https://scrapling.readthedocs.io/fr/latest/spiders/getting-started.html)** : Spiders simultanés, rotation des proxies, nouvelles tentatives, AutoThrottle, pause et reprise, résultats en streaming, modèles prêts à l’emploi et exports en JSON, JSONL, CSV et XML.
- **[Extraire avec l’IA ou depuis le terminal](https://scrapling.readthedocs.io/fr/latest/ai/mcp-server.html)** : Un serveur MCP pour que les agents IA naviguent et extraient des données, une Agent Skill, des commandes CLI et un shell interactif.

Commencez par une seule page :

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

Ou extrayez plus de données avec un spider :

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

Cet exemple affiche `10` et enregistre les citations et leurs auteurs dans `quotes.json`.

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# Sponsors Platine
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> - le fournisseur de proxys le plus efficace pour le Web Scraping et l'automatisation, avec la meilleure qualité d'IP du marché. Utilisez le code SCRAPLING35 pour obtenir 35 % de réduction.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling gère Cloudflare Turnstile. Pour une protection de niveau entreprise, <a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a> fournit des endpoints API qui génèrent des tokens antibot valides pour <b>Akamai</b>, <b>DataDome</b>, <b>Kasada</b> et <b>Incapsula</b>. De simples appels API, sans automatisation de navigateur. </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a> : proxies résidentiels à partir de 0,49 $/Go. Navigateur de scraping avec Chromium dont l’empreinte est entièrement modifiée, IPs résidentielles, résolution automatique de CAPTCHA et contournement anti-bot. </br>
      <b>API Scraper pour des résultats sans tracas. Intégrations MCP et N8N disponibles.</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    Lisez une critique complète de <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">Scrapling sur The Web Scraping Club</a> (nov. 2025), la newsletter n°1 dédiée au Web Scraping.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a> propose des proxys résidentiels évolutifs avec plus de 80 millions d'IPs dans plus de 195 pays, offrant des connexions rapides et fiables, une rotation automatique et des fonctions pour éviter les blocages. Essai gratuit disponible.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a> fournit des proxys résidentiels, mobiles, ISP et de centres de données issus de sources éthiques, ainsi que des outils de scraping et d’automatisation par IA. Utilisez le code SCRAPLING10 pour obtenir 10 % de réduction sur les proxys résidentiels.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a> : Réduisez les blocages et les CAPTCHAs de 90 %. 28 millions d’adresses IP résidentielles premium pour le scraping web intensif. 195 pays. Ciblage par ville/ISP/code postal. Sessions fixes ou rotatives. Trafic sans expiration à partir de $2/GB. Code <strong>SCRAPEANDTAKE</strong> : <em>25 % de réduction</em>.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a> : Ne payez plus par GB. Trafic résidentiel illimité, plus de 100 millions d’IP, plus de 190 pays. Payez selon la bande passante. Demandez un essai gratuit de proxies résidentiels à 50 Mbps.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    $1/GB chez <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a>. Proxies de première main issus de sources éthiques. Plus de 90 millions d’IP, plus de 195 pays. Résidentiels, de datacenter et mobiles. Paiement à l’usage = sans abonnement. Le trafic n’expire jamais.
    </td>
  </tr>
</table>

<i><sub>Vous souhaitez afficher votre publicité ici ? Cliquez [ici](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)</sub></i>
# Sponsors



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>Vous souhaitez afficher votre publicité ici ? Cliquez [ici](https://github.com/sponsors/D4Vinci) et choisissez le niveau qui vous convient !</sub></i>

---

## Fonctions principales

### Spiders : un framework complet d’exploration de sites

- 🕷️ **API de Spider proche de Scrapy** : Définissez des spiders avec `start_urls`, des callbacks `parse` asynchrones et des objets `Request` et `Response`.
- ⚡ **Exploration simultanée** : Réglez le nombre de requêtes simultanées, les limites par domaine et le délai entre les téléchargements.
- 🔄 **Plusieurs sessions** : Utilisez des requêtes HTTP et des navigateurs furtifs sans interface graphique dans le même spider. Dirigez les requêtes vers différentes sessions grâce à leur ID.
- 💾 **Pause et reprise** : Enregistrez les requêtes en attente et les URL visitées avec `crawldir`. Appuyez sur Ctrl+C pour arrêter proprement, puis relancez avec le même dossier.
- 📡 **Résultats en streaming** : Recevez les éléments dès leur extraction avec `async for item in spider.stream()`, avec des statistiques en temps réel. Utile pour les interfaces, les traitements de données et les explorations longues.
- 🛡️ **Détection des requêtes bloquées** : Détectez et relancez les requêtes bloquées automatiquement. Vous pouvez adapter ce comportement.
- 🚦 **AutoThrottle** : Le spider ajuste le délai de chaque domaine selon la vitesse de réponse du site. Si le site bloque ou limite les requêtes, il double le délai ou respecte la durée indiquée par `Retry-After`. Il accélère à nouveau quand la limitation prend fin.
- 🤖 **Respect de robots.txt** : Activez `robots_txt_obey` pour respecter les directives `Disallow`, `Crawl-delay` et `Request-rate`, avec un cache par domaine.
- 🧪 **Mode développement** : Enregistrez les réponses sur disque lors de la première exécution et réutilisez-les ensuite. Vous pouvez ainsi ajuster `parse()` sans envoyer de nouvelles requêtes aux serveurs.
- 🧩 **Modèles de spider prêts à l’emploi** : Utilisez `CrawlSpider` pour suivre les liens selon des règles, `SitemapSpider` pour explorer à partir de sitemaps ou de robots.txt, `XMLFeedSpider` et `CSVFeedSpider` pour lire des flux XML, RSS et CSV, et `ShopifySpider` pour collecter les produits des boutiques Shopify publiques, avec un élément par variante.
- 🔗 **Extraction de liens** : `LinkExtractor` permet d’accepter ou de refuser des liens selon des motifs, de filtrer les domaines et les extensions, de limiter la recherche avec CSS ou XPath et de normaliser les URL. Utilisez-le avec les modèles ou seul.
- 📦 **Export intégré** : Exportez les résultats avec des hooks et votre propre traitement de données, ou utilisez les formats JSON, JSONL, CSV et XML intégrés : `result.items.to_json()`, `to_jsonl()`, `to_csv()` et `to_xml()`.

### Récupération de pages avec des sessions

- **Requêtes HTTP** : Envoyez des requêtes HTTP rapides et furtives avec `Fetcher`. Vous pouvez imiter l’empreinte TLS et les en-têtes d’un navigateur, et utiliser HTTP/3.
- **Chargement dynamique** : Récupérez les sites dynamiques avec une automatisation complète du navigateur grâce à `StealthyFetcher`, compatible avec le Chromium de Playwright et Google Chrome.
- **Contournement des systèmes antibot** : `StealthyFetcher` masque l’automatisation et imite les empreintes du navigateur. Il peut franchir automatiquement les différents types de Cloudflare Turnstile et Interstitial.
- **Gestion des sessions** : `FetcherSession` et `StealthySession` conservent les cookies et l’état entre les requêtes.
- **Rotation des proxies** : `ProxyRotator` permet une rotation cyclique ou personnalisée dans tous les types de sessions. Vous pouvez aussi choisir un proxy pour une requête précise.
- **Blocage des domaines et des publicités** : Bloquez les requêtes vers certains domaines et leurs sous-domaines, ou activez le blocage des publicités des fetchers de navigateur. Il couvre environ 3 500 domaines connus de publicité et de suivi.
- **Prévention des fuites DNS** : Activez DNS-over-HTTPS pour envoyer les requêtes DNS par le service DoH de Cloudflare et éviter les fuites lorsque vous utilisez des proxies.
- **Navigateurs distants** : Connectez-vous par CDP à un navigateur déjà ouvert avec `cdp_url`, sur votre ordinateur, un autre serveur ou un service de navigateurs. Vous pouvez aussi utiliser votre propre version de Chromium avec tout fetcher de navigateur grâce à `executable_path`.
- **Capture des API en arrière-plan** : Activez `record_requests=True` dans une session de navigateur et cherchez les réponses enregistrées avec `session.network.search(limit=None)`. Lisez les données des API et les erreurs HTTP de plusieurs chargements sans répéter les requêtes. L’historique a une taille limitée et conserve le contenu des réponses textuelles.
- **Mode asynchrone** : Tous les fetchers peuvent fonctionner en mode asynchrone, avec des classes de session propres à ce mode.

### Analyse de pages et extraction de données

- 🔄 **Suivi des éléments** : Retrouvez les éléments après un changement du site grâce à des algorithmes de similarité.
- 🎯 **Sélection souple** : Utilisez CSS, XPath, les filtres, le texte, les expressions régulières et plus encore.
- 🔍 **Éléments similaires** : Trouvez automatiquement des éléments proches de ceux que vous avez déjà trouvés.

### Fonctions pour l’IA

- 🤖 **Serveur MCP** : Permet aux assistants et agents IA, comme Claude et Cursor, d’extraire des données avec Scrapling par des requêtes HTTP, des actions du navigateur, des captures d’écran, un état de connexion enregistré et des réponses d’API en arrière-plan. Il utilise notre navigateur furtif et des outils qui aident les modèles adaptés à résoudre les CAPTCHA, en plus du solveur Cloudflare. Il réduit le contenu envoyé au modèle, bloque les publicités et protège contre les injections de prompts. Il permet aussi d’utiliser des navigateurs distants par CDP et des connexions HTTP avec des options d’authentification. ([Vidéo de démonstration](https://www.youtube.com/watch?v=qyFk3ZNwOxE))
- 🧠 **Agent Skill** : Une [Agent Skill](https://scrapling.readthedocs.io/fr/latest/ai/agent-skill.html) prête à installer qui enseigne la bibliothèque aux agents de programmation pour qu’ils écrivent du code conforme à l’API actuelle.
- 📚 **Markdown prêt pour le RAG** : Convertissez une page en Markdown propre et adapté aux modèles de langage avec une ligne (`page.markdown()`), ou enregistrez un site entier en fichiers Markdown avec le modèle `ContentSpider`. Le processus ne demande aucun modèle de langage. ([Documentation](https://scrapling.readthedocs.io/fr/latest/ai/building-rag-systems.html))

### Performances et usage réel

- 🚀 **Grande vitesse** : Des performances optimisées qui dépassent la plupart des bibliothèques de web scraping pour Python.
- 🔋 **Faible usage de la mémoire** : Des structures de données optimisées et un chargement à la demande.
- ⚡ **Conversion rapide en JSON** : 10 fois plus rapide que la bibliothèque standard.
- 🏗️ **Testé en pratique** : Les tests couvrent 92 % de Scrapling et tout le code a des annotations de type. Des centaines de personnes l’ont utilisé chaque jour pour extraire des données pendant l’année passée.

### Outils pour développer et extraire des données

- 🎯 **Shell interactif** : Un shell IPython en option, intégré à Scrapling, avec des raccourcis et des outils pour créer des scripts plus vite. Convertissez les requêtes curl en requêtes Scrapling et consultez les résultats dans votre navigateur.
- 🚀 **Usage depuis le terminal** : Extrayez les données d’une URL sans écrire de code.
- 🛠️ **Navigation dans le DOM** : Accédez aux éléments parents, frères et enfants.
- 🧬 **Traitement du texte** : Expressions régulières, nettoyage du texte et opérations optimisées sur les chaînes.
- 📝 **Création de sélecteurs** : Générez des sélecteurs CSS et XPath fiables pour tout élément.
- 🔌 **API familière** : Proche de Scrapy et BeautifulSoup, avec les mêmes pseudo-éléments que Scrapy et Parsel.
- 🤝 **Intégration directe avec Scrapy** : Ajoutez le décorateur `scrapling_response` à un callback pour analyser les réponses que vous récupérez déjà avec le parser de Scrapling, sans réécrire votre programme.
- 📘 **Annotations de type complètes** : Elles aident l’éditeur à vérifier et à compléter le code. Tout le code est vérifié automatiquement par **PyRight** et **MyPy** à chaque changement.
- 🔋 **Image Docker prête à l’emploi** : Une image Docker avec tous les navigateurs est créée et publiée automatiquement à chaque version.

## Pour commencer

Voici quelques exemples de ce que vous pouvez faire avec Scrapling.

### Utilisation de base
Requêtes HTTP avec des sessions
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # Utiliser la dernière version de l'empreinte TLS de Chrome
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# Ou utiliser des requêtes ponctuelles
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
Mode furtif avancé
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # Garder le navigateur ouvert jusqu'à ce que vous ayez terminé
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# Ou utiliser le style requête ponctuelle : ouvre le navigateur pour cette requête, puis le ferme après
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
Automatisation complète du navigateur
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # Garder le navigateur ouvert jusqu'à ce que vous ayez terminé
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # Sélecteur XPath si vous le préférez

# Ou utiliser le style requête ponctuelle : ouvre le navigateur pour cette requête, puis le ferme après
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### Spiders
Créez des crawlers complets avec des requêtes simultanées, plusieurs types de sessions, la pause et la reprise :
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"{len(result.items)} citations scrapées")
result.items.to_json("quotes.json")
```
Utilisez plusieurs types de sessions dans un seul spider :
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]

    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)

    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # Router les pages protégées via la session furtive
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # Callback explicite
```
Enregistrez la progression pour mettre en pause et reprendre les explorations longues. Lancez le spider ainsi :
```python
QuotesSpider(crawldir="./crawl_data").start()
```
Avec `crawldir`, Ctrl+C enregistre les requêtes en attente et les URL visitées. Relancez avec le même `crawldir` pour reprendre. Enregistrez les données extraites séparément.

Vous pouvez aussi utiliser un modèle prêt à l’emploi. Par exemple, récupérez tout le catalogue d’une boutique Shopify :
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # Tous les produits de la boutique, un élément par variante
```
Le modèle lit les produits disponibles sur les endpoints publics des collections, avec un élément par variante.

### Analyse avancée et navigation
```python
from scrapling.fetchers import Fetcher

# Sélection riche d'éléments et navigation
page = Fetcher.get('https://quotes.toscrape.com/')

# Obtenir des citations avec plusieurs méthodes de sélection
quotes = page.css('.quote')  # Sélecteur CSS
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # Style BeautifulSoup
# Identique à
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # et ainsi de suite...
# Trouver un élément par contenu textuel
quotes = page.find_by_text('Albert Einstein', first_match=False)

# Navigation avancée
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # Sélecteurs chaînés
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# Relations et similarité entre éléments
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
Vous pouvez utiliser le parser directement, sans récupérer de page web :
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
Il fonctionne de la même façon.

### Exemples de sessions asynchrones
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # `FetcherSession` s'adapte au contexte et fonctionne en mode sync comme async
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## CLI et shell interactif

Vous pouvez aussi utiliser Scrapling depuis le terminal :

[](https://asciinema.org/a/736339)

Lancez le shell interactif de web scraping :
```bash
pip install "scrapling[shell]"
scrapling shell
```
Extrayez des pages directement dans un fichier sans programmation. Utilisez `--css-selector` pour choisir le contenu ou `--ai-targeted` pour sélectionner et nettoyer le contenu de `body`. Utilisez `.txt` pour du texte, `.md` pour du Markdown ou `.html` pour du HTML.
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> Consultez les autres fonctions, dont le serveur MCP et le shell interactif, dans la [documentation complète](https://scrapling.readthedocs.io/fr/latest/).

## Tests de performance

Scrapling se distingue aussi par sa vitesse. Ces tests comparent son parser aux dernières versions d’autres bibliothèques connues.

### Vitesse d’extraction du texte (5 000 éléments imbriqués)

| # |   Bibliothèque    | Temps (ms) | Par rapport à Scrapling |
|---|:-----------------:|:----------:|:------------:|
| 1 |     Scrapling     |    1,99    |     1,0x     |
| 2 |   Parsel/Scrapy   |    2,06    |     1,035    |
| 3 |     Lxml seul      |    2,56    |    1,286     |
| 4 |      PyQuery      |   23,98    |     ~12x     |
| 5 |    Selectolax     |   197,02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545,15   |   ~776,5x    |
| 7 |   BS4 avec Lxml   |  1562,1   |   ~785,0x    |
| 8 | BS4 avec html5lib |  3412,73   |   ~1714,9x   |


### Recherche d’éléments similaires et de texte

La recherche adaptative d’éléments de Scrapling est plus rapide que les autres solutions :

| Bibliothèque | Temps (ms) | Par rapport à Scrapling |
|--------------|:----------:|:------------:|
| Scrapling    |    2,3    |     1,0x     |
| AutoScraper  |   12,58    |    5,47x    |


> Chaque résultat est la moyenne d’au moins 100 exécutions. Consultez [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py) pour connaître la méthode.

## Installation

Scrapling demande Python 3.10 ou une version plus récente :

```bash
pip install scrapling
```

> [!IMPORTANT]
> Cette commande installe seulement le parser et ses dépendances, sans fetchers ni outils en ligne de commande. Avec cette seule installation, importer depuis `scrapling.fetchers` ou `scrapling.spiders`, comme dans les exemples précédents, provoque `ModuleNotFoundError`. Pour utiliser les fetchers ou les spiders, installez d’abord les dépendances des fetchers comme indiqué ci-dessous.

### Dépendances facultatives

1. Pour utiliser les fetchers, leurs classes ou les fonctions supplémentaires suivantes, installez les dépendances des fetchers et des navigateurs :
    ```bash
    pip install "scrapling[fetchers]"

    scrapling install           # installation normale
    scrapling install  --force  # réinstallation forcée
    ```

    Cette commande télécharge tous les navigateurs, leurs dépendances système et les outils de modification des empreintes du navigateur.

    Vous pouvez aussi les installer depuis Python, au lieu de lancer une commande :
    ```python
    from scrapling.cli import install

    install([], standalone_mode=False)          # installation normale
    install(["--force"], standalone_mode=False) # réinstallation forcée
    ```

2. Fonctions supplémentaires :
   - Installer le serveur MCP :
       ```bash
       pip install "scrapling[ai]"
       ```
   - Installer les dépendances pour [créer des systèmes RAG](https://scrapling.readthedocs.io/fr/latest/ai/building-rag-systems.html) :
       ```bash
       pip install "scrapling[rag]"
       ```
   - Installer le shell interactif et la commande `extract` :
       ```bash
       pip install "scrapling[shell]"
       ```
   - Tout installer :
       ```bash
       pip install "scrapling[all]"
       ```
   Lancez `scrapling install` pour utiliser les fetchers de navigateur. Les requêtes HTTP ne demandent pas de navigateur.

### Docker
Vous pouvez aussi télécharger depuis DockerHub une image Docker avec tous les extras et navigateurs :
```bash
docker pull pyd4vinci/scrapling
```
Ou la télécharger depuis le registre GitHub :
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
L’image est créée à partir de la branche principale du dépôt et publiée automatiquement par GitHub Actions.

## Contribuer

Les contributions sont les bienvenues ! Lisez nos [consignes de contribution](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md) avant de commencer.

## Avertissement

> [!CAUTION]
> Cette bibliothèque est destinée à l’enseignement et à la recherche. En l’utilisant, vous acceptez de respecter les lois locales et internationales sur l’extraction de données et la vie privée. Les auteurs et contributeurs ne sont pas responsables d’un usage abusif de ce logiciel. Respectez les conditions d’utilisation des sites et les fichiers robots.txt.

## 🎓 Citations
Si vous avez utilisé cette bibliothèque dans vos recherches, citez-la avec cette référence :
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## Licence

Ce projet utilise la licence BSD-3-Clause.

## Remerciements

Ce projet inclut du code adapté de :
- Parsel (Licence BSD) - Utilisé pour le sous-module [translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py)

---
<div align="center"><small>Conçu et développé avec ❤️ par Karim Shoair.</small></div><br>

---

### README JP (`docs/README_JP.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io/ja/latest/">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Scrapling のカバー画像" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>現代のウェブを手軽にスクレイピング</small>
</h1>

<p align="center">
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="テスト">
        <img alt="テスト" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="PyPI のバージョン">
        <img alt="PyPI のバージョン" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Docker のダウンロード数" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="PyPI パッケージのダウンロード数"></a>
    <a href="https://scrapling.readthedocs.io/ja/latest/ai/agent-skill.html" alt="AI エージェント向け Skill">
        <img alt="Agent Skill のバッジ" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Fja%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="OpenClaw 向け Skill">
        <img alt="OpenClaw 向け Skill" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X（旧 Twitter）">
      <img alt="X（旧 Twitter）でフォロー" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="対応する Python バージョン">
        <img alt="対応する Python バージョン" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/ja/latest/parsing/selection.html"><strong>選択メソッド</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ja/latest/fetching/choosing.html"><strong>Fetcher の選び方</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ja/latest/spiders/architecture.html"><strong>Spider</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ja/latest/spiders/proxy-blocking.html"><strong>プロキシの切り替え</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ja/latest/cli/overview.html"><strong>CLI</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ja/latest/ai/mcp-server.html"><strong>MCP サーバー</strong></a>
</p>

Scrapling は Python のウェブスクレイピングフレームワークです。高速な HTTP リクエスト、ステルスブラウザ、ページの解析、並行クロールをひとつのライブラリで扱えます。

静的なページの取得、JavaScript の実行、サイトの操作、背後にある API からのデータ抽出ができます。セッションの再利用、プロキシの切り替え、自動再試行、一時停止と再開、データの出力に対応したクローラーを作れます。

Python やターミナルから使うほか、MCP サーバーと Agent Skill を通じて AI エージェントからも使えます。少数の項目を取り出す作業から、サイト全体を整理された Markdown ファイルとして保存する作業まで対応します。

## Scrapling でできること

- **[ページの取得と操作](https://scrapling.readthedocs.io/ja/latest/fetching/choosing.html)**：高速な HTTP リクエスト、ステルスブラウザ、JavaScript の実行、Cloudflare Turnstile と Interstitial への対応、永続セッション、バックグラウンド API レスポンスの記録。
- **[解析とデータ抽出](https://scrapling.readthedocs.io/ja/latest/parsing/selection.html)**：CSS、XPath、テキスト、正規表現による検索、ページ変更後の要素の追跡、類似要素の検索、整理された Markdown の出力。
- **[クロールと出力](https://scrapling.readthedocs.io/ja/latest/spiders/getting-started.html)**：並行クロール、プロキシの切り替え、再試行、AutoThrottle、一時停止と再開、ストリーミング、すぐに使えるテンプレート、JSON・JSONL・CSV・XML への出力。
- **[AI やターミナルからの利用](https://scrapling.readthedocs.io/ja/latest/ai/mcp-server.html)**：AI エージェントがページを操作してデータを抽出するための MCP サーバー、Agent Skill、CLI コマンド、対話型シェル。

まずはひとつのページから始めます。

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

Spider を使えば、より多くのページを取得できます。

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

このコードは `10` を表示し、名言と作者を `quotes.json` に保存します。

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# プラチナスポンサー
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> は、ウェブスクレイピングと自動化向けの最も効率的なプロキシサービスです。市場最高品質の IP を提供します。コード SCRAPLING35 で 35% 割引になります。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling は Cloudflare Turnstile に対応します。企業向けの高度な保護には、<a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a>が<b>Akamai</b>、<b>DataDome</b>、<b>Kasada</b>、<b>Incapsula</b>向けの有効なボット対策用トークンを生成する API を提供します。簡単な API 呼び出しだけで使え、ブラウザの自動操作は不要です。 </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a>：レジデンシャルプロキシが $0.49/GB から。フィンガープリントを全面的に偽装した Chromium のスクレイピングブラウザを提供します。レジデンシャル IP、CAPTCHA の自動解決、ボット対策の回避に対応します。</br>
      <b>Scraper API で手間なく結果を取得できます。MCP と N8N との連携にも対応します。</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">The Web Scraping Club で Scrapling の詳細レビュー</a>（2025年11月）をお読みください。Web スクレイピング専門の No.1 ニュースレターです。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a> は 195 か国以上、8,000 万以上の IP を備え、利用規模に合わせて使えるレジデンシャルプロキシを提供します。高速で信頼性の高い接続、自動のプロキシ切り替え、強力なブロック回避機能が特長です。無料で試せます。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a> は、倫理的に調達されたレジデンシャル、モバイル、ISP、データセンタープロキシに加え、スクレイピングと AI 自動化のツールを提供します。コード SCRAPLING10 でレジデンシャルプロキシが 10% オフになります。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a>：ブロックと CAPTCHA を 90% 削減します。大規模なウェブスクレイピング向けに、2,800 万の高品質なレジデンシャル IP を提供します。195 か国に対応し、都市・ISP・郵便番号（ZIP）を指定できます。同じ IP を保つセッションと、IP を切り替えるセッションを使えます。有効期限のない通信量を $2/GB から提供します。コード <strong>SCRAPEANDTAKE</strong> で<em>25% オフ</em>になります。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a>：GB 単位の課金は不要です。レジデンシャルプロキシの通信量は無制限です。1 億以上の IP、190 か国以上に対応します。料金は帯域幅に応じて決まります。50 Mbps のレジデンシャルプロキシの無料トライアルをお申し込みください。
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a> なら $1/GB です。倫理的に調達された自社提供のプロキシで、9,000 万以上の IP、195 か国以上に対応します。レジデンシャル、データセンター、モバイルのプロキシを使えます。従量課金なので、定期契約は不要です。通信量に有効期限はありません。
    </td>
  </tr>
</table>

<i><sub>ここに広告を掲載するには、[こちら](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)をご覧ください。</sub></i>
# スポンサー



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>ここに広告を掲載するには、[こちら](https://github.com/sponsors/D4Vinci)からプランを選んでください。</sub></i>

---

## 主な機能

### Spider：本格的なクロールフレームワーク

- 🕷️ **Scrapy に似た Spider API**：`start_urls`、非同期の `parse` コールバック、`Request` と `Response` オブジェクトで Spider を定義します。
- ⚡ **並行クロール**：同時に処理するリクエスト数、ドメインごとの制限、ダウンロードの待ち時間を設定できます。
- 🔄 **複数のセッション**：ひとつの Spider で HTTP リクエストとステルス対応のヘッドレスブラウザを使えます。セッション ID でリクエストの処理先を選びます。
- 💾 **一時停止と再開**：`crawldir` で待機中のリクエストと訪問済み URL を保存します。Ctrl+C で安全に停止し、同じディレクトリで起動すると続きから再開できます。
- 📡 **ストリーミング**：`async for item in spider.stream()` で、抽出したデータをすぐに受け取れます。統計もリアルタイムで確認できます。画面への表示、データ処理、長時間のクロールに適しています。
- 🛡️ **ブロックの検出**：ブロックされたリクエストを自動で検出し、再試行します。処理は変更できます。
- 🚦 **AutoThrottle**：サイトの応答速度に合わせて、ドメインごとの待ち時間を自動調整します。ブロックや頻度制限を受けたら待ち時間を 2 倍にするか、`Retry-After` が指定する時間を待ちます。問題が収まると再び速度を上げます。
- 🤖 **robots.txt の遵守**：`robots_txt_obey` を有効にすると、`Disallow`、`Crawl-delay`、`Request-rate` に従います。ルールはドメインごとにキャッシュします。
- 🧪 **開発モード**：初回のレスポンスをディスクに保存し、次回から再利用します。サーバーに再度アクセスせずに `parse()` を調整できます。
- 🧩 **すぐに使える Spider テンプレート**：`CrawlSpider` はルールに沿ってリンクをたどり、`SitemapSpider` は sitemap や robots.txt を起点にクロールします。`XMLFeedSpider` と `CSVFeedSpider` は XML・RSS・CSV フィードを読み取ります。`ShopifySpider` は公開 Shopify ストアの商品を取得し、バリエーションごとに 1 件のデータを出力します。
- 🔗 **リンク抽出**：`LinkExtractor` はパターンによる許可と除外、ドメインや拡張子の絞り込み、CSS と XPath による範囲指定、URL の正規化に対応します。テンプレート内でも単体でも使えます。
- 📦 **データの出力**：フックと独自の処理を使うか、組み込みの JSON・JSONL・CSV・XML 出力を使えます。`result.items.to_json()`、`to_jsonl()`、`to_csv()`、`to_xml()` を呼び出します。

### セッションを使ったページの取得

- **HTTP リクエスト**：`Fetcher` で高速かつ検出されにくい HTTP リクエストを送れます。ブラウザの TLS フィンガープリントとヘッダーの模倣や、HTTP/3 に対応します。
- **動的なページの読み込み**：`StealthyFetcher` のブラウザ自動化で動的なサイトを取得できます。Playwright の Chromium と Google Chrome に対応します。
- **ボット検出の回避**：`StealthyFetcher` は自動化の痕跡を隠し、フィンガープリントを偽装します。Cloudflare Turnstile や Interstitial の各種検証を自動処理できます。
- **セッション管理**：`FetcherSession` と `StealthySession` は、リクエスト間で Cookie と状態を保持します。
- **プロキシの切り替え**：`ProxyRotator` は、すべてのセッションで順番に、または独自のルールでプロキシを切り替えます。リクエストごとにプロキシを指定することもできます。
- **ドメインと広告のブロック**：指定したドメインとそのサブドメインへのリクエストを止められます。ブラウザ Fetcher には広告ブロック機能もあり、約 3,500 の広告・追跡用ドメインに対応します。
- **DNS リークの防止**：DNS-over-HTTPS を有効にすると、Cloudflare の DoH を通じて DNS を問い合わせます。プロキシ使用時の DNS リークを防ぎます。
- **リモートブラウザ**：CDP と `cdp_url` を使い、すでに動いているブラウザに接続できます。同じパソコン、別のサーバー、ブラウザ提供サービスのいずれでも使えます。`executable_path` で、各ブラウザ Fetcher に独自の Chromium を指定することもできます。
- **バックグラウンド API レスポンスの記録**：ブラウザセッションで `record_requests=True` を有効にし、`session.network.search(limit=None)` で保存済みレスポンスを検索します。リクエストを送り直さずに、複数のページ読み込みで発生した API データや HTTP エラーを確認できます。履歴には上限があり、テキストのレスポンス本文を保存します。
- **非同期対応**：すべての Fetcher で非同期処理を使えます。専用の非同期セッションもあります。

### 解析とデータ抽出

- 🔄 **要素の再検索**：サイトが変わった後も、類似度を使って要素を見つけ直します。
- 🎯 **柔軟な選択**：CSS、XPath、フィルター、テキスト、正規表現などを使えます。
- 🔍 **類似要素の検索**：見つけた要素に似た要素を自動で探します。

### AI 機能

- 🤖 **MCP サーバー**：Claude や Cursor などの AI アシスタントとエージェントが Scrapling を使ってデータを抽出できます。HTTP リクエスト、ブラウザ操作、スクリーンショット、保存済みログイン状態、バックグラウンド API レスポンスに対応します。ステルスブラウザとツールを使い、対応する能力を持つモデルが CAPTCHA を処理できるようにします。Cloudflare 検証の処理機能もあります。モデルへ送る内容を減らし、広告をブロックし、プロンプトインジェクションから保護します。CDP によるリモートブラウザ接続や、認証付きの HTTP 接続にも対応します。（[デモ動画](https://www.youtube.com/watch?v=qyFk3ZNwOxE)）
- 🧠 **Agent Skill**：インストールして使える [Agent Skill](https://scrapling.readthedocs.io/ja/latest/ai/agent-skill.html) が、コーディングエージェントにライブラリの使い方を伝えます。現在の API に合ったコードを書く助けになります。
- 📚 **RAG 向けの Markdown**：1 行のコード（`page.markdown()`）で、ページを整理・クリーニングした LLM 向けの Markdown に変換します。`ContentSpider` テンプレートを使えば、サイト全体を Markdown ファイルに保存できます。この処理に LLM は不要です。（[ドキュメント](https://scrapling.readthedocs.io/ja/latest/ai/building-rag-systems.html)）

### 高速で、実際の作業にも使われています

- 🚀 **高速な処理**：最適化により、多くの Python スクレイピングライブラリを上回る速度を実現しています。
- 🔋 **少ないメモリ使用量**：最適化したデータ構造と、必要なときだけ読み込む仕組みを使っています。
- ⚡ **高速な JSON 出力**：標準ライブラリの 10 倍の速度です。
- 🏗️ **実際の作業で検証済み**：テストカバレッジは 92% で、すべてのコードに型ヒントがあります。この 1 年間、数百人が毎日のデータ抽出に使ってきました。

### 開発とデータ抽出のためのツール

- 🎯 **対話型シェル**：Scrapling と連携した IPython シェルを追加できます。ショートカットやツールでスクリプトの開発を助けます。curl リクエストを Scrapling のリクエストに変換し、結果をブラウザで確認できます。
- 🚀 **ターミナルからの利用**：コードを書かずに URL の内容を取得できます。
- 🛠️ **DOM の移動**：親要素、兄弟要素、子要素をたどれます。
- 🧬 **テキスト処理**：正規表現、テキストのクリーニング、最適化した文字列操作を使えます。
- 📝 **セレクターの生成**：任意の要素に対する CSS と XPath のセレクターを生成します。
- 🔌 **使い慣れた API**：Scrapy や BeautifulSoup に似た API で、Scrapy と Parsel と同じ疑似要素を使えます。
- 🤝 **Scrapy との連携**：コールバックに `scrapling_response` デコレーターを付けると、取得済みのレスポンスを Scrapling のパーサーで解析できます。プログラムを書き直す必要はありません。
- 📘 **すべてのコードに型ヒント**：エディターでの確認とコード補完を助けます。変更のたびに、すべてのコードを **PyRight** と **MyPy** で自動チェックします。
- 🔋 **すぐに使える Docker イメージ**：リリースごとに、すべてのブラウザを含む Docker イメージを自動で作成・公開します。

## はじめに

よく使う機能をいくつか紹介します。

### 基本的な使い方
セッションを使った HTTP リクエスト
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # Chrome の TLS fingerprint の最新バージョンを使用
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# または一回限りのリクエストを使用
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
高度なステルスモード
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # 完了するまでブラウザを開いたままにする
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# または一回限りのリクエストスタイル、このリクエストのためにブラウザを開き、完了後に閉じる
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
完全なブラウザ自動化
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # 完了するまでブラウザを開いたままにする
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # お好みであれば XPath セレクタを使用

# または一回限りのリクエストスタイル、このリクエストのためにブラウザを開き、完了後に閉じる
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### Spider
並行リクエスト、複数のセッション、一時停止と再開に対応したクローラーを作れます。
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"{len(result.items)}件の引用をスクレイプしました")
result.items.to_json("quotes.json")
```
ひとつの Spider で、複数の種類のセッションを使えます。
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]

    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)

    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # 保護されたページはステルス Session を通してルーティング
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # 明示的な callback
```
進捗を保存すれば、長時間のクロールを一時停止して再開できます。次のように Spider を起動します。
```python
QuotesSpider(crawldir="./crawl_data").start()
```
`crawldir` を設定して Ctrl+C を押すと、保留中のリクエストと訪問済み URL が保存されます。同じ `crawldir` で再起動すると再開できます。抽出データは別途保存してください。

すぐに使えるテンプレートもあります。たとえば、Shopify ストアの商品全体を取得できます。
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # ストア内の全商品を、バリエーションごとに 1 件取得
```
このテンプレートは公開されているコレクション API から商品を読み取り、バリエーションごとに 1 件のデータを出力します。

### さらに詳しい解析と要素の移動
```python
from scrapling.fetchers import Fetcher

# 豊富な要素選択とナビゲーション
page = Fetcher.get('https://quotes.toscrape.com/')

# 複数の選択メソッドで引用を取得
quotes = page.css('.quote')  # CSS セレクタ
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # BeautifulSoup スタイル
# 以下と同じ
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # など...
# テキスト内容で要素を検索
quotes = page.find_by_text('Albert Einstein', first_match=False)

# 高度なナビゲーション
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # チェーンセレクタ
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# 要素の関連性と類似性
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
ページを取得せずに、パーサーを直接使うこともできます。
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
使い方は同じです。

### 非同期セッションの例
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # `FetcherSession` はコンテキストに応じて同期・非同期の両方で動作します
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## CLI と対話型シェル

ターミナルからも Scrapling を使えます。

[](https://asciinema.org/a/736339)

スクレイピング用の対話型シェルを起動します。
```bash
pip install "scrapling[shell]"
scrapling shell
```
プログラミングなしでページをファイルに抽出できます。`--css-selector` で内容を選ぶか、`--ai-targeted` で `body` の内容を選択・クリーニングします。テキストは `.txt`、Markdown は `.md`、HTML は `.html` を使います。
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> MCP サーバーや対話型シェルなど、ほかの機能は[ドキュメント](https://scrapling.readthedocs.io/ja/latest/)をご覧ください。

## 性能テスト

Scrapling は処理速度も重視しています。以下では、そのパーサーと他のよく使われるライブラリの最新バージョンを比較します。

### テキスト抽出の速度（5,000 個の入れ子の要素）

| # |      ライブラリ      | 時間（ミリ秒） | Scrapling との比較 |
|---|:-----------------:|:---------:|:------------:|
| 1 |     Scrapling     |   1.99    |     1.0x     |
| 2 |   Parsel/Scrapy   |   2.06    |    1.035     |
| 3 |     Lxml 単体      |   2.56    |    1.286     |
| 4 |      PyQuery      |   23.98   |     ~12x     |
| 5 |    Selectolax     |  197.02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545.15  |   ~776.5x    |
| 7 |   BS4 + Lxml   |  1562.1   |   ~785.0x    |
| 8 | BS4 + html5lib |  3412.73  |   ~1714.9x   |


### 類似要素とテキストの検索

Scrapling の適応型の要素検索は、他の方法より高速です。

| ライブラリ     | 時間（ミリ秒） | Scrapling との比較 |
|-------------|:---------:|:------------:|
| Scrapling   |    2.3    |     1.0x     |
| AutoScraper |   12.58   |    5.47x     |


> 各結果は、100 回以上の実行の平均です。測定方法は [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py) をご覧ください。

## インストール

Scrapling には Python 3.10 以上が必要です。

```bash
pip install scrapling
```

> [!IMPORTANT]
> このコマンドはパーサーとその依存パッケージだけをインストールします。Fetcher やコマンドラインツールは含まれません。この状態で上の例のように `scrapling.fetchers` や `scrapling.spiders` からインポートすると、`ModuleNotFoundError` が発生します。Fetcher や Spider を使う場合は、先に以下の手順で Fetcher の依存パッケージをインストールしてください。

### 追加の依存パッケージ

1. Fetcher、関連するクラス、以下の追加機能を使う場合は、Fetcher とブラウザに必要なパッケージをインストールします。
    ```bash
    pip install "scrapling[fetchers]"

    scrapling install           # normal install
    scrapling install  --force  # force reinstall
    ```

    すべてのブラウザ、必要なシステムパッケージ、フィンガープリントを変更するツールがダウンロードされます。

    コマンドの代わりに、Python のコードからインストールすることもできます。
    ```python
    from scrapling.cli import install

    install([], standalone_mode=False)          # normal install
    install(["--force"], standalone_mode=False) # force reinstall
    ```

2. 追加機能：
   - MCP サーバーをインストール：
       ```bash
       pip install "scrapling[ai]"
       ```
   - [RAG システムの構築](https://scrapling.readthedocs.io/ja/latest/ai/building-rag-systems.html)に必要なパッケージをインストール：
       ```bash
       pip install "scrapling[rag]"
       ```
   - 対話型シェルと `extract` コマンドをインストール：
       ```bash
       pip install "scrapling[shell]"
       ```
   - すべての機能をインストール：
       ```bash
       pip install "scrapling[all]"
       ```
   ブラウザ Fetcher を使う場合は `scrapling install` を実行してください。HTTP リクエストにはブラウザのインストールは不要です。

### Docker
すべての追加機能とブラウザを含む Docker イメージを DockerHub から取得することもできます。
```bash
docker pull pyd4vinci/scrapling
```
GitHub のレジストリからも取得できます。
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
このイメージはリポジトリのメインブランチを使い、GitHub Actions で自動作成・公開されます。

## 開発への参加

開発への参加を歓迎します。始める前に[参加ガイド](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md)をお読みください。

## 免責事項

> [!CAUTION]
> このライブラリは学習と研究のために提供しています。利用する場合は、地域および国際的なデータ取得とプライバシーの法律に従うことに同意したものとします。作者と開発への参加者は、ソフトウェアの悪用に責任を負いません。サイトの利用規約と robots.txt に従ってください。

## 🎓 引用
研究でこのライブラリを使った場合は、次の形式で引用してください。
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## ライセンス

本プロジェクトは BSD-3-Clause ライセンスで公開しています。

## 謝辞

本プロジェクトには、次のプロジェクトをもとにしたコードが含まれます。
- Parsel（BSD ライセンス）：[translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py) サブモジュールで使用

---
<div align="center"><small>Karim Shoair が❤️を込めてデザイン・制作しました。</small></div><br>

---

### README KR (`docs/README_KR.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io/ko/latest/">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Scrapling 표지" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>현대적인 웹을 간편하게 스크래핑하세요</small>
</h1>

<p align="center">
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="테스트">
        <img alt="테스트" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="PyPI 버전">
        <img alt="PyPI 버전" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Docker 다운로드 수" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="PyPI 패키지 다운로드 수"></a>
    <a href="https://scrapling.readthedocs.io/ko/latest/ai/agent-skill.html" alt="AI 에이전트용 Skill">
        <img alt="Agent Skill 배지" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Fko%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="OpenClaw용 Skill">
        <img alt="OpenClaw용 Skill" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X(구 Twitter)">
      <img alt="X(구 Twitter) 팔로우" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="지원하는 Python 버전">
        <img alt="지원하는 Python 버전" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/ko/latest/parsing/selection.html"><strong>요소 찾기</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ko/latest/fetching/choosing.html"><strong>Fetcher 선택 가이드</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ko/latest/spiders/architecture.html"><strong>Spider</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ko/latest/spiders/proxy-blocking.html"><strong>프록시 교체</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ko/latest/cli/overview.html"><strong>CLI</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ko/latest/ai/mcp-server.html"><strong>MCP 서버</strong></a>
</p>

Scrapling은 빠른 HTTP 요청, 스텔스 브라우저, 강력한 파싱, 동시 크롤링을 하나로 묶은 Python 웹 스크래핑 프레임워크입니다.

정적 페이지를 가져오고, JavaScript를 실행하고, 사이트를 조작하고, 사이트가 호출하는 API에서 데이터를 추출하세요. 세션 재사용, 프록시 교체, 자동 재시도, 일시 정지와 재개, 데이터 내보내기를 지원하는 크롤러를 만들 수 있습니다.

Python이나 터미널에서 사용할 수 있으며, MCP 서버와 Agent Skill을 통해 AI 에이전트에서도 사용할 수 있습니다. 몇 개의 필드를 추출하는 작업부터 사이트 전체를 깔끔한 Markdown 파일로 저장하는 작업까지 지원합니다.

## Scrapling으로 할 수 있는 일

- **[페이지 가져오기와 조작](https://scrapling.readthedocs.io/ko/latest/fetching/choosing.html)**: 빠른 HTTP 요청, 스텔스 브라우저, JavaScript 실행, Cloudflare Turnstile과 Interstitial 처리, 지속 세션, 백그라운드 API 응답 기록.
- **[파싱과 데이터 추출](https://scrapling.readthedocs.io/ko/latest/parsing/selection.html)**: CSS, XPath, 텍스트와 정규식 검색, 페이지가 바뀐 뒤에도 요소 추적, 비슷한 요소 찾기, 깔끔한 Markdown 출력.
- **[크롤링과 내보내기](https://scrapling.readthedocs.io/ko/latest/spiders/getting-started.html)**: 동시 크롤링, 프록시 교체, 재시도, AutoThrottle, 일시 정지와 재개, 스트리밍, 바로 쓸 수 있는 템플릿, JSON·JSONL·CSV·XML 내보내기.
- **[AI나 터미널에서 스크래핑](https://scrapling.readthedocs.io/ko/latest/ai/mcp-server.html)**: AI 에이전트가 사이트를 탐색하고 데이터를 추출하는 MCP 서버, Agent Skill, CLI 명령어, 대화형 셸.

한 페이지부터 시작하세요:

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

스파이더로 여러 페이지를 수집할 수도 있습니다:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

이 코드는 `10`을 출력하고 명언과 저자를 `quotes.json`에 저장합니다.

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# 플래티넘 스폰서
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> - 웹 스크래핑과 자동화를 위한 가장 효율적인 프록시 제공업체로, 시장에서 가장 높은 품질의 IP를 제공합니다. 코드 SCRAPLING35를 사용하면 35% 할인을 받을 수 있습니다.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling은 Cloudflare Turnstile을 처리합니다. 기업용 보호 기능을 우회해야 한다면, <a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a>가 <b>Akamai</b>, <b>DataDome</b>, <b>Kasada</b>, <b>Incapsula</b>용 유효한 안티봇 토큰을 생성하는 API 엔드포인트를 제공합니다. 간단한 API 호출만으로 사용할 수 있으며 브라우저 자동화는 필요 없습니다. </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a>: 레지덴셜 프록시를 GB당 $0.49부터 제공합니다. 브라우저 지문을 완전히 위장한 Chromium 기반 스크래핑 브라우저, 레지덴셜 IP, 자동 CAPTCHA 처리, 봇 차단 우회를 지원합니다.</br>
      <b>Scraper API로 번거로움 없이 결과를 얻으세요. MCP 및 N8N 연동도 지원합니다.</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">The Web Scraping Club에서 Scrapling의 전체 리뷰</a>(2025년 11월)를 읽어보세요. 웹 스크래핑 전문 No.1 뉴스레터입니다.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a>는 195개국 이상에서 8천만 개 이상의 IP를 갖춘 확장 가능한 주거용 프록시를 제공하며, 빠르고 안정적인 연결, 자동 프록시 교체, 강력한 차단 방지 기능을 제공합니다. 무료로 체험할 수 있습니다.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a>은 윤리적으로 확보한 주거용, 모바일, ISP 및 데이터센터 프록시와 스크래핑 및 AI 자동화 도구를 제공합니다. 코드 SCRAPLING10을 사용하면 주거용 프록시를 10% 할인받을 수 있습니다.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a>: 차단과 CAPTCHA를 90% 줄입니다. 대규모 웹 스크래핑을 위한 2,800만 개의 프리미엄 주거용 IP를 제공합니다. 195개 국가를 지원하며 도시, ISP, 우편번호(ZIP)를 지정할 수 있습니다. IP를 유지하거나 바꾸는 세션을 사용할 수 있습니다. 유효 기간이 없는 트래픽을 $2/GB부터 제공합니다. 코드 <strong>SCRAPEANDTAKE</strong>를 사용하면 <em>25% 할인</em>을 받을 수 있습니다.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a>: GB당 요금을 내지 않아도 됩니다. 무제한 주거용 프록시 트래픽과 1억 개 이상의 IP를 제공하며 190개 이상의 국가를 지원합니다. 대역폭에 따라 요금을 지불하세요. 50 Mbps 주거용 프록시 무료 체험을 신청하세요.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a>에서 $1/GB로 이용하세요. 윤리적으로 확보한 자체 프록시를 제공합니다. 9,000만 개 이상의 IP와 195개 이상의 국가를 지원합니다. 주거용, 데이터센터, 모바일 프록시를 사용할 수 있습니다. 사용량에 따라 결제하므로 구독이 필요 없습니다. 트래픽에 유효 기간이 없습니다.
    </td>
  </tr>
</table>

<i><sub>여기에 광고를 게재하고 싶으신가요? [여기](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)를 클릭하세요</sub></i>
# 스폰서



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>여기에 광고를 게재하고 싶으신가요? [여기](https://github.com/sponsors/D4Vinci)를 클릭하고 원하는 요금제를 선택하세요!</sub></i>

---

## 주요 기능

### 스파이더: 본격적인 크롤링 프레임워크

- 🕷️ **Scrapy와 비슷한 Spider API**: `start_urls`, 비동기 `parse` 콜백, `Request`/`Response` 객체로 스파이더를 정의합니다.
- ⚡ **동시 크롤링**: 동시에 처리할 요청 수, 도메인별 제한, 다운로드 사이의 대기 시간을 설정합니다.
- 🔄 **여러 세션 지원**: 한 스파이더에서 HTTP 요청과 스텔스 헤드리스 브라우저를 같은 방식으로 사용합니다. 세션 ID로 각 요청을 보낼 세션을 고릅니다.
- 💾 **일시 정지와 재개**: `crawldir`로 대기 중인 요청과 방문한 URL을 저장합니다. Ctrl+C로 안전하게 멈춘 뒤 같은 폴더로 다시 시작하면 이어서 실행됩니다.
- 📡 **스트리밍**: `async for item in spider.stream()`으로 추출한 항목을 바로 받고 실시간 통계를 확인합니다. 화면 표시, 데이터 처리, 긴 크롤링 작업에 적합합니다.
- 🛡️ **차단 감지**: 차단된 요청을 자동으로 감지하고 재시도합니다. 처리 방식도 바꿀 수 있습니다.
- 🚦 **AutoThrottle**: 대기 시간을 직접 추측할 필요가 없습니다. 스파이더가 응답 속도에 맞춰 도메인별 대기 시간을 조절합니다. 차단이나 요청 빈도 제한이 시작되면 두 배로 늘리거나 `Retry-After`가 지정한 시간만큼 기다리고, 문제가 사라지면 다시 속도를 높입니다.
- 🤖 **robots.txt 준수**: `robots_txt_obey`를 켜면 `Disallow`, `Crawl-delay`, `Request-rate` 규칙을 따릅니다. 규칙은 도메인별로 캐시합니다.
- 🧪 **개발 모드**: 첫 실행에서 응답을 디스크에 저장하고 다음 실행부터 다시 사용합니다. 서버에 다시 요청하지 않고 `parse()`를 수정하며 시험할 수 있습니다.
- 🧩 **바로 쓰는 스파이더 템플릿**: `CrawlSpider`는 규칙에 따라 링크를 따라가고, `SitemapSpider`는 sitemap과 robots.txt를 사용합니다. `XMLFeedSpider`/`CSVFeedSpider`는 XML·RSS·CSV 피드를 읽습니다. `ShopifySpider`는 공개 Shopify 스토어에서 상품을 수집하며, 상품 옵션 조합마다 한 항목을 만듭니다.
- 🔗 **링크 추출**: `LinkExtractor`는 허용·제외 패턴, 도메인 필터, CSS·XPath 범위 지정, 확장자 필터, URL 정규화를 지원합니다. 템플릿 안에서 또는 단독으로 사용할 수 있습니다.
- 📦 **데이터 내보내기**: 훅과 자체 처리 과정으로 결과를 저장하거나 내장 JSON·JSONL·CSV·XML 기능을 사용하세요. `result.items.to_json()`, `to_jsonl()`, `to_csv()`, `to_xml()`을 호출하면 됩니다.

### 세션을 사용한 사이트 가져오기

- **HTTP 요청**: `Fetcher`로 빠르고 탐지하기 어려운 HTTP 요청을 보냅니다. 브라우저의 TLS 지문과 헤더를 흉내 내고 HTTP/3를 사용할 수 있습니다.
- **동적 페이지**: `StealthyFetcher`로 브라우저를 자동 조작하며 동적 사이트를 가져옵니다. Playwright의 Chromium과 Google Chrome을 지원합니다.
- **봇 차단 우회**: `StealthyFetcher`는 자동화 흔적을 숨기고 브라우저 지문을 위장합니다. 모든 유형의 Cloudflare Turnstile과 Interstitial 검사를 자동으로 통과할 수 있습니다.
- **세션 관리**: `FetcherSession`과 `StealthySession`은 요청 사이에 쿠키와 상태를 유지합니다.
- **프록시 교체**: `ProxyRotator`는 모든 세션에서 프록시를 순서대로 또는 정한 규칙에 따라 교체합니다. 요청마다 다른 프록시를 지정할 수도 있습니다.
- **도메인과 광고 차단**: 특정 도메인과 하위 도메인으로 보내는 요청을 막을 수 있습니다. 브라우저 Fetcher의 광고 차단 기능은 약 3,500개의 광고·추적 도메인을 차단합니다.
- **DNS 유출 방지**: DNS-over-HTTPS를 켜면 Cloudflare의 DoH를 통해 DNS를 조회합니다. 프록시를 쓸 때 DNS가 새어 나가는 것을 막습니다.
- **원격 브라우저**: `cdp_url`로 CDP를 통해 이미 실행 중인 브라우저에 연결합니다. 같은 컴퓨터, 다른 서버, 브라우저 제공 서비스 어디에서든 사용할 수 있습니다. `executable_path`로 직접 만든 Chromium을 브라우저 Fetcher에 지정할 수도 있습니다.
- **백그라운드 API 응답 기록**: 브라우저 세션에서 `record_requests=True`를 켜고 `session.network.search(limit=None)`으로 저장된 응답을 검색하세요. 요청을 다시 보내지 않고 여러 페이지에서 발생한 API 데이터와 HTTP 오류를 읽을 수 있습니다. 기록에는 크기 제한이 있으며 텍스트 응답 본문을 저장합니다.
- **비동기 지원**: 모든 Fetcher에서 비동기 호출을 지원하며, 전용 비동기 세션 클래스도 제공합니다.

### 파싱과 데이터 추출

- 🔄 **요소 추적**: 사이트가 바뀌어도 유사도 알고리즘으로 요소를 다시 찾습니다.
- 🎯 **유연한 선택**: CSS, XPath, 필터, 텍스트, 정규식 등 여러 방법을 사용할 수 있습니다.
- 🔍 **비슷한 요소 찾기**: 이미 찾은 요소와 비슷한 요소를 자동으로 찾습니다.

### AI 기능

- 🤖 **MCP 서버**: Claude나 Cursor 같은 AI 챗봇과 에이전트가 Scrapling으로 데이터를 수집합니다. HTTP 요청, 브라우저 조작, 스크린샷, 저장된 로그인 상태, 백그라운드 API 응답을 사용할 수 있습니다. 스텔스 브라우저와 도구를 통해 충분한 능력을 가진 AI 모델이 작업 중 마주치는 모든 CAPTCHA를 처리하도록 돕습니다. Cloudflare 처리 기능도 내장되어 있습니다. 모델에 보내는 내용을 줄이고 광고를 차단하며 프롬프트 인젝션으로부터 모델을 보호합니다. CDP 원격 브라우저와 인증을 지원하는 HTTP 연결도 제공합니다. ([데모 영상](https://www.youtube.com/watch?v=qyFk3ZNwOxE))
- 🧠 **Agent Skill**: 설치해서 쓰는 [Agent Skill](https://scrapling.readthedocs.io/ko/latest/ai/agent-skill.html)이 코딩 에이전트에 라이브러리 전체 사용법을 알려 줍니다. 에이전트가 추측 대신 현재 API에 맞는 코드를 작성하도록 돕습니다.
- 📚 **RAG용 Markdown**: 한 줄(`page.markdown()`)로 페이지를 정리하고 위험한 내용을 제거해 LLM용 Markdown으로 만듭니다. `ContentSpider` 템플릿으로 사이트 전체를 Markdown 파일로 저장할 수도 있습니다. 이 과정에는 LLM이 필요하지 않습니다. ([문서](https://scrapling.readthedocs.io/ko/latest/ai/building-rag-systems.html))

### 빠르고 실무에서 검증된 구조

- 🚀 **빠른 처리**: 최적화를 통해 대부분의 Python 스크래핑 라이브러리보다 빠르게 동작합니다.
- 🔋 **적은 메모리 사용**: 최적화한 자료 구조를 사용하고 필요한 시점에만 데이터를 불러옵니다.
- ⚡ **빠른 JSON 변환**: 표준 라이브러리보다 10배 빠릅니다.
- 🏗️ **실무 검증**: 테스트 커버리지 92%와 전체 코드의 타입 힌트를 갖췄습니다. 지난 1년 동안 수백 명이 매일 데이터를 수집하는 데 사용했습니다.

### 개발자를 위한 편리한 도구

- 🎯 **대화형 셸**: Scrapling을 통합한 IPython 셸을 추가할 수 있습니다. 단축 명령과 도구로 스크립트를 빠르게 개발하세요. curl 요청을 Scrapling 요청으로 바꾸고 결과를 브라우저에서 볼 수 있습니다.
- 🚀 **터미널에서 바로 사용**: 코드를 한 줄도 쓰지 않고 URL에서 데이터를 가져올 수 있습니다!
- 🛠️ **DOM 탐색**: 부모, 형제, 자식 요소로 이동하는 메서드를 제공합니다.
- 🧬 **텍스트 처리**: 정규식, 텍스트 정리, 빠른 문자열 연산을 사용할 수 있습니다.
- 📝 **선택자 생성**: 어떤 요소든 안정적인 CSS·XPath 선택자를 만들 수 있습니다.
- 🔌 **익숙한 API**: Scrapy와 BeautifulSoup에 익숙하다면 쉽게 사용할 수 있습니다. Scrapy·Parsel과 같은 가상 요소를 지원합니다.
- 🤝 **Scrapy 통합**: 콜백에 `scrapling_response` 데코레이터를 붙이면 이미 가져온 응답을 Scrapling 파서로 처리할 수 있습니다. 코드를 새로 작성할 필요가 없습니다.
- 📘 **전체 타입 힌트**: 편집기 지원과 코드 자동 완성을 돕습니다. 코드가 바뀔 때마다 **PyRight**와 **MyPy**가 전체 코드를 자동으로 검사합니다.
- 🔋 **바로 쓰는 Docker 이미지**: 새 버전마다 모든 브라우저가 포함된 Docker 이미지를 자동으로 만들고 배포합니다.

## 시작하기

자주 쓰는 기능을 몇 가지 살펴보겠습니다.

### 기본 사용법
세션을 지원하는 HTTP 요청
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # Chrome의 최신 TLS fingerprint 사용
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# 또는 일회성 요청 사용
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
고급 스텔스 모드
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # 작업이 끝날 때까지 브라우저를 열어둡니다
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# 또는 일회성 요청 스타일 - 이 요청을 위해 브라우저를 열고, 완료 후 닫습니다
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
완전한 브라우저 자동화
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # 작업이 끝날 때까지 브라우저를 열어둡니다
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # 원하시면 XPath selector도 사용 가능

# 또는 일회성 요청 스타일 - 이 요청을 위해 브라우저를 열고, 완료 후 닫습니다
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### 스파이더
동시 요청, 여러 세션, 일시 정지와 재개를 지원하는 크롤러를 만들 수 있습니다:
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"{len(result.items)}개의 인용구를 스크레이핑했습니다")
result.items.to_json("quotes.json")
```
한 스파이더에서 여러 종류의 세션을 사용합니다:
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]

    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)

    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # 보호된 페이지는 스텔스 세션을 통해 라우팅
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # 명시적 콜백
```
진행 상태를 저장하면 긴 크롤링 작업을 멈췄다가 이어서 실행할 수 있습니다. 다음처럼 스파이더를 시작하세요:
```python
QuotesSpider(crawldir="./crawl_data").start()
```
`crawldir`를 설정한 뒤 Ctrl+C를 누르면 대기 중인 요청과 방문한 URL이 저장됩니다. 같은 `crawldir`로 다시 시작하면 이어서 실행됩니다. 추출한 데이터는 따로 저장하세요.

바로 쓸 수 있는 템플릿도 있습니다. 예를 들어 Shopify 스토어의 전체 상품을 가져올 수 있습니다:
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # 스토어의 모든 상품을 변형당 한 항목씩 수집
```
이 템플릿은 공개 컬렉션 API에서 상품을 읽고, 상품 옵션 조합마다 한 항목을 만듭니다.

### 고급 파싱과 요소 탐색
```python
from scrapling.fetchers import Fetcher

# 풍부한 요소 선택과 내비게이션
page = Fetcher.get('https://quotes.toscrape.com/')

# 여러 선택 메서드로 인용구 가져오기
quotes = page.css('.quote')  # CSS selector
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # BeautifulSoup 스타일
# 아래와 동일
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # 등등...
# 텍스트 내용으로 요소 찾기
quotes = page.find_by_text('Albert Einstein', first_match=False)

# 고급 내비게이션
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # 체이닝 셀렉터
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# 요소 관계와 유사도
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
페이지를 가져오지 않고 파서를 직접 사용할 수도 있습니다:
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
사용법은 같습니다!

### 비동기 세션 예제
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # `FetcherSession`은 컨텍스트에 따라 동기/비동기 방식 모두로 동작합니다
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## CLI와 대화형 셸

터미널에서도 Scrapling을 사용할 수 있습니다:

[](https://asciinema.org/a/736339)

스크래핑용 대화형 셸을 실행합니다:
```bash
pip install "scrapling[shell]"
scrapling shell
```
프로그래밍 없이 페이지를 파일로 바로 추출합니다. `--css-selector`로 내용을 고르거나 `--ai-targeted`로 `body` 내용을 선택하고 정리하세요. 텍스트는 `.txt`, Markdown은 `.md`, HTML은 `.html`을 사용하세요.
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> MCP 서버와 대화형 셸 등 다른 기능은 [문서](https://scrapling.readthedocs.io/ko/latest/)에서 확인하세요.

## 성능 테스트

Scrapling은 강력할 뿐 아니라 매우 빠릅니다. 다음 테스트는 Scrapling 파서와 널리 쓰이는 다른 라이브러리의 최신 버전을 비교합니다.

### 텍스트 추출 속도: 중첩 요소 5,000개

| # |      라이브러리      | 시간(ms) | Scrapling 대비 |
|---|:-----------------:|:---------:|:------------:|
| 1 |     Scrapling     |   1.99    |     1.0x     |
| 2 |   Parsel/Scrapy   |   2.06    |    1.035     |
| 3 |     Lxml 단독      |   2.56    |    1.286     |
| 4 |      PyQuery      |   23.98   |     ~12x     |
| 5 |    Selectolax     |  197.02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545.15  |   ~776.5x    |
| 7 |   BS4 + Lxml   |  1562.1   |   ~785.0x    |
| 8 | BS4 + html5lib |  3412.73  |   ~1714.9x   |


### 비슷한 요소 찾기와 텍스트 검색

Scrapling의 적응형 요소 검색은 다른 방법보다 훨씬 빠릅니다:

| 라이브러리     | 시간(ms) | Scrapling 대비 |
|-------------|:---------:|:------------:|
| Scrapling   |    2.3    |     1.0x     |
| AutoScraper |   12.58   |    5.47x     |


> 각 결과는 100회 이상 실행한 평균입니다. 측정 방법은 [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py)를 확인하세요.

## 설치

Scrapling에는 Python 3.10 이상이 필요합니다:

```bash
pip install scrapling
```

> [!IMPORTANT]
> 이 명령은 파서와 필요한 패키지만 설치합니다. Fetcher나 명령줄 도구는 포함되지 않습니다. 따라서 위 예제처럼 `scrapling.fetchers`나 `scrapling.spiders`에서 가져오면 `ModuleNotFoundError`가 발생합니다. Fetcher나 스파이더를 사용하려면 먼저 아래 방법으로 Fetcher에 필요한 패키지를 설치하세요.

### 추가 패키지

1. Fetcher, 관련 클래스, 아래 추가 기능을 사용하려면 Fetcher와 브라우저에 필요한 패키지를 설치하세요:
    ```bash
    pip install "scrapling[fetchers]"

    scrapling install           # 일반 설치
    scrapling install  --force  # 강제 재설치
    ```

    모든 브라우저, 필요한 시스템 패키지, 브라우저 지문을 바꾸는 도구를 다운로드합니다.

    명령어 대신 코드에서 설치할 수도 있습니다:
    ```python
    from scrapling.cli import install

    install([], standalone_mode=False)          # 일반 설치
    install(["--force"], standalone_mode=False) # 강제 재설치
    ```

2. 추가 기능:
   - MCP 서버 설치:
       ```bash
       pip install "scrapling[ai]"
       ```
   - [RAG 시스템 만들기](https://scrapling.readthedocs.io/ko/latest/ai/building-rag-systems.html)에 필요한 패키지 설치:
       ```bash
       pip install "scrapling[rag]"
       ```
   - 대화형 셸과 `extract` 명령어 설치:
       ```bash
       pip install "scrapling[shell]"
       ```
   - 모든 기능 설치:
       ```bash
       pip install "scrapling[all]"
       ```
   브라우저 Fetcher를 사용하려면 `scrapling install`을 실행하세요. HTTP 요청에는 브라우저 설치가 필요하지 않습니다.

### Docker
모든 추가 기능과 브라우저가 포함된 Docker 이미지를 DockerHub에서 받을 수도 있습니다:
```bash
docker pull pyd4vinci/scrapling
```
또는 GitHub 레지스트리에서 받으세요:
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
이 이미지는 저장소의 main 브랜치를 바탕으로 GitHub Actions에서 자동으로 만들고 배포합니다.

## 개발에 참여하기

개발 참여를 환영합니다! 시작하기 전에 [참여 안내](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md)를 읽어 주세요.

## 면책 조항

> [!CAUTION]
> 이 라이브러리는 학습과 연구 목적으로 제공합니다. 사용하면 국내외 데이터 수집과 개인정보 보호 관련 법률을 따르는 데 동의한 것으로 봅니다. 작성자와 참여자는 소프트웨어의 오용에 책임지지 않습니다. 사이트의 이용 약관과 robots.txt를 지켜 주세요.

## 🎓 인용
연구에 이 라이브러리를 사용했다면 다음 형식으로 인용해 주세요:
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## 라이선스

이 프로젝트는 BSD-3-Clause 라이선스로 배포합니다.

## 감사의 말

다음 프로젝트를 바탕으로 한 코드가 포함되어 있습니다:
- Parsel (BSD 라이선스) - [translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py) 서브모듈에 사용

---
<div align="center"><small>Karim Shoair가 ❤️으로 디자인하고 만들었습니다.</small></div><br>

---

### README PT BR (`docs/README_PT_BR.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io/pt-br/latest/">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Capa do Scrapling" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>Extraia dados da web moderna de forma simples</small>
</h1>

<p align="center">
    <a href="https://trendshift.io/repositories/14244" target="_blank"><img src="https://trendshift.io/api/badge/repositories/14244" alt="D4Vinci%2FScrapling | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
    <br/>
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="Testes">
        <img alt="Testes" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="Versão no PyPI">
        <img alt="Versão no PyPI" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Downloads no Docker" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="Downloads do pacote no PyPI"></a>
    <a href="https://scrapling.readthedocs.io/pt-br/latest/ai/agent-skill.html" alt="Skill para agentes de IA">
        <img alt="Badge da Agent Skill" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Fpt-br%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="Skill para OpenClaw">
        <img alt="Skill para OpenClaw" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X (antigo Twitter)">
      <img alt="Siga no X (antigo Twitter)" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="Versões do Python compatíveis">
        <img alt="Versões do Python compatíveis" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/pt-br/latest/parsing/selection.html"><strong>Métodos de seleção</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/pt-br/latest/fetching/choosing.html"><strong>Fetchers</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/pt-br/latest/spiders/architecture.html"><strong>Spiders</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/pt-br/latest/spiders/proxy-blocking.html"><strong>Rotação de proxies</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/pt-br/latest/cli/overview.html"><strong>CLI</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/pt-br/latest/ai/mcp-server.html"><strong>MCP</strong></a>
</p>

Scrapling é um framework de web scraping para Python. Ele reúne solicitações HTTP rápidas, navegadores furtivos, análise de páginas e rastreamento simultâneo em uma só biblioteca.

Extraia dados de páginas estáticas, execute JavaScript, interaja com sites e acesse as APIs que eles usam. Crie crawlers com sessões reutilizáveis, rotação de proxies, novas tentativas automáticas, pausa e retomada, e exportação de dados integrada.

Use o Scrapling pelo Python, pelo terminal ou com seu agente de IA por meio do servidor MCP e da Agent Skill. Ele cobre todo o processo, desde extrair alguns campos até salvar um site inteiro como arquivos Markdown limpos.

## O que você pode fazer com o Scrapling

- **[Obter páginas e interagir](https://scrapling.readthedocs.io/pt-br/latest/fetching/choosing.html)**: Solicitações HTTP rápidas, navegadores furtivos, execução de JavaScript, tratamento de Cloudflare Turnstile e Interstitial, sessões persistentes e captura de respostas de APIs em segundo plano.
- **[Analisar e extrair](https://scrapling.readthedocs.io/pt-br/latest/parsing/selection.html)**: Busca com CSS, XPath, texto e expressões regulares, localização de elementos após mudanças na página, busca de elementos semelhantes e saída em Markdown limpo.
- **[Rastrear e exportar](https://scrapling.readthedocs.io/pt-br/latest/spiders/getting-started.html)**: Spiders simultâneos, rotação de proxies, novas tentativas, AutoThrottle, pausa e retomada, resultados em streaming, modelos prontos e exportação em JSON, JSONL, CSV e XML.
- **[Extrair dados com IA ou pelo terminal](https://scrapling.readthedocs.io/pt-br/latest/ai/mcp-server.html)**: Um servidor MCP para agentes de IA navegarem e extraírem dados, uma Agent Skill, comandos CLI e um shell interativo.

Comece com uma só página:

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

Ou extraia mais dados com um spider:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

Este exemplo imprime `10` e salva as citações e seus autores em `quotes.json`.

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# Patrocinadores Platinum
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> - o provedor de proxies mais eficiente para Web Scraping e automação, com a mais alta qualidade de IP do mercado. Use o código SCRAPLING35 para obter 35% de desconto.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling lida com o Cloudflare Turnstile. Para proteção de nível empresarial, <a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a> oferece endpoints de API que geram tokens antibot válidos para <b>Akamai</b>, <b>DataDome</b>, <b>Kasada</b> e <b>Incapsula</b>. Chamadas simples de API, sem necessidade de automação de navegador. </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a>: proxies residenciais a partir de US$0,49/GB. Navegador de scraping com Chromium que altera sua identificação, IPs residenciais, resolução automática de CAPTCHA e recursos para evitar sistemas antibot. </br>
      <b>Scraper API para resultados sem complicação. Integrações com MCP e N8N estão disponíveis.</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    Leia uma análise completa do <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">Scrapling no The Web Scraping Club</a> (nov. 2025), a newsletter número 1 dedicada a Web Scraping.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a> fornece proxies residenciais escaláveis com mais de 80 milhões de IPs em mais de 195 países, entregando conexões rápidas e confiáveis, rotação automática e recursos para evitar bloqueios. Teste grátis disponível.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    A <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a> fornece proxies residenciais, móveis, ISP e de datacenter de origem ética, além de ferramentas de scraping e automação com IA. Use o código SCRAPLING10 para obter 10% de desconto em proxies residenciais.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a>: Reduza os bloqueios e os CAPTCHAs em 90%. 28 milhões de IPs residenciais premium para scraping intensivo da web. 195 países. Segmentação por cidade/ISP/CEP. Sessões fixas ou rotativas. Tráfego sem prazo de validade a partir de $2/GB. Código <strong>SCRAPEANDTAKE</strong>: <em>25% de desconto</em>.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a>: Pare de pagar por GB. Tráfego residencial ilimitado, mais de 100 milhões de IPs, mais de 190 países. Pague pela largura de banda. Solicite um teste gratuito de proxies residenciais de 50 Mbps.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    $1/GB na <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a>. Proxies de origem ética, direto da fonte. Mais de 90 milhões de IPs, mais de 195 países. Residenciais, de datacenter e móveis. Pagamento por uso = sem assinatura. O tráfego nunca expira.
    </td>
  </tr>
</table>

<i><sub>Quer mostrar seu anúncio aqui? Clique [aqui](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)</sub></i>
# Patrocinadores



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>Quer mostrar seu anúncio aqui? Clique [aqui](https://github.com/sponsors/D4Vinci) e escolha o plano que fizer mais sentido para você!</sub></i>

---

## Principais recursos

### Spiders: um framework completo de rastreamento

- 🕷️ **API de Spider parecida com a do Scrapy**: Defina spiders com `start_urls`, callbacks `parse` assíncronos e objetos `Request` e `Response`.
- ⚡ **Rastreamento simultâneo**: Configure o número de solicitações simultâneas, os limites por domínio e o intervalo entre downloads.
- 🔄 **Várias sessões**: Use solicitações HTTP e navegadores furtivos sem interface gráfica no mesmo spider. Direcione as solicitações para sessões diferentes pelo ID.
- 💾 **Pausa e retomada**: Salve as solicitações pendentes e as URLs visitadas com `crawldir`. Pressione Ctrl+C para parar com segurança e reinicie com o mesmo diretório.
- 📡 **Resultados em streaming**: Receba os itens assim que forem extraídos com `async for item in spider.stream()`, junto com estatísticas em tempo real. É útil para interfaces, processos de dados e rastreamentos longos.
- 🛡️ **Detecção de solicitações bloqueadas**: Detecte e repita automaticamente as solicitações bloqueadas. Você pode personalizar esse comportamento.
- 🚦 **AutoThrottle**: O spider ajusta o intervalo de cada domínio conforme a velocidade de resposta do site. Se o site bloquear ou limitar as solicitações, ele dobra o intervalo ou respeita o tempo indicado por `Retry-After`. Quando a limitação termina, volta a acelerar.
- 🤖 **Respeito ao robots.txt**: Ative `robots_txt_obey` para respeitar as diretivas `Disallow`, `Crawl-delay` e `Request-rate`, com cache por domínio.
- 🧪 **Modo de desenvolvimento**: Salve as respostas em disco na primeira execução e reutilize-as nas próximas. Assim você pode ajustar `parse()` sem enviar novas solicitações aos servidores.
- 🧩 **Modelos de spider prontos**: Use `CrawlSpider` para seguir links por regras, `SitemapSpider` para rastrear a partir de sitemaps ou robots.txt, `XMLFeedSpider` e `CSVFeedSpider` para ler feeds XML, RSS e CSV, e `ShopifySpider` para coletar produtos de lojas públicas do Shopify, com um item por variante.
- 🔗 **Extração de links**: `LinkExtractor` permite aceitar ou recusar links por padrões, filtrar domínios e extensões, limitar a busca com CSS ou XPath e normalizar as URLs. Use com os modelos ou separadamente.
- 📦 **Exportação integrada**: Exporte os resultados com hooks e seu próprio processo de dados, ou use os formatos JSON, JSONL, CSV e XML integrados: `result.items.to_json()`, `to_jsonl()`, `to_csv()` e `to_xml()`.

### Obtenção de páginas com suporte a sessões

- **Solicitações HTTP**: Envie solicitações HTTP rápidas e furtivas com `Fetcher`. Você pode imitar a impressão digital TLS e os cabeçalhos de um navegador, além de usar HTTP/3.
- **Carregamento dinâmico**: Obtenha sites dinâmicos com automação completa do navegador por meio de `StealthyFetcher`, compatível com o Chromium do Playwright e o Google Chrome.
- **Evasão de sistemas antibot**: `StealthyFetcher` oculta a automação e imita impressões digitais do navegador. Pode superar automaticamente os diferentes tipos de Cloudflare Turnstile e Interstitial.
- **Gerenciamento de sessões**: `FetcherSession` e `StealthySession` mantêm os cookies e o estado entre solicitações.
- **Rotação de proxies**: `ProxyRotator` permite alternar os proxies de forma cíclica ou personalizada em todos os tipos de sessão. Você também pode escolher um proxy para uma solicitação específica.
- **Bloqueio de domínios e anúncios**: Bloqueie solicitações a domínios e subdomínios específicos ou ative o bloqueio de anúncios dos fetchers de navegador. Ele inclui cerca de 3.500 domínios conhecidos de anúncios e rastreamento.
- **Prevenção de vazamentos de DNS**: Ative DNS-over-HTTPS para enviar consultas DNS pelo serviço DoH da Cloudflare e evitar vazamentos ao usar proxies.
- **Navegadores remotos**: Conecte-se a um navegador em execução por CDP com `cdp_url`, seja no seu computador, em outro servidor ou em um serviço de navegadores. Você também pode usar sua própria versão do Chromium com qualquer fetcher de navegador por meio de `executable_path`.
- **Captura de APIs em segundo plano**: Ative `record_requests=True` em uma sessão de navegador e busque as respostas salvas com `session.network.search(limit=None)`. Leia dados de APIs e erros HTTP de diferentes carregamentos sem repetir as solicitações. O histórico tem tamanho limitado e salva o conteúdo das respostas de texto.
- **Suporte assíncrono**: Todos os fetchers permitem o uso assíncrono, com classes de sessão próprias para esse modo.

### Análise de páginas e extração de dados

- 🔄 **Localização de elementos**: Encontre os elementos após mudanças no site usando algoritmos de semelhança.
- 🎯 **Seleção flexível**: Use seletores CSS e XPath, filtros, texto, expressões regulares e mais.
- 🔍 **Elementos semelhantes**: Encontre automaticamente elementos parecidos com os que você já localizou.

### Recursos de IA

- 🤖 **Servidor MCP**: Permite que assistentes e agentes de IA, como Claude e Cursor, extraiam dados com Scrapling por meio de solicitações HTTP, ações do navegador, capturas de tela, estado de login salvo e respostas de APIs em segundo plano. Usa nosso navegador furtivo e ferramentas que ajudam os modelos adequados a resolver CAPTCHA, além do solucionador de Cloudflare. Reduz o conteúdo enviado ao modelo, bloqueia anúncios e protege contra injeção de instruções (prompt injection). Também permite usar navegadores remotos por CDP e conexões HTTP com opções de autenticação. ([Vídeo de demonstração](https://www.youtube.com/watch?v=qyFk3ZNwOxE))
- 🧠 **Agent Skill**: Uma [Agent Skill](https://scrapling.readthedocs.io/pt-br/latest/ai/agent-skill.html) pronta para instalar que ensina a biblioteca aos agentes de programação, para que escrevam código compatível com a API atual.
- 📚 **Markdown pronto para RAG**: Converta uma página em Markdown limpo e preparado para modelos de linguagem com uma linha (`page.markdown()`), ou salve um site inteiro como arquivos Markdown com o modelo `ContentSpider`. O processo não precisa de um modelo de linguagem. ([Documentação](https://scrapling.readthedocs.io/pt-br/latest/ai/building-rag-systems.html))

### Alto desempenho e uso comprovado

- 🚀 **Alta velocidade**: Desempenho otimizado que supera a maioria das bibliotecas de web scraping para Python.
- 🔋 **Baixo consumo de memória**: Estruturas de dados otimizadas e carregamento apenas quando necessário.
- ⚡ **Conversão rápida para JSON**: 10 vezes mais rápida que a biblioteca padrão.
- 🏗️ **Testado na prática**: Os testes cobrem 92% do Scrapling e todo o código tem anotações de tipo. Centenas de pessoas o usaram diariamente para extrair dados durante o último ano.

### Ferramentas para desenvolver e extrair dados

- 🎯 **Shell interativo**: Shell IPython opcional integrado ao Scrapling, com atalhos e ferramentas para criar scripts mais rápido. Converta solicitações curl em solicitações do Scrapling e veja os resultados no navegador.
- 🚀 **Uso pelo terminal**: Extraia os dados de uma URL sem escrever código.
- 🛠️ **Navegação pelo DOM**: Acesse os elementos pai, irmãos e filhos.
- 🧬 **Processamento de texto**: Expressões regulares, limpeza de texto e operações de strings otimizadas.
- 📝 **Geração de seletores**: Gere seletores CSS e XPath confiáveis para qualquer elemento.
- 🔌 **API conhecida**: Parecida com Scrapy e BeautifulSoup, com os mesmos pseudoelementos do Scrapy e do Parsel.
- 🤝 **Integração direta com Scrapy**: Adicione o decorador `scrapling_response` a um callback para analisar as respostas que você já obtém com o parser do Scrapling, sem reescrever seu programa.
- 📘 **Anotações de tipo completas**: Ajudam o editor a verificar e completar o código. Todo o código é verificado automaticamente com **PyRight** e **MyPy** a cada alteração.
- 🔋 **Imagem Docker pronta**: Uma imagem Docker com todos os navegadores é criada e publicada automaticamente a cada versão.

## Primeiros passos

Veja alguns exemplos do que você pode fazer com o Scrapling.

### Uso básico
Solicitações HTTP com suporte a sessões
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # Use a versão mais recente da fingerprint TLS do Chrome
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# Ou use requisições avulsas
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
Navegação furtiva
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # Mantenha o navegador aberto até terminar
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# Ou use o estilo de requisição avulsa, ele abre o navegador para esta requisição e o fecha ao finalizar
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
Automação completa de navegador
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # Mantenha o navegador aberto até terminar
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # Se preferir, use seletor XPath

# Ou use o estilo de requisição avulsa, ele abre o navegador para esta requisição e o fecha ao finalizar
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### Spiders
Crie crawlers completos com solicitações simultâneas, vários tipos de sessão, pausa e retomada:
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10
    
    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }
            
        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"Extraídas {len(result.items)} citações")
result.items.to_json("quotes.json")
```
Use vários tipos de sessão no mesmo spider:
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]
    
    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)
    
    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # Direcione páginas protegidas através da sessão stealth
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # callback explícito
```
Salve o progresso para pausar e retomar rastreamentos longos. Execute o spider assim:
```python
QuotesSpider(crawldir="./crawl_data").start()
```
Com `crawldir` definido, pressione Ctrl+C para salvar as solicitações pendentes e as URLs visitadas. Reinicie com o mesmo `crawldir` para continuar. Salve os dados extraídos separadamente.

Você também pode usar um modelo pronto. Por exemplo, extraia o catálogo inteiro de uma loja Shopify:
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # Todos os produtos da loja, um item por variante
```
O modelo lê os produtos disponíveis nos endpoints públicos das coleções, com um item por variante.

### Análise avançada e navegação
```python
from scrapling.fetchers import Fetcher

# Seleção rica de elementos e navegação
page = Fetcher.get('https://quotes.toscrape.com/')

# Obtenha citações com múltiplos métodos de seleção
quotes = page.css('.quote')  # Seletor CSS
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # Estilo BeautifulSoup
# O mesmo que
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # e assim por diante...
# Encontre elementos por conteúdo de texto
quotes = page.find_by_text('Albert Einstein', first_match=False)

# Navegação avançada
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # Seletores encadeados
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# Relações e similaridade entre elementos
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
Você pode usar o parser diretamente, sem obter uma página da web:
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
Ele funciona da mesma forma.

### Exemplos de sessões assíncronas
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # `FetcherSession` se adapta ao contexto e funciona tanto com sync quanto com async
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## CLI e shell interativo

Você também pode usar o Scrapling pelo terminal:

[](https://asciinema.org/a/736339)

Inicie o shell interativo de web scraping:
```bash
pip install "scrapling[shell]"
scrapling shell
```
Extraia páginas diretamente para um arquivo sem programar. Use `--css-selector` para escolher o conteúdo ou `--ai-targeted` para selecionar e limpar o conteúdo de `body`. Use `.txt` para texto, `.md` para Markdown ou `.html` para HTML.
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> Veja mais recursos, incluindo o servidor MCP e o shell interativo, na [documentação completa](https://scrapling.readthedocs.io/pt-br/latest/).

## Testes de desempenho

Scrapling também se destaca pela velocidade. Estes testes comparam seu parser com as versões mais recentes de outras bibliotecas conhecidas.

### Velocidade de extração de texto (5.000 elementos aninhados)

| # |    Biblioteca     | Tempo (ms) | Comparação com Scrapling |
|---|:-----------------:|:----------:|:------------:|
| 1 |     Scrapling     |    1,99    |     1,0x     |
| 2 |   Parsel/Scrapy   |    2,06    |     1,035    |
| 3 |     Lxml puro      |    2,56    |    1,286     |
| 4 |      PyQuery      |   23,98    |     ~12x     |
| 5 |    Selectolax     |   197,02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545,15   |   ~776,5x    |
| 7 |   BS4 com Lxml   |   1562,1   |   ~785,0x    |
| 8 | BS4 com html5lib |  3412,73   |   ~1714,9x   |


### Desempenho da busca de elementos semelhantes e de texto

A busca adaptativa de elementos do Scrapling é mais rápida que as alternativas:

| Biblioteca  | Tempo (ms) | Comparação com Scrapling |
|-------------|:----------:|:------------:|
| Scrapling   |    2,3     |     1,0x     |
| AutoScraper |   12,58    |    5,47x     |


> Cada resultado é a média de pelo menos 100 execuções. Veja o método em [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py).

## Instalação

Scrapling requer Python 3.10 ou mais recente:

```bash
pip install scrapling
```

> [!IMPORTANT]
> Este comando instala apenas o parser e suas dependências, sem fetchers ou ferramentas de linha de comando. Se você instalar apenas isso, importar de `scrapling.fetchers` ou `scrapling.spiders`, como nos exemplos anteriores, gera `ModuleNotFoundError`. Para usar fetchers ou spiders, instale primeiro as dependências dos fetchers, como mostrado a seguir.

### Dependências opcionais

1. Para usar os fetchers, suas classes ou os recursos adicionais a seguir, instale as dependências dos fetchers e dos navegadores:
    ```bash
    pip install "scrapling[fetchers]"
    
    scrapling install           # instalação normal
    scrapling install  --force  # forçar reinstalação
    ```

    Isso baixa todos os navegadores, as dependências do sistema e as ferramentas para alterar as impressões digitais do navegador.

    Você também pode instalar pelo Python, em vez de executar um comando:
    ```python
    from scrapling.cli import install
    
    install([], standalone_mode=False)          # instalação normal
    install(["--force"], standalone_mode=False) # forçar reinstalação
    ```

2. Recursos adicionais:
   - Instalar o servidor MCP:
       ```bash
       pip install "scrapling[ai]"
       ```
   - Instalar as dependências para [criar sistemas RAG](https://scrapling.readthedocs.io/pt-br/latest/ai/building-rag-systems.html):
       ```bash
       pip install "scrapling[rag]"
       ```
   - Instalar o shell interativo e o comando `extract`:
       ```bash
       pip install "scrapling[shell]"
       ```
   - Instalar tudo:
       ```bash
       pip install "scrapling[all]"
       ```
   Execute `scrapling install` para usar fetchers de navegador. Solicitações HTTP não precisam de um navegador.

### Docker
Você também pode baixar do DockerHub uma imagem Docker com todos os extras e navegadores:
```bash
docker pull pyd4vinci/scrapling
```
Ou baixar pelo registro do GitHub:
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
A imagem é criada a partir da branch principal do repositório e publicada automaticamente pelo GitHub Actions.

## Como contribuir

Contribuições são bem-vindas! Leia nossas [diretrizes de contribuição](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md) antes de começar.

## Aviso legal

> [!CAUTION]
> Esta biblioteca é apenas para ensino e pesquisa. Ao usá-la, você concorda em cumprir as leis locais e internacionais de extração de dados e privacidade. Os autores e colaboradores não se responsabilizam pelo uso indevido deste software. Respeite os termos de serviço dos sites e os arquivos robots.txt.

## 🎓 Citações
Se você usou esta biblioteca em sua pesquisa, cite-a com esta referência:
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## Licença

Este projeto usa a licença BSD-3-Clause.

## Agradecimentos

Este projeto inclui código adaptado de:
- Parsel (Licença BSD) - usado para o submódulo [translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py)

---
<div align="center"><small>Projetado e desenvolvido com ❤️ por Karim Shoair.</small></div><br>

---

### README RU (`docs/README_RU.md`)

<h1 align="center">
    <a href="https://scrapling.readthedocs.io/ru/latest/">
        <picture>
          <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_dark.svg?sanitize=true">
          <img alt="Обложка Scrapling" src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/docs/assets/cover_light.svg?sanitize=true">
        </picture>
    </a>
    <br>
    <small>Простой веб-скрапинг для современного интернета</small>
</h1>

<p align="center">
    <a href="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml" alt="Тесты">
        <img alt="Тесты" src="https://github.com/D4Vinci/Scrapling/actions/workflows/tests.yml/badge.svg"></a>
    <a href="https://badge.fury.io/py/Scrapling" alt="Версия PyPI">
        <img alt="Версия PyPI" src="https://badge.fury.io/py/Scrapling.svg"></a>
    <a href="https://hub.docker.com/r/pyd4vinci/scrapling" target="_blank">
        <img alt="Загрузки Docker" src="https://img.shields.io/docker/pulls/pyd4vinci/scrapling?labelColor=%20%23FDB062&logo=Docker&labelColor=%20%23528bff"></a>
    <a href="https://clickpy.clickhouse.com/dashboard/scrapling" rel="nofollow"><img src="https://img.shields.io/pypi/dm/scrapling" alt="Загрузки пакета PyPI"></a>
    <a href="https://scrapling.readthedocs.io/ru/latest/ai/agent-skill.html" alt="Skill для AI-агентов">
        <img alt="Значок Agent Skill" src="https://img.shields.io/badge/Skill-black?style=flat&label=Agent&link=https%3A%2F%2Fscrapling.readthedocs.io%2Fru%2Flatest%2Fai%2Fagent-skill.html"></a>
    <a href="https://clawhub.ai/D4Vinci/scrapling-official" alt="Skill для OpenClaw">
        <img alt="Skill для OpenClaw" src="https://img.shields.io/badge/Clawhub-darkred?style=flat&label=OpenClaw&link=https%3A%2F%2Fclawhub.ai%2FD4Vinci%2Fscrapling-official"></a>
    <br/>
    <a href="https://discord.gg/EMgGbDceNQ" alt="Discord" target="_blank">
      <img alt="Discord" src="https://img.shields.io/discord/1360786381042880532?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FEMgGbDceNQ">
    </a>
    <a href="https://x.com/Scrapling_dev" alt="X (бывший Twitter)">
      <img alt="Подписаться в X (бывший Twitter)" src="https://img.shields.io/twitter/follow/Scrapling_dev?style=social&logo=x&link=https%3A%2F%2Fx.com%2FScrapling_dev">
    </a>
    <br/>
    <a href="https://pypi.org/project/scrapling/" alt="Поддерживаемые версии Python">
        <img alt="Поддерживаемые версии Python" src="https://img.shields.io/pypi/pyversions/scrapling.svg"></a>
</p>

<p align="center">
    <a href="https://scrapling.readthedocs.io/ru/latest/parsing/selection.html"><strong>Поиск элементов</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ru/latest/fetching/choosing.html"><strong>Выбор Fetcher</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ru/latest/spiders/architecture.html"><strong>Пауки</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ru/latest/spiders/proxy-blocking.html"><strong>Смена прокси</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ru/latest/cli/overview.html"><strong>CLI</strong></a>
    &middot;
    <a href="https://scrapling.readthedocs.io/ru/latest/ai/mcp-server.html"><strong>MCP-сервер</strong></a>
</p>

Scrapling объединяет быстрые HTTP-запросы, скрытные браузеры, мощный разбор страниц и параллельный обход сайтов в одной библиотеке Python.

Загружайте статические страницы, выполняйте JavaScript, работайте с сайтами и извлекайте данные из API этих сайтов. Создавайте краулеры с повторным использованием сессий, сменой прокси, автоматическими повторами, паузой и продолжением работы, а также готовым экспортом данных.

Используйте Scrapling из Python, терминала или AI-агента через MCP-сервер и Agent Skill. Библиотека помогает на всех этапах: от извлечения нескольких полей до сохранения целого сайта в виде чистых Markdown-файлов.

## Что можно сделать со Scrapling

- **[Загрузка и работа с сайтами](https://scrapling.readthedocs.io/ru/latest/fetching/choosing.html)**: быстрые HTTP-запросы, скрытные браузеры, выполнение JavaScript, прохождение Cloudflare Turnstile и Interstitial, постоянные сессии и запись фоновых API-ответов.
- **[Разбор и извлечение данных](https://scrapling.readthedocs.io/ru/latest/parsing/selection.html)**: CSS, XPath, поиск по тексту и регулярным выражениям, поиск элементов после изменений страницы, поиск похожих элементов и чистый Markdown.
- **[Обход и экспорт](https://scrapling.readthedocs.io/ru/latest/spiders/getting-started.html)**: параллельные Spider, смена прокси, повторы, AutoThrottle, пауза и продолжение, потоковая выдача, готовые шаблоны и экспорт в JSON, JSONL, CSV и XML.
- **[Сбор данных с AI или из терминала](https://scrapling.readthedocs.io/ru/latest/ai/mcp-server.html)**: MCP-сервер для работы AI-агентов с сайтами и данными, Agent Skill, команды CLI и интерактивная оболочка.

Начните с одной страницы:

```python
from scrapling.fetchers import Fetcher

page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
print(quotes)
```

Или используйте Spider для обхода многих страниц:

```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

result = QuotesSpider().start()
print(len(result.items))
result.items.to_json("quotes.json")
```

Код выведет `10` и сохранит цитаты с авторами в `quotes.json`.

<p align="center">
    <a href="https://dataimpulse.com/?utm_source=scrapling&utm_medium=banner&utm_campaign=scrapling" target="_blank" style="display:flex; justify-content:center; padding:4px 0;">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse.png" alt="At DataImpulse, we specialize in developing custom proxy services for your business. Make requests from anywhere, collect data, and enjoy fast connections with our premium proxies." style="max-height:60px;">
    </a>
</p>

# Платиновые спонсоры
<table>
  <tr>
    <td width="200">
      <a href="https://go.nodemaven.com/scraplingoctober" target="_blank" title="Proxies with the Highest IP Scores">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/NodeMaven.jpg" width="240" height="100">
      </a>
    </td>
    <td>
    <a href="https://go.nodemaven.com/scraplingoctober" target="_blank">NodeMaven</a> - самый эффективный провайдер прокси для веб-скрапинга и автоматизации с IP-адресами самого высокого качества на рынке. Используйте код SCRAPLING35 для получения скидки 35%.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=scrapling" target="_blank" title="Bot Protection Bypass API for Akamai, DataDome, Incapsula & Kasada">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/HyperSolutions.png">
      </a>
    </td>
    <td> Scrapling справляется с Cloudflare Turnstile. Для обхода защиты корпоративного уровня
      <a href="https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=scrapling">
        <b>Hyper Solutions</b>
      </a> предоставляет API для получения действительных antibot-токенов для <b>Akamai</b>, <b>DataDome</b>, <b>Kasada</b> и <b>Incapsula</b>. Достаточно простых вызовов API. Автоматизация браузера не нужна.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling" target="_blank" title="Evomi is your Swiss Quality Proxy Provider, starting at $0.49/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/evomi.png">
      </a>
    </td>
    <td>
      <a href="https://evomi.com?utm_source=github&utm_medium=banner&utm_campaign=d4vinci-scrapling">
        <b>Evomi</b>
      </a>: резидентные прокси от $0,49/ГБ. Браузер для скрапинга на основе Chromium с полной подменой отпечатка браузера, резидентными IP, автоматическим решением CAPTCHA и обходом защиты от ботов. </br>
      <b>Scraper API для получения результатов без лишних сложностей. Доступны интеграции с MCP и N8N.</b>
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank" title="The #1 newsletter dedicated to Web Scraping">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/TWSC.png">
      </a>
    </td>
    <td>
    Прочитайте полный обзор <a href="https://substack.thewebscraping.club/p/scrapling-hands-on-guide?utm_source=github&utm_medium=repo&utm_campaign=scrapling" target="_blank">Scrapling на The Web Scraping Club</a> (ноябрь 2025), опубликованный в рассылке №1 по веб-скрапингу.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank" title="Scalable Solutions for Web Data Access">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SwiftProxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.swiftproxy.net/?ref=D4Vinci" target="_blank">Swiftproxy</a> предоставляет масштабируемые резидентные прокси с более чем 80 млн IP в 195+ странах, обеспечивая быстрые и надёжные соединения, автоматическую ротацию и высокую устойчивость к блокировкам. Доступна бесплатная пробная версия.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank" title="Ethically sourced residential proxy infrastructure powering web scraping and AI agents">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/byteful.png">
      </a>
    </td>
    <td>
    <a href="https://byteful.com/?utm_source=github&utm_medium=github-sponsor&utm_campaign=scrapling_github_sponsor" target="_blank">Byteful</a> предоставляет резидентные, мобильные, ISP- и дата-центровые прокси из этичных источников, а также инструменты для веб-скрапинга и автоматизации с AI. Используйте код SCRAPLING10 для получения скидки 10% на резидентные прокси.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank" title="28M+ clean residential IPs for browser automation. No Blocks. No CAPTCHAs. Pay-as-you-Go.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxylane.png">
      </a>
    </td>
    <td>
    <a href="https://proxylane.dev/?utm_source=scrapling&utm_medium=partnership&utm_campaign=scrapling_platinum_202609&utm_content=github_readme" target="_blank">ProxyLane</a>: Сократите число блокировок и CAPTCHA на 90%. 28 млн премиальных резидентных IP-адресов для интенсивного веб-скрапинга. 195 стран. Выбор города, ISP и почтового индекса. Сессии с постоянным IP или сменой IP. Трафик без срока действия от $2/ГБ. Код <strong>SCRAPEANDTAKE</strong>: <em>скидка 25%</em>.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://www.lundproxy.com/unlimited-residential-bandwidth.html?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=banner" target="_blank" title="Unlimited residential traffic, sized only by bandwidth.">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/lundproxy.png">
      </a>
    </td>
    <td>
    <a href="https://www.lundproxy.com?utm_source=github&utm_medium=sponsorship&utm_campaign=scrapling&utm_content=text" target="_blank">LundProxy</a>: Хватит платить за каждый ГБ. Безлимитный резидентный трафик, более 100 млн IP-адресов, более 190 стран. Оплата по пропускной способности. Запросите бесплатный пробный доступ к резидентным прокси на скорости 50 Мбит/с.
    </td>
  </tr>
  <tr>
    <td width="200">
      <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank" title="Buy Pay-as-you-go proxies from $1/GB">
        <img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/DataImpulse_Platinum.png">
      </a>
    </td>
    <td>
    $1/ГБ в <a href="https://dataimpulse.com/?utm_source=website&utm_medium=github_readme&utm_campaign=scrapling_platinum" target="_blank">DataImpulse</a>. Прокси из этичных источников, без посредников. Более 90 млн IP-адресов, более 195 стран. Резидентные, дата-центровые и мобильные. Оплата по мере использования, без подписки. Трафик без срока действия.
    </td>
  </tr>
</table>

<i><sub>Хотите разместить здесь свою рекламу? Нажмите [здесь](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646)</sub></i>
# Спонсоры



<a href="https://cloro.dev/?utm_source=referral&utm_medium=scrapling" target="_blank" title="The search API for the AI era"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/cloro.jpg"></a>

<br/>

<a href="https://serpapi.com/?utm_source=scrapling" target="_blank" title="Scrape Google and other search engines with SerpApi"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/SerpApi.png"></a>
<a href="https://visit.decodo.com/Dy6W0b" target="_blank" title="Try the Most Efficient Residential Proxies for Free"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/decodo.png"></a>
<a href="https://proxyempire.io/?ref=scrapling&utm_source=github&utm_medium=paid_referral&utm_campaign=open_source_sponsorship&utm_content=scrapling" target="_blank" title="Collect The Data Your Project Needs with the Best Residential Proxies"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/ProxyEmpire.png"></a>
<a href="https://www.webshare.io/?referral_code=48r2m2cd5uz1" target="_blank" title="The Most Reliable Proxy with Unparalleled Performance"><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/webshare.png"></a>
<a href="https://proxiware.com/?ref=scrapling" target="_blank" title="Collect Any Data. At Any Scale."><img src="https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/proxiware.png"></a>




<i><sub>Хотите разместить здесь свою рекламу? Нажмите [здесь](https://github.com/sponsors/D4Vinci) и выберите подходящий план!</sub></i>

---

## Основные возможности

### Spider: всё для обхода сайтов

- 🕷️ **API Spider в стиле Scrapy**: задайте `start_urls`, асинхронные обработчики `parse` и объекты `Request`/`Response`.
- ⚡ **Параллельный обход**: настройте число одновременных запросов, ограничения для каждого домена и задержки между загрузками.
- 🔄 **Несколько сессий**: используйте HTTP-запросы и скрытные браузеры без окна в одном Spider. Выбирайте сессию для запроса по её ID.
- 💾 **Пауза и продолжение**: сохраняйте ожидающие запросы и посещённые URL с помощью `crawldir`. Нажмите Ctrl+C для корректной остановки, затем запустите Spider с той же папкой.
- 📡 **Потоковая выдача**: получайте данные сразу после извлечения через `async for item in spider.stream()` и следите за статистикой в реальном времени. Удобно для интерфейсов, обработки данных и долгих обходов.
- 🛡️ **Обнаружение блокировок**: заблокированные запросы автоматически обнаруживаются и повторяются. Логику можно настроить.
- 🚦 **AutoThrottle**: больше не нужно угадывать задержки. Spider сам меняет задержку для каждого домена по скорости ответа сайта. При блокировках или ограничении частоты запросов он удваивает её либо ждёт время из `Retry-After`, а затем снова ускоряется.
- 🤖 **Соблюдение robots.txt**: включите `robots_txt_obey`, чтобы учитывать `Disallow`, `Crawl-delay` и `Request-rate`. Правила кешируются для каждого домена.
- 🧪 **Режим разработки**: сохраните ответы на диск при первом запуске и используйте их снова. Меняйте логику `parse()` без повторных обращений к серверам.
- 🧩 **Готовые шаблоны Spider**: `CrawlSpider` обходит ссылки по правилам, `SitemapSpider` использует sitemap и robots.txt, `XMLFeedSpider`/`CSVFeedSpider` читают ленты XML/RSS и CSV, а `ShopifySpider` собирает товары из открытых магазинов Shopify, по одной записи на вариант.
- 🔗 **Извлечение ссылок**: `LinkExtractor` поддерживает разрешающие и запрещающие шаблоны, фильтры доменов и расширений, выбор области через CSS/XPath и приведение URL к единому виду. Используйте его в шаблонах или отдельно.
- 📦 **Готовый экспорт**: сохраняйте результаты через хуки и собственную обработку либо в JSON, JSONL, CSV и XML через `result.items.to_json()`, `to_jsonl()`, `to_csv()` и `to_xml()`.

### Загрузка сайтов с поддержкой сессий

- **HTTP-запросы**: `Fetcher` отправляет быстрые и скрытные запросы. Он умеет имитировать TLS-отпечаток и заголовки браузера, а также использовать HTTP/3.
- **Динамические страницы**: `StealthyFetcher` загружает сайты с полной автоматизацией браузера. Поддерживаются Chromium из Playwright и Google Chrome.
- **Обход защиты от ботов**: `StealthyFetcher` скрывает признаки автоматизации и подменяет отпечаток браузера. Он автоматически проходит все виды проверок Cloudflare Turnstile и Interstitial.
- **Управление сессиями**: `FetcherSession` и `StealthySession` сохраняют cookie и состояние между запросами.
- **Смена прокси**: `ProxyRotator` перебирает прокси по кругу или по вашим правилам во всех типах сессий. Для отдельного запроса можно указать другой прокси.
- **Блокировка доменов и рекламы**: блокируйте запросы к выбранным доменам и их поддоменам. В браузерных Fetcher можно включить блокировку рекламы, которая охватывает около 3 500 рекламных и отслеживающих доменов.
- **Защита от утечек DNS**: включите DNS-over-HTTPS, чтобы отправлять DNS-запросы через DoH от Cloudflare и не допускать утечек DNS при работе с прокси.
- **Удалённые браузеры**: подключайтесь к уже запущенному браузеру через CDP с помощью `cdp_url`. Браузер может работать на том же компьютере, другом сервере или у провайдера браузерных услуг. Параметр `executable_path` позволяет указать собственную сборку Chromium для любого браузерного Fetcher.
- **Запись фоновых API-ответов**: включите `record_requests=True` в браузерной сессии, затем ищите сохранённые ответы через `session.network.search(limit=None)`. Читайте API-данные и HTTP-ошибки от разных загрузок страниц без повторной отправки запросов. История имеет ограниченный размер и сохраняет текстовые тела ответов.
- **Асинхронная работа**: все Fetcher поддерживают асинхронные вызовы. Есть и отдельные классы асинхронных сессий.

### Разбор и извлечение данных

- 🔄 **Поиск элементов после изменений**: алгоритмы сходства находят элементы снова, даже если сайт изменился.
- 🎯 **Гибкий поиск**: используйте CSS, XPath, фильтры, текст, регулярные выражения и другие способы.
- 🔍 **Похожие элементы**: автоматически находите элементы, похожие на уже найденные.

### Возможности для AI

- 🤖 **MCP-сервер**: AI-боты и агенты, такие как Claude и Cursor, могут собирать данные через Scrapling. Им доступны HTTP-запросы, действия в браузере, снимки экрана, сохранённый вход и фоновые API-ответы. Скрытный браузер и нужные инструменты позволяют подходящим AI-моделям проходить любые CAPTCHA во время работы, а проверки Cloudflare обрабатываются встроенным решением. Сервер уменьшает объём данных для модели, блокирует рекламу и защищает от Prompt Injection. Есть подключение к удалённым браузерам по CDP и HTTP-транспорт с настройками аутентификации. ([Демонстрация](https://www.youtube.com/watch?v=qyFk3ZNwOxE))
- 🧠 **Agent Skill**: готовый к установке [Agent Skill](https://scrapling.readthedocs.io/ru/latest/ai/agent-skill.html) знакомит агента со всей библиотекой. Он помогает писать код под текущий API без догадок.
- 📚 **Markdown для RAG**: одна строка (`page.markdown()`) превращает страницу в чистый и безопасный Markdown для LLM. Шаблон `ContentSpider` сохраняет целый сайт в набор Markdown-файлов. Для самого сбора и преобразования LLM не нужна. ([Документация](https://scrapling.readthedocs.io/ru/latest/ai/building-rag-systems.html))

### Высокая скорость, проверенная на практике

- 🚀 **Быстрая работа**: оптимизации позволяют опережать большинство библиотек Python для скрапинга.
- 🔋 **Мало памяти**: оптимизированные структуры данных и загрузка только по мере необходимости.
- ⚡ **Быстрое преобразование в JSON**: в 10 раз быстрее стандартной библиотеки.
- 🏗️ **Проверено на практике**: 92% покрытия тестами и аннотации типов для всего кода. За последний год сотни специалистов ежедневно использовали Scrapling для сбора данных.

### Удобные инструменты для разработчиков

- 🎯 **Интерактивная оболочка**: дополнительная оболочка IPython со Scrapling, сокращёнными командами и инструментами для быстрой разработки. Преобразуйте curl-запросы в запросы Scrapling и просматривайте результаты в браузере.
- 🚀 **Работа из терминала**: собирайте данные по URL, не написав ни строки кода!
- 🛠️ **Навигация по DOM**: переходите к родителям, соседним и дочерним элементам.
- 🧬 **Обработка текста**: регулярные выражения, очистка текста и быстрые операции со строками.
- 📝 **Создание селекторов**: получайте надёжные CSS- и XPath-селекторы для любого элемента.
- 🔌 **Знакомый API**: подход похож на Scrapy и BeautifulSoup, с теми же псевдоэлементами, что и в Scrapy/Parsel.
- 🤝 **Интеграция со Scrapy**: добавьте декоратор `scrapling_response` к обработчику, чтобы разбирать уже загруженные ответы парсером Scrapling. Переписывать проект не нужно.
- 📘 **Полные аннотации типов**: удобная работа в редакторе и автодополнение. При каждом изменении весь код автоматически проверяется **PyRight** и **MyPy**.
- 🔋 **Готовый образ Docker**: с каждым выпуском автоматически собирается и публикуется образ со всеми браузерами.

## Начало работы

Вот несколько примеров того, что умеет Scrapling.

### Базовое использование
HTTP-запросы с сессиями
```python
from scrapling.fetchers import Fetcher, FetcherSession

with FetcherSession(impersonate='chrome') as session:  # Используйте последнюю версию TLS fingerprint Chrome
    page = session.get('https://quotes.toscrape.com/', stealthy_headers=True)
    quotes = page.css('.quote .text::text').getall()

# Или используйте одноразовые запросы
page = Fetcher.get('https://quotes.toscrape.com/')
quotes = page.css('.quote .text::text').getall()
```
Расширенный режим скрытности
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, solve_cloudflare=True) as session:  # Держите браузер открытым, пока не закончите
    page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    data = page.css('#padded_content a').getall()

# Или используйте стиль одноразового запроса - открывает браузер для этого запроса, затем закрывает его после завершения
page = StealthyFetcher.fetch('https://nopecha.com/demo/cloudflare', solve_cloudflare=True)
data = page.css('#padded_content a').getall()
```
Полная автоматизация браузера
```python
from scrapling.fetchers import StealthyFetcher, StealthySession

with StealthySession(headless=True, disable_resources=False, network_idle=True) as session:  # Держите браузер открытым, пока не закончите
    page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
    data = page.xpath('//span[@class="text"]/text()').getall()  # XPath-селектор, если вы предпочитаете его

# Или используйте стиль одноразового запроса - открывает браузер для этого запроса, затем закрывает его после завершения
page = StealthyFetcher.fetch('https://quotes.toscrape.com/')
data = page.css('.quote .text::text').getall()
```

### Пауки
Создавайте краулеры с параллельными запросами, разными сессиями, паузой и продолжением работы:
```python
from scrapling.spiders import Spider, Response

class QuotesSpider(Spider):
    name = "quotes"
    start_urls = ["https://quotes.toscrape.com/"]
    concurrent_requests = 10

    async def parse(self, response: Response):
        for quote in response.css('.quote'):
            yield {
                "text": quote.css('.text::text').get(),
                "author": quote.css('.author::text').get(),
            }

        next_page = response.css('.next a')
        if next_page:
            yield response.follow(next_page[0].attrib['href'])

result = QuotesSpider().start()
print(f"Извлечено {len(result.items)} цитат")
result.items.to_json("quotes.json")
```
Используйте несколько типов сессий в одном Spider:
```python
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession

class MultiSessionSpider(Spider):
    name = "multi"
    start_urls = ["https://example.com/"]

    def configure_sessions(self, manager):
        manager.add("fast", FetcherSession(impersonate="chrome"))
        manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)

    async def parse(self, response: Response):
        for link in response.css('a::attr(href)').getall():
            # Направляйте защищённые страницы через stealth-сессию
            if "protected" in link:
                yield Request(link, sid="stealth")
            else:
                yield Request(link, sid="fast", callback=self.parse)  # явный callback
```
Сохраняйте прогресс, чтобы приостанавливать и продолжать долгий обход. Запустите Spider так:
```python
QuotesSpider(crawldir="./crawl_data").start()
```
Если задан `crawldir`, нажмите Ctrl+C, чтобы сохранить ожидающие запросы и уже посещённые URL. Для продолжения запустите Spider с тем же `crawldir`. Сохраняйте извлечённые данные отдельно.

Можно взять готовый шаблон. Например, для сбора всего каталога магазина Shopify:
```python
from scrapling.spiders import ShopifySpider

class MyStore(ShopifySpider):
    target_website = "example.com"

result = MyStore().start()  # Все товары магазина, по одной записи на вариант
```
Шаблон получает товары через открытые API коллекций и выдаёт одну запись на каждый вариант товара.

### Расширенный разбор и навигация
```python
from scrapling.fetchers import Fetcher

# Богатый выбор элементов и навигация
page = Fetcher.get('https://quotes.toscrape.com/')

# Получение цитат различными методами выбора
quotes = page.css('.quote')  # CSS-селектор
quotes = page.xpath('//div[@class="quote"]')  # XPath
quotes = page.find_all('div', {'class': 'quote'})  # В стиле BeautifulSoup
# То же самое, что
quotes = page.find_all('div', class_='quote')
quotes = page.find_all(['div'], class_='quote')
quotes = page.find_all(class_='quote')  # и так далее...
# Найти элемент по текстовому содержимому
quotes = page.find_by_text('Albert Einstein', first_match=False)

# Продвинутая навигация
quote_text = page.css('.quote')[0].css('.text::text').get()
quote_texts = page.css('.quote').css('.text::text').getall()  # Цепочка селекторов
first_quote = page.css('.quote')[0]
author = first_quote.css('.author::text').get()
next_quote = first_quote.next
parent_container = first_quote.parent

# Связи элементов и подобие
similar_elements = first_quote.find_similar()
below_elements = first_quote.below_elements
```
Можно использовать парсер напрямую, без загрузки сайта:
```python
from scrapling.parser import Selector

page = Selector("<html>...</html>")
```
И он работает точно так же!

### Асинхронные сессии
```python
import asyncio
from scrapling.fetchers import FetcherSession, AsyncStealthySession

async def main():
    async with FetcherSession(http3=True) as http_session:  # `FetcherSession` учитывает контекст и работает как с sync, так и с async
        page1 = await http_session.get('https://quotes.toscrape.com/')
        page2 = await http_session.get('https://quotes.toscrape.com/page/2/', impersonate='chrome')
        print(len(page1.css('.quote')), len(page2.css('.quote')))

    async with AsyncStealthySession(max_pages=2) as browser_session:
        urls = ['https://quotes.toscrape.com/js/', 'https://quotes.toscrape.com/js/page/2/']
        pages = await asyncio.gather(*(browser_session.fetch(url, wait_selector='.quote') for url in urls))
        print([len(page.css('.quote')) for page in pages])

asyncio.run(main())
```

## CLI и интерактивная оболочка

Scrapling можно использовать из командной строки:

[](https://asciinema.org/a/736339)

Запустите интерактивную оболочку для сбора данных:
```bash
pip install "scrapling[shell]"
scrapling shell
```
Извлекайте страницы прямо в файл без программирования. Выберите содержимое с `--css-selector` или используйте `--ai-targeted` для выбора и очистки содержимого `body`. Используйте `.txt` для текста, `.md` для Markdown или `.html` для HTML.
```bash
scrapling extract get 'https://quotes.toscrape.com/' quotes.md
scrapling extract get 'https://quotes.toscrape.com/' quotes.txt --css-selector '.quote' --impersonate 'chrome'
scrapling extract fetch 'https://quotes.toscrape.com/js/' quotes.md --css-selector '.quote' --wait-selector '.quote' --no-headless
scrapling extract fetch 'https://nopecha.com/demo/cloudflare' captchas.html --css-selector '#padded_content a' --solve-cloudflare
```

> [!NOTE]
> О других возможностях, включая MCP-сервер и интерактивную оболочку, читайте в [документации](https://scrapling.readthedocs.io/ru/latest/).

## Тесты производительности

Scrapling не только мощный, но и очень быстрый. Следующие тесты производительности сравнивают парсер Scrapling с последними версиями других популярных библиотек.

### Скорость извлечения текста: 5 000 вложенных элементов

| # |    Библиотека     | Время (мс) | По сравнению со Scrapling |
|---|:-----------------:|:----------:|:------------:|
| 1 |     Scrapling     |    1,99    |     1,0x     |
| 2 |   Parsel/Scrapy   |    2,06    |     1,035    |
| 3 |     Чистый Lxml      |    2,56    |    1,286     |
| 4 |      PyQuery      |   23,98    |     ~12x     |
| 5 |    Selectolax     |   197,02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545,15   |   ~776,5x    |
| 7 |   BS4 + Lxml   |   1562,1   |   ~785,0x    |
| 8 | BS4 + html5lib |  3412,73   |   ~1714,9x   |


### Поиск похожих элементов и текста

Адаптивный поиск элементов в Scrapling значительно опережает другие решения:

| Библиотека  | Время (мс) | По сравнению со Scrapling |
|-------------|:----------:|:------------:|
| Scrapling   |    2,3     |     1,0x     |
| AutoScraper |   12,58    |    5,47x     |


> Результаты усреднены по более чем 100 запускам. Методика приведена в [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py).

## Установка

Для Scrapling нужен Python 3.10 или новее:

```bash
pip install scrapling
```

> [!IMPORTANT]
> Эта команда устанавливает только парсер и его зависимости. Fetcher и инструменты командной строки в неё не входят. Поэтому импорт из `scrapling.fetchers` или `scrapling.spiders`, как в примерах выше, вызовет `ModuleNotFoundError`. Чтобы использовать Fetcher или Spider, сначала установите зависимости для загрузки страниц, как показано ниже.

### Дополнительные зависимости

1. Для Fetcher, их классов и дополнительных функций ниже установите зависимости для загрузки страниц и браузеров:
    ```bash
    pip install "scrapling[fetchers]"

    scrapling install           # normal install
    scrapling install  --force  # force reinstall
    ```

    Команда загрузит все браузеры, нужные системные пакеты и средства изменения отпечатков браузера.

    Вместо команды можно запустить установку из кода:
    ```python
    from scrapling.cli import install

    install([], standalone_mode=False)          # normal install
    install(["--force"], standalone_mode=False) # force reinstall
    ```

2. Дополнительные возможности:
   - MCP-сервер:
       ```bash
       pip install "scrapling[ai]"
       ```
   - Зависимости для [создания RAG-систем](https://scrapling.readthedocs.io/ru/latest/ai/building-rag-systems.html):
       ```bash
       pip install "scrapling[rag]"
       ```
   - Интерактивная оболочка и команда `extract`:
       ```bash
       pip install "scrapling[shell]"
       ```
   - Все возможности:
       ```bash
       pip install "scrapling[all]"
       ```
   Выполните `scrapling install`, если нужны браузерные Fetcher. Для HTTP-запросов устанавливать браузер не нужно.

### Docker
Образ Docker со всеми дополнениями и браузерами можно скачать из DockerHub:
```bash
docker pull pyd4vinci/scrapling
```
Или из реестра GitHub:
```bash
docker pull ghcr.io/d4vinci/scrapling:latest
```
Образ автоматически собирается и публикуется через GitHub Actions из основной ветки репозитория.

## Участие в разработке

Присоединяйтесь к разработке! Перед началом прочитайте [руководство для участников](https://github.com/D4Vinci/Scrapling/blob/main/CONTRIBUTING.md).

## Отказ от ответственности

> [!CAUTION]
> Библиотека предназначена только для обучения и исследований. Используя её, вы соглашаетесь соблюдать местные и международные законы о сборе данных и конфиденциальности. Авторы и участники не отвечают за неправомерное использование программы. Соблюдайте условия сайтов и правила robots.txt.

## 🎓 Цитирование
Если вы использовали библиотеку в исследовании, укажите её так:
```text
  @misc{scrapling,
    author = {Karim Shoair},
    title = {Scrapling},
    year = {2024},
    url = {https://github.com/D4Vinci/Scrapling},
    note = {A Python Web Scraping framework for everything from a single request to a full-scale crawl!}
  }
```

## Лицензия

Проект распространяется по лицензии BSD-3-Clause.

## Благодарности

В проекте есть код на основе следующих проектов:
- Parsel (лицензия BSD) - Используется для подмодуля [translator](https://github.com/D4Vinci/Scrapling/blob/main/scrapling/core/translator.py)

---
<div align="center"><small>Разработал и создал с ❤️ Карим Шоаир.</small></div><br>

---

### Benchmarks (`docs/benchmarks.md`)

---
title: "Python HTML Parser Benchmarks: Scrapling and Other Libraries"
description: "See how Scrapling performs in HTML parsing, text extraction and element similarity tests against other popular Python libraries."
---

# Performance Benchmarks

Scrapling isn't just powerful - it's also blazing fast. The following benchmarks compare Scrapling's parser with other popular libraries.

### Text Extraction Speed Test (5000 nested elements)

| # |      Library      | Time (ms) | vs Scrapling | 
|---|:-----------------:|:---------:|:------------:|
| 1 |     Scrapling     |   1.99    |     1.0x     |
| 2 |   Parsel/Scrapy   |   2.06    |    1.035     |
| 3 |     Raw Lxml      |   2.56    |    1.286     |
| 4 |      PyQuery      |   23.98   |     ~12x     |
| 5 |    Selectolax     |  197.02   |     ~99x     |
| 6 |  MechanicalSoup   |  1545.15  |   ~776.5x    |
| 7 |   BS4 with Lxml   |  1562.1  |   ~785.0x    |
| 8 | BS4 with html5lib |  3412.73  |   ~1714.9x   |


### Element Similarity & Text Search Performance

Scrapling's adaptive element finding capabilities significantly outperform alternatives:

| Library     | Time (ms) | vs Scrapling |
|-------------|:---------:|:------------:|
| Scrapling   |   2.3    |     1.0x     |
| AutoScraper |   12.58   |    5.47x    |

> All benchmarks represent averages of 100 timed runs. See [benchmarks.py](https://github.com/D4Vinci/Scrapling/blob/main/benchmarks.py) for methodology.

---

### Changelog (`docs/changelog.md`)

---
title: "Scrapling changelog"
description: "Release notes for Scrapling, including new features, fixes, and breaking changes."
---

# Changelog {#changelog}

All notable changes to Scrapling, taken from the [GitHub releases](https://github.com/D4Vinci/Scrapling/releases).

## [v0.5](https://github.com/D4Vinci/Scrapling/releases/tag/v0.5) - 2026-10-17 {#v0.5}

**Scrapling v0.5 upgrades almost everything: fetching, parsing, spiders, browser automation, AI tools, and docs in ten languages 🚀**

!!! warning "Warning"

    **This release introduces a lot of breaking changes that don't fit here. Check the [Migrating to v0.5 guide](migrating-to-v0.5.md) before updating.**

### 🚀 New Stuff and quality of life changes {#v0.5-new-stuff-and-quality-of-life-changes}

- **A much more capable MCP server for AI agents that can solve almost any CAPTCHA** (Check the [docs](ai/mcp-server.md)):

    - **Complete browser workflows**: fill forms, click, hover, scroll, use the keyboard, handle dialogs, and wait for results in one ordered sequence. Supports different field types and slower interactions, with actions stopping at the first error.
    - **Read and search the current page without reloading it**: extract HTML, Markdown, or text from a whole page or one element. Searchable page snapshots show element roles, names, and positions, with focused views that retain the surrounding context.
    - **Run custom JavaScript and take focused screenshots**: execute scripts, including async work, with access to the page's own JavaScript. Capture individual elements, the viewport, or the full page as PNG or JPEG.
    - **Inspect network activity and reuse logins**: examine recorded requests and responses, save and restore browser login state, and interact with elements inside open or closed Shadow DOM. Read recorded traffic before closing the session.
    - **Use fewer tokens and get clearer errors**: leaner tool descriptions and shared guidance reduce repeated text, while browser and request failures reach agents with useful error messages.

- **See the requests behind the page**. Enable `record_requests=True` to record completed traffic across loads, actions, and tabs, then inspect saved responses without sending requests again. (Check the [docs](fetching/stealthy.md#network-history))

    ```python
    from scrapling.fetchers import StealthySession

    with StealthySession(record_requests=True) as session:
        session.fetch("https://example.com", network_idle=True)
        for response in session.network.search(url_pattern=r"/api/", limit=None):
            print(response.url, response.status, response.body)
    ```

    - Filter by URL, method, resource type, or status; retrieve one response by ID. Inspect headers, sent data, API responses, HTTP errors, and redirects through the usual `Response` API.
    - Retains supported text bodies with size limits, plus metadata and a reason when a body cannot be saved. The default limit is 1,000 requests. Works with sync and async sessions; saved Python history stays readable after close.

- **Save a login once and reuse it across runs**. `save_state(path)` and `load_state(path)` save cookies, local storage, and IndexedDB in Playwright-compatible JSON. Both sync and async browser sessions support them. (Check the [docs](fetching/stealthy.md#save-and-load-session-state))
    - Load state before fetching or reloading a page. Requires a started, shared browser context without `proxy_rotator`; tabs, browser settings, and `sessionStorage` are not saved.

- **Extract open Shadow DOM with `pierce_shadow=True`**, then use CSS or XPath as usual. Available in browser fetchers, sessions, and the CLI's `--pierce-shadow` option. Preserves slot content without changing the live page. HTML capture excludes closed roots and iframe documents. (Check the [docs](fetching/stealthy.md#shadow-dom))

- **Choose how your spider explores a site**. `CrawlSpider` and its subclasses, including `ContentSpider`, support `crawl_strategy="bfs"` for oldest-first or `"dfs"` for newest-first scheduling. Priority still wins, and concurrent pages can finish in a different order. (Check the [docs](spiders/generic-templates.md#crawl-order))

### 🐛 Bug Fixes {#v0.5-bug-fixes}

- **Improved Cloudflare solving** with delayed-widget detection, fewer unnecessary waits, and bounded passive-challenge and hidden-frame retry loops. Fixes [#468](https://github.com/D4Vinci/Scrapling/issues/468) and [#509](https://github.com/D4Vinci/Scrapling/issues/509).
- **Fixed browser startup from an elevated Windows shell**. Fixes [#463](https://github.com/D4Vinci/Scrapling/issues/463).
- **Kept the built-in stealth flags when adding custom browser flags** by @alkaz-nodemaven in [#430](https://github.com/D4Vinci/Scrapling/pull/430).
- **Improved charset parsing for browser responses**, including declarations with different letter case, spaces, or quoted values.
- **Stopped logging the absence of a Cloudflare challenge as an error** when no challenge needs to be solved. Fixes [#459](https://github.com/D4Vinci/Scrapling/issues/459).

- **Corrected request fingerprints** for query parameters by @yetval in [#448](https://github.com/D4Vinci/Scrapling/pull/448), empty or falsy JSON bodies by @ac1982 in [#480](https://github.com/D4Vinci/Scrapling/pull/480), and header insertion order by @SarwadnyaMahajan in [#466](https://github.com/D4Vinci/Scrapling/pull/466).
- **Fixed request data leaking into followed links**, including stale body-related headers, by @yetval in [#462](https://github.com/D4Vinci/Scrapling/pull/462).
- **Prevented blocked responses from being stored as successful development-cache entries** by @Kuang-xianxin in [#446](https://github.com/D4Vinci/Scrapling/pull/446).
- **Preserved checkpoint files when a crawl fails with an exception** by @SulimanAbdulrazzaq in [#486](https://github.com/D4Vinci/Scrapling/pull/486).
- **Corrected robots.txt failure handling** so failed lookups are not cached as permission to crawl, by @prateekraawat1 in [#443](https://github.com/D4Vinci/Scrapling/pull/443).
- **Fixed link extraction with restricted selectors**, including empty matches and selectors that target the link element itself, by @SulimanAbdulrazzaq in [#452](https://github.com/D4Vinci/Scrapling/pull/452) and [#483](https://github.com/D4Vinci/Scrapling/pull/483).
- **Fixed sitemap callback routing** by @SulimanAbdulrazzaq in [#458](https://github.com/D4Vinci/Scrapling/pull/458), **and XML parsing with comments or processing instructions** by @sup3dev in [#450](https://github.com/D4Vinci/Scrapling/pull/450).
- **Handled leading byte-order marks in robots.txt and CSV feeds** by @SulimanAbdulrazzaq in [#453](https://github.com/D4Vinci/Scrapling/pull/453).
- **Fixed `stealthy_headers` handling in spider HTTP sessions**, passing the option to the session instead of directly to `curl_cffi`, by @Yigtwxx in [#475](https://github.com/D4Vinci/Scrapling/pull/475).

- **Fixed dictionary form encoding for list and tuple values**, while preserving request-body precedence and existing `None` handling, with contributions by @SulimanAbdulrazzaq in [#485](https://github.com/D4Vinci/Scrapling/pull/485).
- **Fixed case-insensitive merging of session and per-request HTTP headers** by @SulimanAbdulrazzaq in [#487](https://github.com/D4Vinci/Scrapling/pull/487).
- **Fixed CLI requests silently dropping empty or falsy JSON bodies** by @SulimanAbdulrazzaq in [#484](https://github.com/D4Vinci/Scrapling/pull/484).
- **Made Markdown and text file exports consistently use UTF-8** and prevented conversion errors from truncating an existing output file, by @SulimanAbdulrazzaq in [#488](https://github.com/D4Vinci/Scrapling/pull/488).
- **Fixed `curl2fetcher()` handling of curl's user-agent and proxy options** by @SulimanAbdulrazzaq in [#490](https://github.com/D4Vinci/Scrapling/pull/490).

- **Fixed Markdown blocks running together** when several selected elements are converted through `Response.markdown()` or CLI extraction, with contributions by @Yigtwxx in [#432](https://github.com/D4Vinci/Scrapling/pull/432).
- **Fixed hidden-content cleaning for AI output** to keep visible content such as `opacity:0.95`, recognize more hidden styles, and remove hidden slots, with contributions by @Yigtwxx in [#460](https://github.com/D4Vinci/Scrapling/pull/460).
- **Fixed noise-tag removal stopping early around nested tags** by @Yigtwxx in [#474](https://github.com/D4Vinci/Scrapling/pull/474).
- **Fixed generated CSS and XPath selectors for the first of several same-tag siblings** by @yellow-dog-dog in [#495](https://github.com/D4Vinci/Scrapling/pull/495).
- **Resolved an lxml HTML parser deprecation warning** by @afsuyadi in [#493](https://github.com/D4Vinci/Scrapling/pull/493).

### Docs {#v0.5-docs}

- **The full website now speaks ten languages**: English, Arabic, Spanish, Brazilian Portuguese, French, German, Simplified Chinese, Japanese, Russian, and Korean. Guides, API references, tutorials, and the [changelog](changelog.md) are translated, with Arabic RTL support and language switches that keep your page and section.
- **Clearer guides, README examples, and setup steps**, covering checkpoint data, browser encodings, saved state, network history, Shadow DOM, and crawl order.
- **Updated the Agent Skill**, its examples, references, and downloadable archive for the current browser and MCP tools.
- **Moved the changelog to the website** and added access to each page's Markdown source.

### Project {#v0.5-project}

- Refreshed Scrapling's logo, cover images, and website presentation.
- Expanded tests for browser actions, dialogs, extraction, screenshots, JavaScript, network recording, state files, Shadow DOM, and crawler fixes.
- Added a browser-test marker and separate browser, async, and parallel test runs. Improved Windows checkpoint and CSV test portability by @diegobravtraps-oss in [#457](https://github.com/D4Vinci/Scrapling/pull/457).
- Updated the shared multilingual documentation build setup and contribution guidance.

## [v0.4.15](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.15) - 2026-08-23 {#v0.4.15}

**One of the biggest releases this year: a reworked MCP server, RAG-ready Markdown in one line, an improved Cloudflare solver, and browser tabs that stay open for automation 🚀**

!!! warning "Warning"

    **This release introduces breaking changes to the MCP server. Check the [breaking changes](https://github.com/D4Vinci/Scrapling/blob/v0.4.15/docs/ai/mcp-server.md#breaking-changes) section before updating.**

### 🚀 New Stuff and quality of life changes {#v0.4.15-new-stuff-and-quality-of-life-changes}

- **Browser tabs now stay open and get reused across requests** (Check the [docs](fetching/stealthy.md#session-management)):
    - All browser sessions keep their tabs after a request, and the next request reuses a free tab instead of opening a new one.
    - Every request re-applies its own settings (timeouts, headers, resource blocking) to the tab it gets, so nothing leaks between requests.
    - Tabs that hit an error are closed and replaced, and the new `close_pages()` method closes every open tab.
    - The page you fetched stays loaded, so a `page_setup` function on the next request runs on it before navigating away. That's the building block for chaining automation across requests.

- **Turn any page into clean, LLM-ready Markdown with `Response.markdown()`** (Check the [docs](ai/building-rag-systems.md)):

    ```python
    from scrapling.fetchers import Fetcher

    markdown = Fetcher.get("https://example.com").markdown(main_content_only=True)
    ```

    - Scripts, styles, and hidden prompt-injection content are always stripped first, the same cleaning the MCP server does.
    - Pass `css_selector` to convert only the elements you need.
    - Available through the new `rag` extra (`pip install "scrapling[rag]"`), which the `ai`/`shell`/`all` extras include too.

- **New `SiteToMarkdownSpider` template to crawl a whole website into a Markdown corpus for RAG pipelines** (Check the [docs](ai/building-rag-systems.md)):

    ```python
    from scrapling.spiders import SiteToMarkdownSpider

    class DocsSpider(SiteToMarkdownSpider):
        name = "docs"
        start_urls = ["https://example.com/docs/"]
        allowed_domains = {"example.com"}
        output_dir = "docs_markdown"

    result = DocsSpider().start()
    result.items.to_jsonl("docs.jsonl")
    ```

    - Yields one item per page with `url`/`title`/`markdown`, and the optional `output_dir` writes one Markdown file per page.
    - `max_pages` caps the crawl, and since it builds on `CrawlSpider`, overriding `rules()` gives you full control over which links get followed.

- **The MCP server is reworked (breaking)** (Check the [breaking changes](https://github.com/D4Vinci/Scrapling/blob/v0.4.15/docs/ai/mcp-server.md#breaking-changes) and the [docs](ai/mcp-server.md)):
    - The 13 tools are now split into two modes: one-shot tools (`fetch`, `bulk_fetch`, `stealthy_fetch`, `bulk_stealthy_fetch`) that always launch their own browser and show their real defaults, and session tools that work through a session opened once.
    - The new `session_fetch` tool fetches through a browser session, while `open_session` now holds the browser-level settings only and returns the session's effective settings for the AI agent.
    - The `get` tool is renamed to `make_request`, and it now supports any HTTP method.
    - The new `open_request_session` and `session_make_request` tools give the AI persistent HTTP sessions that keep cookies and the browser fingerprint between requests.
    - This also ends fetches resetting the session's settings, first fixed by @Yigtwxx in [#418](https://github.com/D4Vinci/Scrapling/pull/418).

- **The MCP server's HTTP transport now requires authentication and binds to localhost by default (breaking)** by @yamantaka-singh in [#414](https://github.com/D4Vinci/Scrapling/pull/414) (Fixes [#413](https://github.com/D4Vinci/Scrapling/issues/413), check the [docs](ai/mcp-server.md#authentication)):
    - Pass `--auth-token` (or the `SCRAPLING_MCP_AUTH_TOKEN` environment variable) to require a bearer token, or `--no-auth` to serve it unauthenticated on purpose.
    - Pass `--host 0.0.0.0` to accept connections from the network.

### 🐛 Bug Fixes {#v0.4.15-bug-fixes}

- **Cloudflare Turnstile/Interstitial solving now works regardless of the browser locale, and no longer loops forever on interactive challenges in headless mode**. Stealth pages also stop crashing mid-solve, with contributions by @subediparas5 in [#412](https://github.com/D4Vinci/Scrapling/pull/412). (Fixes [#411](https://github.com/D4Vinci/Scrapling/issues/411) and [#422](https://github.com/D4Vinci/Scrapling/issues/422))
- **Fixed `find`/`find_all` with `class_` silently missing multi-class elements** by @yetval in [#410](https://github.com/D4Vinci/Scrapling/pull/410), **and blank `class_` values and unescaped CSS string values** by @yamantaka-singh in [#417](https://github.com/D4Vinci/Scrapling/pull/417).
- **Fixed cached responses in `development_mode` losing the request meta on replay** by @Yigtwxx in [#419](https://github.com/D4Vinci/Scrapling/pull/419).
- **Fixed HTTP requests with `retries` below 1 failing without sending the request** by @Yigtwxx in [#420](https://github.com/D4Vinci/Scrapling/pull/420).

### Docs {#v0.4.15-docs}

- **The website sections are restructured**: a new "Using with AI" section holds the MCP server, the new [Agent skill](ai/agent-skill.md) page, and the [Building RAG systems](ai/building-rag-systems.md) guide, and the BeautifulSoup migration guide moved next to the Scrapy integration under "Integrations and migrations".
- **Added a [changelog](changelog.md)** to the repository with the notes of every release so far.

## [v0.4.14](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.14) - 2026-08-10 {#v0.4.14}

**A quick maintenance release to fix installation with `uv` 🔧**

### 🐛 Bug Fixes {#v0.4.14-bug-fixes}

- **Fixed `uv` refusing to install v0.4.13 by default and silently falling back to an older version**. The previous release required a prerelease version of `curl_cffi`, which `uv` doesn't allow unless explicitly enabled.
All dependencies now resolve to stable releases. (Fixes [#407](https://github.com/D4Vinci/Scrapling/issues/407))

## [v0.4.13](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.13) - 2026-08-09 {#v0.4.13}

**A new update bringing feed spiders and a smarter MCP server 🎉**

### 🚀 New Stuff and quality of life changes {#v0.4.13-new-stuff-and-quality-of-life-changes}

- **New feed spider templates**. `XMLFeedSpider` iterates over the nodes of any XML feed (RSS, Atom, product feeds, etc.), and `CSVFeedSpider` iterates over CSV rows as dictionaries. Both decompress gzipped feeds automatically. (Check the [docs](spiders/generic-templates.md))

  ```python
  from scrapling.spiders import XMLFeedSpider

  class RSSSpider(XMLFeedSpider):
      name = "rss"
      start_urls = ["https://example.com/feed.xml"]

      async def parse_node(self, response, node):
          yield {"title": node.findtext("title"), "link": node.findtext("link")}

  result = RSSSpider().start()
  ```

- **Upgraded the MCP server to MCP SDK v2 and made it smarter**. The server now ships instructions that teach your AI agent how to use the tools efficiently; every tool declares annotations so clients like Claude Code can auto-approve the read-only ones; tool descriptions are leaner to save tokens; and the server advertises its version and logo to MCP clients. (Check the [docs](ai/mcp-server.md))
- **Added a `scrapling-mcp` command** that maps directly to `scrapling mcp`, so registering Scrapling with MCP clients and registries that expect a single command is now a one-liner.
- **Unpinned Playwright/Patchright and browser versions**. The generated browser User-Agent now always matches the exact Chromium version your installed Playwright/Patchright drives, so Scrapling no longer pins their versions and you can upgrade them freely. Run `scrapling install --force` after updating to refresh the browsers.

### 🐛 Bug Fixes {#v0.4.13-bug-fixes}

- **Fixed importing Scrapling crashing with a `browserforge` ValueError** when the fingerprints data package lags behind the browser versions. (Fixes [#394](https://github.com/D4Vinci/Scrapling/issues/394), [#396](https://github.com/D4Vinci/Scrapling/issues/396), and [#400](https://github.com/D4Vinci/Scrapling/issues/400))
- **Fixed the MCP bulk browser tools mis-sizing their page pools**, which made `bulk_fetch` fail on batches of more than 50 URLs and `bulk_stealthy_fetch` fetch all URLs through a single tab, by @Yigtwxx in [#393](https://github.com/D4Vinci/Scrapling/pull/393).

### Project {#v0.4.13-project}

- **New [AI Contribution Policy](https://github.com/D4Vinci/Scrapling/blob/main/AI_POLICY.md)**: AI-assisted contributions are welcome but must be disclosed in the PR or issue; submissions that look like undisclosed AI output get labeled and closed.

## [v0.4.12](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.12) - 2026-07-26 {#v0.4.12}

**A release focused on making your spiders smarter about the websites they crawl**

### 🚀 New Stuff and quality of life changes {#v0.4.12-new-stuff-and-quality-of-life-changes}

- **Spiders can now tune their own speed with AutoThrottle.** Instead of guessing a `download_delay` that's either too slow or gets you banned, the spider measures how fast each website answers and adjusts the delay of every domain on its own. When a website starts blocking or rate-limiting you, it doubles the delay (or waits exactly what the `Retry-After` header asks for) until that stops, then speeds back up. Your `download_delay` and any robots.txt `Crawl-delay` are still respected as the minimum. (Check the [docs](spiders/advanced.md#autothrottle))

    ```python
    class MySpider(Spider):
        name = "adaptive"
        start_urls = ["https://example.com"]
        autothrottle_enabled = True
        autothrottle_start_delay = 2.0
        autothrottle_max_delay = 30.0
        autothrottle_block_backoff = True
    ```

- **Export your results to CSV and XML**, next to the JSON/JSONL exporters you already had. Items that don't all share the same keys are still exported without losing anything, and nested values are written as JSON. (Check the [docs](spiders/getting-started.md))

    ```python
    result = MySpider().start()
    result.items.to_csv("products.csv")
    result.items.to_xml("products.xml")
    ```

- **The MCP server can now require authentication**, so you can safely expose it instead of keeping it on your own machine. Any request without the token is rejected, and you can also restrict which hostnames the server answers to. (Check the [docs](ai/mcp-server.md))

    ```bash
    scrapling mcp --http --auth-token "$(openssl rand -hex 32)"
    ```

- **Browsers now accept CDP URLs over HTTP**, not just WebSocket ones. So next to the `wss://` endpoints managed browser providers hand out, you can now point any browser fetcher or MCP session at a Chrome you started yourself with `--remote-debugging-port=9222`.

- **Published Docker images are now tagged with their release version** instead of only `latest`, so you can pin the exact version you want, by @JanRK in [#384](https://github.com/D4Vinci/Scrapling/pull/384).

### 🐛 Bug Fixes {#v0.4.12-bug-fixes}

- **Fixed cached responses losing all their cookies** when the response came from a browser engine, which silently broke any session or auth logic relying on them while using the spiders' development mode, by @amitvijapur in [#379](https://github.com/D4Vinci/Scrapling/pull/379). (Fixes [#376](https://github.com/D4Vinci/Scrapling/issues/376))

- **Fixed `StealthyFetcher` forcing the `en-US` locale** on every browser instead of following your system's, which made websites see a mismatch between your locale and your IP address and treat you as suspicious, like Google answering with 429s. (Fixes [#381](https://github.com/D4Vinci/Scrapling/issues/381))

- **Fixed a misleading error message in the storage system** and removed a dead call left after inserts, by @fix2015 in [#377](https://github.com/D4Vinci/Scrapling/pull/377).

### Performance {#v0.4.12-performance}

- **`get_all_text()` is now O(nodes)** instead of walking up the ancestors of every single text node, which makes it around 5-6x faster on deeply nested pages, by @yetval in [#378](https://github.com/D4Vinci/Scrapling/pull/378).

## [v0.4.11](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.11) - 2026-07-12 {#v0.4.11}

**A solid update bringing the first platform spider template, a faster parser, and important fixes 🎉**

### 🚀 New Stuff and quality of life changes {#v0.4.11-new-stuff-and-quality-of-life-changes}

- **Added `ShopifySpider`, the first platform spider template!** Extract every product from any Shopify-powered store through its JSON API without touching the website's HTML. Subclass it, set the store's domain, and you are done (Check the [docs](spiders/platform-templates.md))

  ```python
  from scrapling.spiders import ShopifySpider

  class MyStore(ShopifySpider):
      target_website = "example.com"

  result = MyStore().start()
  ```

- **Added `--executable-path` to the CLI browser commands**. Both `scrapling extract fetch` and `scrapling extract stealthy-fetch` now accept a custom Chromium-compatible browser executable, and fall back to the `SCRAPLING_EXECUTABLE_PATH` environment variable when the option isn't passed, bringing full parity with the MCP server (Solves [#371](https://github.com/D4Vinci/Scrapling/issues/371))

  ```bash
  scrapling extract fetch "https://example.com" page.html --executable-path "/path/to/chromium"
  ```

### 🤖 Quality of life changes {#v0.4.11-quality-of-life-changes}
- **Made `find_by_text` and `find_by_regex` up to ~2x faster** when `first_match` is enabled (the default) by wrapping elements lazily so the search stops at the first match, by @yetval in [#370](https://github.com/D4Vinci/Scrapling/pull/370)
- **Updated the benchmarks with the new numbers against the latest versions of all libraries.**
- **Updated contribution rules**

### 🐛 Bug Fixes {#v0.4.11-bug-fixes}

- **Fixed the MCP server's fetch tools crashing on pages containing control characters** with the error `All strings must be XML compatible`, by @yetval in [#368](https://github.com/D4Vinci/Scrapling/pull/368) (Fixes [#366](https://github.com/D4Vinci/Scrapling/issues/366))

## [v0.4.10](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.10) - 2026-07-04 {#v0.4.10}

**A new update with a brand-new Scrapy integration and a batch of community fixes 🎉**

### 🚀 New Stuff and quality of life changes {#v0.4.10-new-stuff-and-quality-of-life-changes}

- **Added a Scrapy integration** so you can use Scrapling's parsing API inside your existing Scrapy projects without rewriting them. Put the `scrapling_response` decorator on any spider callback, and the response it receives becomes a Scrapling `Response` while Scrapy keeps handling the crawling (Check the [docs](integrations/scrapy.md)):

    ```python
    import scrapy
    from scrapling.integrations.scrapy import scrapling_response

    class QuotesSpider(scrapy.Spider):
        name = "quotes"
        start_urls = ["https://quotes.toscrape.com"]

        @scrapling_response
        def parse(self, response):  # `response` is now a Scrapling Response
            first_quote = response.find_by_text("The world as we have created it", partial=True)
            for quote in [first_quote, *first_quote.find_similar()]:
                yield {"text": quote.get_all_text(strip=True)}
    ```

- **The MCP server can now use a custom Chromium-compatible browser** for all browser-based tools. Set it once with `scrapling mcp --executable-path "/path/to/chromium"` or the `SCRAPLING_EXECUTABLE_PATH` environment variable, or per request with the `executable_path` argument, by @samrusani in [#360](https://github.com/D4Vinci/Scrapling/pull/360) (Solves [#347](https://github.com/D4Vinci/Scrapling/issues/347))
- **Updated all browsers and fingerprints**. Run `scrapling install --force` after updating to refresh them.

### 🐛 Bug Fixes {#v0.4.10-bug-fixes}

- **Fixed garbled text (mojibake) from browser fetchers on non-UTF-8 websites** by @yehudalevy-collab in [#365](https://github.com/D4Vinci/Scrapling/pull/365) (Fixes [#364](https://github.com/D4Vinci/Scrapling/issues/364)).
- **Fixed `LinkExtractor` not filtering compound file extensions like `.tar.gz`** by @renbkna in [#359](https://github.com/D4Vinci/Scrapling/pull/359) (Fixes [#349](https://github.com/D4Vinci/Scrapling/issues/349)).
- **Fixed paused crawls losing their in-flight requests from checkpoints, so resuming no longer skips them** by @yetval in [#358](https://github.com/D4Vinci/Scrapling/pull/358).
- **Fixed spiders calculating wrong crawl delays from robots.txt `Request-rate` directives** through the Protego upgrade, with tests aligned by @Disaster-Terminator in [#355](https://github.com/D4Vinci/Scrapling/pull/355).

### Docs {#v0.4.10-docs}

- **Clarified how `init_script` interacts with Patchright's isolated execution context in stealth mode** by @mturac in [#353](https://github.com/D4Vinci/Scrapling/pull/353) (Solves [#350](https://github.com/D4Vinci/Scrapling/issues/350)).
- **Added the [skills.sh](https://skills.sh/D4Vinci/Scrapling) install method for the agent skill** by @ob-aion in [#363](https://github.com/D4Vinci/Scrapling/pull/363).

## [v0.4.9](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.9) - 2026-06-07 {#v0.4.9}

**A maintenance update packed with community-reported fixes 🛠️**

### 🚀 New Stuff and quality of life changes {#v0.4.9-new-stuff-and-quality-of-life-changes}

- **Updated all browsers and fingerprints**. Run `scrapling install --force` after updating to refresh them.
- **Added a `--version` flag to the CLI** by @ETM-Code in [#303](https://github.com/D4Vinci/Scrapling/pull/303) (Solves [#299](https://github.com/D4Vinci/Scrapling/issues/299))

### 🐛 Bug Fixes {#v0.4.9-bug-fixes}

- **Fixed the session-level `proxy` argument being silently ignored in HTTP sessions**, which could leak your real IP (Solves [#295](https://github.com/D4Vinci/Scrapling/issues/295)). Note that mixing a session-level `proxy` with a per-request `proxies` argument (or vice versa) now raises an error instead of one being silently dropped.
- **Fixed browser navigations failing when combining `init_script` with `user_data_dir`** (Solves [#294](https://github.com/D4Vinci/Scrapling/issues/294)).
- **Fixed encoding detection when websites quote the charset value in the `Content-Type` header** by @Bortlesboat in [#323](https://github.com/D4Vinci/Scrapling/pull/323).
- **Fixed an `IndexError` in adaptive element relocation when `auto_save` is enabled** by @Mubashirrrr in [#340](https://github.com/D4Vinci/Scrapling/pull/340).
- **Fixed spiders' checkpoint and cache saving crashing on Windows** by @MrStarkEG in [#344](https://github.com/D4Vinci/Scrapling/pull/344).
- **Fixed incorrect similarity scoring in `find_similar` for elements with mismatched attribute counts** (Solves [#322](https://github.com/D4Vinci/Scrapling/issues/322)).

### Docs {#v0.4.9-docs}

- **Clarified that the default installation includes the parser engine only**, and the fetchers/spiders need the extras (Solves [#343](https://github.com/D4Vinci/Scrapling/issues/343)).
- **Fixed the Docker image name in the remaining examples** by @evanclan in [#315](https://github.com/D4Vinci/Scrapling/pull/315).
- **Fixed a broken link in the contribution guide** by @Bortlesboat in [#320](https://github.com/D4Vinci/Scrapling/pull/320).

## [v0.4.8](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.8) - 2026-05-11 {#v0.4.8}

**A big spider update that takes the crawling framework to the next level 🕷️**

### 🚀 New Stuff and quality of life changes {#v0.4.8-new-stuff-and-quality-of-life-changes}

- **Added a `LinkExtractor` primitive** in `scrapling.spiders.LinkExtractor` to pull URLs out of a `Response`. There are a lot of controls (Check the [docs](spiders/generic-templates.md))

    ```python
    from scrapling.spiders import LinkExtractor

    extractor = LinkExtractor(allow=r"/posts/", deny_domains=["ads.example.com"])
    ```

- **Added `CrawlSpider` and `CrawlRule`** generic spider templates so you no longer have to hand-write the same "follow links matching this pattern" boilerplate. Override `rules()` to return a list of `CrawlRule` objects, each pairing a `LinkExtractor`. (Check the [docs](spiders/generic-templates.md))

    ```python
    from scrapling.spiders import CrawlSpider, CrawlRule, LinkExtractor

    class QuotesSpider(CrawlSpider):
        name = "blog"
        start_urls = ["https://quotes.toscrape.com/"]

        def rules(self):
            return [
                CrawlRule(LinkExtractor(allow=r"/author/"), callback=self.parse_author),
                CrawlRule(LinkExtractor(allow=r"/page/\d+/")),  # pagination, no callback
            ]

        async def parse_author(self, response):
            yield {
                "name": response.css(".author-title::text").get(),
                "birthday": response.css(".author-born-date::text").get(),
                "url": response.url,
            }
    ```

- **Added a `SitemapSpider` template** that seeds a crawl directly from a sitemap, or `robots.txt` URLs. Handles gzip-compressed sitemaps, and a lot of controls and options. URLs are dispatched via the crawl rules as shown above for **CrawlSpider**. (Check the [docs](spiders/generic-templates.md))

    ```python
    from scrapling.spiders import SitemapSpider, CrawlRule, LinkExtractor

    class NewsSitemap(SitemapSpider):
        name = "news"
        sitemap_urls = ["https://example.com/robots.txt"]

        def rules(self):
            return [
                CrawlRule(LinkExtractor(allow=r"/articles/"), callback=self.parse_article),
            ]

        async def parse_article(self, response):
            yield {"url": response.url, "title": response.css("h1::text").get()}
    ```

- **Adaptive relocation now defaults to a 40% similarity threshold** instead of `0` across all methods. This will make the adaptive feature work better. When nothing crosses the threshold, a warning now tells you the top score it did see, so you can lower `percentage` deliberately if needed.

- **Updated all browsers and fingerprints**. Run a new `scrapling install  --force` after updating to refresh the browsers and fingerprints.

### 🐛 Bug Fixes {#v0.4.8-bug-fixes}

- **Fixed `Fetcher.configure(...)` not applying to per-request calls**. Same fix applied to `AsyncFetcher`.
- **Fixed incorrect request fingerprinting that caused duplicate requests in spiders** by @yetval in [#255](https://github.com/D4Vinci/Scrapling/pull/255).
- **Fixed the Adaptive scraping engine staying silent on weak matches.** Combined with the threshold change above, you now get a warning instead of a misleading "best guess" element when relocation fails.

### Docs {#v0.4.8-docs}

- **Refreshed older code examples** across the documentation to match the current version.
- **Improved the code copy-paste experience** on the docs site and trimmed the agent skill so it uses fewer tokens per invocation.

## [v0.4.7](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.7) - 2026-04-17 {#v0.4.7}

**A focused update bringing eyes to your AI agents 📸**

### 🚀 New Stuff and quality of life changes {#v0.4.7-new-stuff-and-quality-of-life-changes}

- **Added a `screenshot` MCP tool** that captures a page and returns it as a real MCP `ImageContent` block so the model can actually see it. The tool requires an open browser session, so you call `open_session` first (either `dynamic` or `stealthy`) and pass the `session_id` here. Supports PNG and JPEG, full-page captures, JPEG quality, and the usual readiness controls (`wait`, `wait_selector`, `network_idle`, `timeout`). (implements [#244](https://github.com/D4Vinci/Scrapling/issues/244))
- **Added a custom `session_id` parameter to `open_session`** so you can name sessions meaningfully (`"search"`, `"checkout"`) instead of the random 12-character hex default. By @hauntedhost in [#243](https://github.com/D4Vinci/Scrapling/pull/243)

### 🐛 Bug Fixes {#v0.4.7-bug-fixes}

- **Fixed `FetcherSession` state corruption and a lazy session close crash**. By @yetval in [#245](https://github.com/D4Vinci/Scrapling/pull/245)
- **Fixed `TypeError: Session.request() got an unexpected keyword argument 'block_ads'`** when using the CLI's `--ai-targeted` flag with HTTP commands. By @voidborne-d in [#249](https://github.com/D4Vinci/Scrapling/pull/249) (Fixes [#247](https://github.com/D4Vinci/Scrapling/issues/247))

### Translations {#v0.4.7-translations}

- **Added a Brazilian Portuguese README translation** By @rgomids in [#250](https://github.com/D4Vinci/Scrapling/pull/250)

## [v0.4.6](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.6) - 2026-04-13 {#v0.4.6}

**A focused update on browser stealth, privacy, and developer experience 🔒**

### 🚀 New Stuff and quality of life changes {#v0.4.6-new-stuff-and-quality-of-life-changes}

- **Added built-in ad blocking** for browser fetchers. Pass `block_ads=True` to block requests to ~3,500 known ad and tracker domains at the route interception level -- no DNS, no TCP, instant abort. Can be combined with `blocked_domains` for custom lists. The MCP server and CLI `--ai-targeted` mode enable this automatically to save tokens and speed up page loads.

    ```python
    page = StealthyFetcher.fetch('https://example.com', block_ads=True)
    ```

- **Added DNS-over-HTTPS support** to prevent DNS leaks when using proxies. Pass `dns_over_https=True` to route DNS queries through Cloudflare's DoH, so your real location isn't exposed through DNS resolution even when your HTTP traffic goes through a proxy.

    ```python
    page = StealthyFetcher.fetch('https://example.com', proxy='http://proxy:8080', dns_over_https=True)
    ```

- **Added `page_setup` callback** for browser fetchers. A function that runs before `page.goto()`, letting you register event listeners, routes, or scripts that must be set up before the page navigates. Pairs with `page_action` (which runs after navigation). (Solves [#237](https://github.com/D4Vinci/Scrapling/issues/237))

    ```python
    def capture_websockets(page):
        page.on("websocket", lambda ws: print(f"WS: {ws.url}"))

    page = DynamicFetcher.fetch('https://example.com', page_setup=capture_websockets)
    ```

- **Added `--block-ads` and `--dns-over-https` CLI options** to both `fetch` and `stealthy-fetch` commands.

### 🐛 Bug Fixes {#v0.4.6-bug-fixes}

- **Fixed `Seconds` type alias** rejecting float values. Passing `wait=1.5` or `timeout=500.0` to browser fetchers would fail with a type error because the type alias incorrectly treated `float` as metadata instead of a type. by @kuishou68 in [#240](https://github.com/D4Vinci/Scrapling/pull/240)
- **Fixed duplicate ID segments in full-path selector generation**. Elements with `id` attributes had their selector appended twice when generating full CSS/XPath paths, producing selectors like `body > #main > #main > #target > #target`. Also fixed full-path XPath emitting bare `[@id='x']` predicates (invalid XPath) instead of `*[@id='x']`. by @sjhddh in [#241](https://github.com/D4Vinci/Scrapling/pull/241)
- **Fixed missing shell signature parameters**. The interactive shell was missing `blocked_domains`, `block_ads`, `retries`, `retry_delay`, `capture_xhr`, `executable_path`, and `dns_over_https` from its function signatures.

## [v0.4.5](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.5) - 2026-04-07 {#v0.4.5}

**A focused update with one big quality-of-life feature for spider developers and a couple of important fixes 🎉**

### 🚀 New Stuff and quality of life changes {#v0.4.5-new-stuff-and-quality-of-life-changes}

- **Spider Development Mode**: Iterating on a spider's `parse()` logic used to mean re-hitting the target servers on every run, which is slow, noisy, and a great way to get rate-limited while you're still figuring out your selectors. The new development mode caches every response to disk on the first run and replays them from disk on every subsequent run, so you can tweak your callbacks and re-run as many times as you want without making a single network request. Enable it with one class attribute:

    ```python
    class MySpider(Spider):
        name = "my_spider"
        start_urls = ["https://example.com"]
        development_mode = True

        async def parse(self, response):
            yield {"title": response.css("title::text").get("")}
    ```

    The cache lives in `.scrapling_cache/{spider.name}/` by default and can be redirected anywhere with `development_cache_dir`. Two new stat counters, `cache_hits` and `cache_misses`, let you see how the cache performed. Cache replay bypasses `download_delay`, rate limiting, and the blocked-request retry path so iteration is as fast as the disk allows. Don't ship a spider with `development_mode = True` -- it's a development tool, not a production cache. See the [docs](spiders/advanced.md#development-mode) for the full story.

- **Safer redirects by default**: `follow_redirects` now defaults to `"safe"` across all HTTP fetchers, the MCP server, and the shell. Redirects are still followed, but ones targeting internal/private IPs (loopback, private networks, link-local) are rejected. This protects you from SSRF when scraping user-supplied URLs. Pass `follow_redirects="all"` to get the old behavior, or `False` to disable redirects entirely.

### 🐛 Bug Fixes {#v0.4.5-bug-fixes}

- **Force-stop no longer loses your checkpoint**: Pressing Ctrl+C twice (force-stop) on a spider with `crawldir` enabled used to race against the checkpoint write -- the cancel scope would tear down the task before the pickle finished, leaving `paused=False` and triggering the cleanup path that *deletes* the previous checkpoint. The result was that force-stopping a long crawl could lose all the progress you were trying to save. The engine now writes the checkpoint **before** calling `cancel_scope.cancel()`, so a force-stop always preserves the latest pending state. By @voidborne-d in [#230](https://github.com/D4Vinci/Scrapling/pull/230).

## [v0.4.4](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.4) - 2026-04-05 {#v0.4.4}

**A new update with important spider improvements and bug fixes 🎉**

### 🚀 New Stuff and quality of life changes {#v0.4.4-new-stuff-and-quality-of-life-changes}
- **Added robots.txt compliance to the Spider framework** with a new `robots_txt_obey` option. When enabled, the spider will automatically fetch and respect robots.txt rules before crawling, including `Disallow`, `Crawl-delay`, and `Request-rate` directives. Robots.txt files are fetched concurrently and cached per domain for the entire crawl. By @AbdullahY36 in [#226](https://github.com/D4Vinci/Scrapling/pull/226)
- **Added robots.txt cache pre-warming** so all start_urls domains have their robots.txt fetched and parsed before the crawl loop begins, avoiding delays on the first request to each domain.
- **Added a new `robots_disallowed_count` stat** to `CrawlStats` to track how many requests were blocked by robots.txt rules during a crawl.

Check it out on the website from [here](spiders/getting-started.md#robotstxt-compliance)

### 🐛 Bug Fixes {#v0.4.4-bug-fixes}
- **Fixed a critical MRO issue with `ProxyRotator`** where the `_build_context_with_proxy` stub was shadowing the real implementation from child classes, causing proxy rotation to always raise `NotImplementedError` (Fixes [#215](https://github.com/D4Vinci/Scrapling/issues/215)). Thanks @yetval
- **Fixed a page pool leak** when using per-request proxy rotation with browser sessions. Pages created inside temporary contexts were not removed from the pool on cleanup, leading to stale references accumulating over time. By @yetval in [#223](https://github.com/D4Vinci/Scrapling/pull/223)
- **Fixed a missing type assertion** in the static fetcher where `curl_cffi` could return `None` from `session.request()`, causing downstream errors.

### Other {#v0.4.4-other}
- Updated dependencies, so expect the latest fingerprints and other stuff.
- Added `protego` as a new dependency under the `fetchers` optional group for robots.txt parsing.

## [v0.4.3](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.3) - 2026-03-30 {#v0.4.3}

**A new update with many important changes 🎉**

### 🚀 New Stuff and quality of life changes {#v0.4.3-new-stuff-and-quality-of-life-changes}
- **Added a new MCP tool** to open a persistent normal/stealthy browser to keep using it with the rest of the tools, and another new tool to close it. ([Examples](https://github.com/D4Vinci/Scrapling/blob/v0.4.3/docs/ai/mcp-server.md#examples))
- **Added a new MCP tool** to list all existing browser sessions. Aimed to be used with the new tools.
- **Added a new option to browser sessions** to automatically collect all background requests that happen during a request (Solves [#159](https://github.com/D4Vinci/Scrapling/pull/159)) [[Examples](https://github.com/D4Vinci/Scrapling/blob/v0.4.3/docs/fetching/dynamic.md#capturing-xhrfetch-requests)].
- **Added a new sanitizer** to protect the MCP server from common Prompt Injection attacks by removing hidden/invisible content.
- **Added a new commandline option** called `--ai-targeted` to the Web Scraping commands to make content targeted to AI and safe against common Prompt Injection attacks like the MCP server.
- **Added a new option to browser sessions** called `executable_path` to allow setting a custom browser path (Solves [#202](https://github.com/D4Vinci/Scrapling/pull/202))
- **Refactored** the MCP server code to be easily maintained and unified all tools to be async.
- **Refactored** the CLI commands code to be easily maintained and shorter by 210 lines.

### 🐛 Bug Fixes {#v0.4.3-bug-fixes}
- A fix to preserve HTTP method across retries in spider session by @karesansui-u in [#201](https://github.com/D4Vinci/Scrapling/pull/201)
- Added a max retry limit to getting page content to prevent infinite loop by @haosenwang1018 & @D4Vinci in [#197](https://github.com/D4Vinci/Scrapling/pull/197)
- Replace bare `raise` with `return False` in `_restore_from_checkpoint` by @haosenwang1018 in [#196](https://github.com/D4Vinci/Scrapling/pull/196)
- Replaced `get_all` with `getall` in `Texthandler` to match the Selector class.

### Coverage/tests improvement {#v0.4.3-coverage-tests-improvement}
- Added `_normalize_credentials` edge case coverage tests by @Bortlesboat in [#192](https://github.com/D4Vinci/Scrapling/pull/192)
- Added save/retrieve round-trip and core storage coverage tests by @haosenwang1018 in [#193](https://github.com/D4Vinci/Scrapling/pull/193)
- Added coverage for `TextHandler` regex paths and `TextHandlers.re()` by @haosenwang1018 in [#194](https://github.com/D4Vinci/Scrapling/pull/194)
- Added edge case tests for `filter`, `iterancestors`, and `find_similar` by @awanawana in [#200](https://github.com/D4Vinci/Scrapling/pull/200)

### Agent Skill improvement {#v0.4.3-agent-skill-improvement}
- Fixed broken markdown links in skill references by @yetval in [#204](https://github.com/D4Vinci/Scrapling/pull/204)
- Improved the skill structure to be more acceptable by [Clawhub](https://clawhub.ai/d4vinci/scrapling-official) validation.
- Forced the skill to use the `--ai-targeted` commandline option when scraping through commandline commands.

### Docs improvement {#v0.4.3-docs-improvement}
- Added Korean README translation by @greatsk55 in [#187](https://github.com/D4Vinci/Scrapling/pull/187)
- CJK Latin spacing fixes for the Chinese and Japanese READMEs.
- Fixed broken links from the old website design.

## [v0.4.2](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.2) - 2026-03-08 {#v0.4.2}

**A new maintenance update with important changes**

#### Bug fixes {#v0.4.2-bug-fixes}
- The function `get_all_text()` now captures tail text nodes. This will make the MCP server and commands see text that was missed before ([#168](https://github.com/D4Vinci/Scrapling/pull/168)). Thanks @mhillebrand
- Referer now returns a bare Google url instead of a Google search URL. The previous logic was incorrect and may have produced a fingerprinting signal ([#179](https://github.com/D4Vinci/Scrapling/pull/179)). Thanks @Bortlesboat
- Fixed an issue with extra flags concatenation in all browsers. Thanks @rostchri
- Fixed a type hints issue with Python versions below 3.12 that caused it to crash. (Solves [#163](https://github.com/D4Vinci/Scrapling/issues/163))

#### Other {#v0.4.2-other}
- Added an Agent Skill for Claude Code / OpenClaw and other AI agentic tools.
- Added the Agent Skill to Clawhub.
- Updates all browsers and Playwright versions to the latest.
- Added a French translation to the main README file.

## [v0.4.1](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4.1) - 2026-02-27 {#v0.4.1}

**A new update with many important changes**

### 🚀 New Stuff and quality of life changes {#v0.4.1-new-stuff-and-quality-of-life-changes}
- **Improved regex precision** for Cloudflare challenge detection (Thanks to @Rinz27 [#133](https://github.com/D4Vinci/Scrapling/pull/133))
- **Improved the speed and efficiency** of the Cloudflare solver. Now it is nearly twice as fast.
- **Improved the Cloudflare solver** to handle the case where websites sometimes show the Cloudflare page twice before redirecting to the main website.
- **Improved the stealthy browser**'s stealth mode and speed by removing the injected JS files.
- **Improved the MCP schema** to be acceptable by OpenCode (Thanks to @robin-ede [#137](https://github.com/D4Vinci/Scrapling/pull/137))
- **Made the MCP schema even more MCP-friendly** to be accepted by VS Code Copilot and other strict tools. (Solves #150 )
- **Improved the MCP server tokens consumption** by a large margin through stripping useless HTML tags while the `main_content_only` option is activated.
- Fixed the PyPI page and added the files to register the MCP server to the MCP servers registry.
- Added a new code snippet to show how to install the browsers deps through code instead of using the commandline to allow easier automation.
- Improved all workflows by using the latest actions versions (Thanks to @salmanmkc [#143](https://github.com/D4Vinci/Scrapling/pull/143)/[#144](https://github.com/D4Vinci/Scrapling/pull/144))

## [v0.4](https://github.com/D4Vinci/Scrapling/releases/tag/v0.4) - 2026-02-15 {#v0.4}

**The biggest release of Scrapling yet - introducing the Spider framework, proxy rotation, and major parser improvements**

This release brings a fully async spider/crawling framework, intelligent proxy management, and significant API changes that make Scrapling more powerful and consistent. Please review the breaking changes section carefully before upgrading.

### 🕷️ Spider Framework {#v0.4-spider-framework}

A new async crawling framework built on top of `anyio` for structured, large-scale scraping:

```python
from scrapling.spiders import Spider, Response

class MySpider(Spider):
  name = "demo"
  start_urls = ["https://example.com/"]

  async def parse(self, response: Response):
      for item in response.css('.product'):
          yield {"title": item.css('h2::text').get()}

MySpider().start()
```

-  **Scrapy-like Spider API**: Define spiders with `start_urls`, async `parse` callbacks, `Request`/`Response` objects, and priority queue.
- **Concurrent Crawling**: Configurable concurrency limits, per-domain throttling, and download delays.
- **Multi-Session Support**: Unified interface for HTTP requests, and stealthy headless browsers in a single spider - route requests to different sessions by ID. Supports lazy session initialization.
- **Pause & Resume**: Checkpoint-based crawl persistence. Press Ctrl+C to gracefully shut down; then restart to resume from where you left off.
- **Streaming Mode**: Stream scraped items as they arrive via `async for item in spider.stream()` with real-time stats - ideal for UI, pipelines, and long-running crawls.
- **Blocked Request Detection**: Automatic detection and retry of blocked requests with customizable logic.
- **Built-in Export**: Export results through hooks and your own pipeline or the built-in JSON/JSONL with `result.items.to_json()` / `result.items.to_jsonl()` respectively.
- **Lifecycle hooks**: `on_start()`, `on_close()`, `on_error()`, `on_scraped_item()`, and more hooks for full control over the crawl lifecycle.
- **Detailed crawl stats**: track requests, responses, bytes, status codes, proxies, per-domain/session breakdowns, log level counts, and more.
- **uvloop support**: Pass `use_uvloop=True` to `spider.start()` for faster async execution when available.

A new section has been added to the website with the Full details. Click [here](spiders/architecture.md)

### 🔄 Proxy Rotation {#v0.4-proxy-rotation}

* New `ProxyRotator` class with thread-safe rotation. Works with all fetchers and sessions:

  ```python
  from scrapling import ProxyRotator
  rotator = ProxyRotator(["http://proxy1:8080", "http://proxy2:8080"])
  Fetcher.get(url, proxy_rotator=rotator)
  ```

* **Custom rotation strategies**: Make your own proxy rotation logic
* **Per-request proxy override**: Pass `proxy=` to any individual `get()`/`post()`/`fetch()` call to override the session proxy for that request.

### 🌐 Browser Fetcher Improvements {#v0.4-browser-fetcher-improvements}

* **Domain blocking**: New `blocked_domains` parameter on `DynamicFetcher`/`StealthyFetcher` to block requests to specific domains (subdomains matched automatically).
* **Automatic retries**: Browser fetchers now retry on failure with `retries` (default: 3) and `retry_delay` (default: 1s) parameters. Includes proxy-aware error detection.
* **Response metadata**: `Response.meta` dict automatically stores the proxy used, and merges request metadata.
* **Response.follow()**: Create follow-up `Request` objects with automatic referer flow, designed for the spider system.
* **No autoplay**: Browser sessions are now blocking autoplay content, which caused issues before.
* **Speed**: Improved stealth and speed by adjusting browser flags.

### 🔧 Bug Fixes & Improvements {#v0.4-bug-fixes-improvements}
- **Parser optimization**: Optimized the parser for repeated operations, improving performance.
- **Errored pages**: Fixed a bug that caused the browser to not close when pages gave errors.
- **Empty body**: Handle responses with empty body.
- **Playwright loop**: Solving an issue with leaving the Playwright loop open when CDP connection fails
- **Type safety**: Fixed all mypy errors and added type hints across untyped function bodies. Added mypy and pyright to the CI workflow.

### ⚠️ Breaking Changes {#v0.4-breaking-changes}

* **`css_first`/`xpath_first` removed**: Use `css('.selector').first`, `css('.selector')[0]`, or `css('.selector').get()` instead.
* **All selection now returns `Selectors`**: `css('::text')`, `xpath('//text()')`, `css('::attr(href)')`, and `xpath('//@href')` now return `Selectors` (wrapping text nodes in `Selector` objects with `tag="#text"`) instead of `TextHandlers`. This makes the API consistent across all selection methods and the type hints.
* **`Response.body` is always `bytes`**: Previously could be `str` or `bytes`, now always returns `bytes`.
* **`get()`/`getall()` behavior**: On `Selector`: `get()` returns `TextHandler` (serialized HTML or text value), `getall()` returns `TextHandlers`. Aliases: `extract_first = get`, `extract = getall`. Old `get_all()` on `Selectors` is removed.
* **`Selectors.first`/`.last`**: Safe accessors that return `Selector | None` instead of raising `IndexError`.
* **Internal constants renamed**: `DEFAULT_FLAGS` → `DEFAULT_ARGS`, `DEFAULT_STEALTH_FLAGS` → `STEALTH_ARGS`, `HARMFUL_DEFAULT_ARGS` → `HARMFUL_ARGS`, `DEFAULT_DISABLED_RESOURCES` → `EXTRA_RESOURCES`.

### 🔨 Other Changes {#v0.4-other-changes}

* **Dependency changes**: Replaced `tldextract` with `tld`, removed internal `_html_utils.py` in favor of `w3lib.html.replace_entities`, added `typing_extensions` as a hard requirement.
* **Docs overhaul**: Full switch from MkDocs to Zensical, new spider documentation section, updated all existing pages, and added new API references.

## [v0.3.14](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.14) - 2026-01-03 {#v0.3.14}

**A minor maintenance update to fix issues that happened with some devices in v0.3.13**

- Disabled the incognito mode in `StealthyFetcher` and its session classes since it made cookies not persistent across pages on Windows devices. It didn't happen on MacOS and Linux (Fixes [#123](https://github.com/D4Vinci/Scrapling/issues/123), thanks to @frugality4121 for bringing it up and to @gembleman for pointing out the solution).
- Pinned down the last version of browserforge to solve the issue with old header models for users with an already old browserforge version.

## [v0.3.13](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.13) - 2026-01-01 {#v0.3.13}

**This is a big update with many improvements across many places, but also many breaking changes for good reasons. Please read the below before updating**

* For many reasons, we decided that from now on, we will stop using Camoufox entirely, and we might switch back to it in the future if its development continues. If you prefer to continue using Camoufox as before this release, there are instructions for that in this [section](https://github.com/D4Vinci/Scrapling/blob/v0.3.13/docs/fetching/stealthy.md#using-camoufox-as-an-engine).

* Previously, we were using patchright in the stealth mode inside `DynamicFetcher` and its session classes. Now we removed the stealth mode from them and started using patchright inside `StealthyFetcher` and its session classes, with A LOT of improvements, as you will see, improving the stealth overall on top of patchright.

**This makes `StealthyFetcher` and its session classes 101% faster than before, use less memory and space, and have ~400 lines of code shorter, but, most importantly, are more stable than when we used Camoufox before.**

This will also shorten the installation time of the `scrapling install` command, reduce the size of the Docker image, improve test smoothness in GitHub's CI, and make scrapling less confusing for new users.

### Breaking changes {#v0.3.13-breaking-changes}
1. The `stealth` argument was removed from the `DynamicFetcher` class and its session class, while the `hide_canvas` argument was moved to the `StealthyFetcher` and its session classes.
2.  The `disable_webgl` argument has been moved from `DynamicFetcher` to the `StealthyFetcher` class and renamed as `allow_webgl`. All session classes as well.
3. The `StealthyFetcher` class is now basically the new stealthy version of `DynamicFetcher`, so the following arguments are removed: `block_images`, `humanize`, `addons`, `os_randomize`, `disable_ads`, and `geoip`. I tried to replicate them in Chromium, but each had its own problem. This might change with upcoming releases before v0.4.

Now to the good news, we have improved and fixed a lot of stuff :)

### Improvements {#v0.3.13-improvements}
- You already know that the `StealthyFetcher` class and its session classes are now 101% faster than before, but now also the `DynamicFetcher` class and its session class are 20% faster.
- Cloudflare's solver algorithm has been improved over before now to finish faster and handle more cases. Also, thanks to the new refactor, expect the solver to solve the captcha twice as fast!
- All fetchers now use less memory.
- The MCP server now uses fewer tokens to save more money!
- The Docker image is now 60% smaller.
- The whole documentation website has been updated with the new stuff. At the same time, it was made more explicit, many sections were shortened, more examples were added, missing arguments were included, the API reference section was updated with graphs, and many other improvements were made. The Website now loads 130% faster, uses less data, and is better for SEO.

### Fixes {#v0.3.13-fixes}
- Added the arguments that were missing before in the Web Scraping shell shortcuts and made them more accurate.
- Fixed the issue where the `google_search` argument was creating a Google referrer even if the URL is a localhost/IP.

## [v0.3.12](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.12) - 2025-12-18 {#v0.3.12}

### What's Changed {#v0.3.12-what-s-changed}
- Added a new argument to `DynamicSession`/`AsyncDynamicSession` classes called `timezone_id`, which allows you to set the timezone of the browser so that it matches the timezone of the Proxy/VPN you are using. That way, the websites can't detect that you are using a proxy through the timezone mismatch technique.
- Improved the automated conversion of response to JSON.
- Renamed the internal function `__create__` to `start` inside fetchers' session classes to make it easier to use them outside the `with` context.
- Updated `curl_cffi` and other deps to the latest versions.

## [v0.3.11](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.11) - 2025-12-03 {#v0.3.11}

### What's Changed {#v0.3.11-what-s-changed}
- Added a better logic for handling timeout errors when the `network_idle` argument is used on an unstable website (websites with media playing, etc.)
- Fixed the autocompletion for the `stealthy_fetch` shortcut in the Web Scraping Shell

## [v0.3.10](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.10) - 2025-11-26 {#v0.3.10}

**A maintenance update with many significant changes and possible breaking changes**

- **Solved** all encoding issues by using a better approach which will handle web pages where encoding is not correctly declared (Thanks to @Kemsty2's efforts for pointing that out in [#110](https://github.com/D4Vinci/Scrapling/issues/110) [#111](https://github.com/D4Vinci/Scrapling/pull/111) )
- **Solved** a logical issue with overriding session-level parameters with request-level parameters in all browser-based fetchers that was present since v0.3
- **Fixed** the signatures of the shortcuts in the interactive web scraping shell, which made a perfect autocompletion experience for the shortcuts in the shell. This issue has been present since v0.3 as well.
- **Pumped up** the version for the Maxmind database, which will improve the `geoip` argument for `StealthyFetcher` and its session classes.
- **Updated** all used browser versions to the latest available ones.
- **BREAKING** - all fetchers had gone through a big refactor, which resulted in some interesting things that might break your code:
    1. Scrapling codebase is now smaller by ~750 lines and many changes which would make maintenance very much easier in the future and use a bit less resources.
    2. The validation for all fetchers and their session classes became much faster, which will reflect on their overall speed.
    3. To achieve this, now all fetchers can't accept standard arguments other than the `url` argument; the rest of the arguments must be keyword-arguments so your code must be like `Fetcher.get('https://google.com', stealthy_headers=True)` not `Fetcher.get('https://google.com', True)` if you were doing that for some reason!
    4. An annoying difference between browser-based fetchers and their session classes since v0.3 was that the argument used to pass custom parser settings per request was called `custom_config`, while it was named `selector_config` in the session classes. This refactor allowed us to unify the naming to `selector_config` without breaking your code, so the main one is now `selector_config` with backward compatibility for the `custom_config` argument. The autocompletion support will be available only for the `selector_config` argument.
    5. Also, to achieve all of this, we had to make the type hints of the fetchers' functions dynamically generated, so if you don't get a proper autocompletion in your IDE, make sure you are using a modern version of it. We have tested almost all known IDEs/editors.

> We have also updated all benchmark tables with the current numbers against the latest versions of all alternative libraries.

## [v0.3.9](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.9) - 2025-11-17 {#v0.3.9}

**A new update with many important changes**

### 🚀 New Stuff and quality of life changes {#v0.3.9-new-stuff-and-quality-of-life-changes}
- Now the `impersonate` argument in `Fetcher` and `FetcherSession` can accept a list of browsers that the library will choose a random browser from them with each request.

```python
from scrapling.fetchers import FetcherSession

with FetcherSession(impersonate=['chrome', 'firefox', 'safari']) as s:
  s.get('https://github.com/D4Vinci/Scrapling')
```

- A new argument to the `clean` method in `TextHandler` to remove html entities from the current text easily.
- Huge improvements to the documentation with more precise explanations of many parts and automatic translations of the main `README.md` file.

### 🐛 Bug Fixes {#v0.3.9-bug-fixes}
- Fixed a big issue with retrieving responses from browser-based fetchers. Now, there is intelligent content type detection that ensures `response.body` contains the rendered browser content only if the content is HTML; otherwise, it contains the raw content of the last request made. This allows you to download binary files and text-based files without having to find them wrapped in HTML tags, while being able to retrieve the rendered content you want from the website when fetching it.

### 🔨 Misc {#v0.3.9-misc}
- Updated the contributing guide to make it clearer and easier.
- Add a new workflow to enforce code quality tools (Same ones used as pre-commit hooks).

## [v0.3.8](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.8) - 2025-10-27 {#v0.3.8}

**A new update with many important changes**

### 🚀 New Stuff and quality of life changes {#v0.3.8-new-stuff-and-quality-of-life-changes}
- For all browser-based fetchers: websites that never finish loading their requests won't crash the code now if you used `network_idle` with them.
- The logic for collecting/checking for page content in browser-based fetchers has been changed to make browsers more stable on Windows systems now, as Linux/MacOS (All this difference in behaviour is because of Playwright's different implementation on Windows systems).
- Refactored all the validation logic, which made all requests done from all browser-based fetchers faster by 8-15%
- A New option called `extra_flags` has been added to `DynamicFetcher` and its session to allow users to add custom Chrome flags to the existing ones while launching the browser.
- Reverted the route logic for catching responses (changed in the last version) to use the old routing version when `page_action` is used. This was added to collect the latest version of a page's content in case `page_action` changes it without making a request. (Thanks for @gembleman to pointing it in [#100](https://github.com/D4Vinci/Scrapling/issues/100) and [#102](https://github.com/D4Vinci/Scrapling/pull/102) )

### 🐛 Bug Fixes {#v0.3.8-bug-fixes}
- Fixed a typo in `load_dom` in DynamicSession's async_fetch
- Fixed an issue with Cloudflare solver that made the solver wait forever for embedded captchas that don't disappear after solving. Now it will wait for the captcha to disappear for 30 seconds, then assume it's the type that doesn't disappear (Fixes #100 )

### 🔨 Misc {#v0.3.8-misc}
- Now the Docker image is automatically pushed to Dockerhub and GitHub's container registry for user convenience.
- Added a [new documentation page](https://github.com/D4Vinci/Scrapling/blob/v0.3.8/docs/tutorials/external.md) to show how to use Scrapeless browser with Scrapling.

## [v0.3.7](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.7) - 2025-10-12 {#v0.3.7}

**A new update with many important changes**

### 🚀 New Stuff and quality of life changes {#v0.3.7-new-stuff-and-quality-of-life-changes}
- Reworked `solve_cloudflare` argument in `StealthyFetcher` to make it able to solve all kinds of custom implementations of Turnstile.
- Refactored the entire codebase to be acceptable by Pyright, so expect a flawless IDE experience now with all software and many bugs solved.
- Refactored the requests logic to be cleaner and faster (Also solves #97 )
- Added a new option `user_data_dir` to all browser-based session classes to allow the user to reuse the browser session data (cookies/storage/etc...) from previous sessions. Leaving it will cause Playwright to use a random directory on each run, as was happening before.
- Added a new customization option `additional_args` to `Dynamic fetcher` and its session class to enable the user to pass extra arguments to Playwright's context, as we had with `StealthyFetcher` before.
- The route logic for collecting the last navigation response for all browsers has been improved, which allows the raw responses to be passed to the parser before being processed by the browsers as before. This will be very helpful with text/JSON responses.

### 🐛 Bug Fixes {#v0.3.7-bug-fixes}
- The rework of the route logic solved an issue with retrieving the content of unstable websites on some Windows devices.
- All the refactors that happened in this version solved a lot of bugs along the way that were hard to spot before, and weird autocompletion issues with some IDEs.
- Many fixes to the documentation website

## [v0.3.6](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.6) - 2025-10-01 {#v0.3.6}

### 🚀 New Stuff {#v0.3.6-new-stuff}
- Improved the `solve_cloudflare` argument in `StealthyFetcher` and its session classes to be able to solve all types of both Turnstile and interstitial Cloudflare challenges 🎉
- Now the MCP server has the option to use `Streamable HTTP`, so you can easily expose the server.
- Added Docker support, so now an image is built and pushed to Docker Hub automatically with each release (contains all browsers)

### 🐛 Bug Fixes {#v0.3.6-bug-fixes}
- Fixed an encoding issue with the parser that happened in some cases (the famous `invalid start byte` error)
- Restructured multiple parts of the library to fix some memory leaks, so now enjoy noticably lower memory usage based on your config (Also solves #92 )
- Improved type annotation in many parts of the code so you can have a better IDE experience (Also solves #93 )

## [v0.3.5](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.5) - 2025-09-20 {#v0.3.5}

**Necessary release that fixes multiple issues**

### 🚀 New Stuff {#v0.3.5-new-stuff}
- All browser-based fetchers (`DynamicFetcher`/`StealthyFetcher`/...) and their session classes are now fetching websites 15-20%:
    1. Page management is now much faster due to the logic improvement by @AbdullahY36 in #87
    2. Optimized the validation logic overall and improved page creation for sync fetches, which together introduced a lot of speed improvements

- Big improvements to the stealth mode in `DynamicFetcher` and its session classes by replacing `rebrowser-playwright` with `PatchRight`:
    1. Before this update, `rebrowser-playwright` was turned off when you enabled `stealth` and `real_chrome` because they weren't doing well together, but now we don't have this issue with `PatchRight`
    2. You can now interact with Closed-Shadow Roots since `PatchRight` can handle them automatically.

### 🐛 Bug Fixes {#v0.3.5-bug-fixes}
- Fixed a bug that happens while using the `re` method from the `Selectors` class.
- Fixed a bug with `uncurl` and `curl2fetcher` commands in the Web Scraping Shell that made curl's `--data-raw` flag parse incorrectly.
- Fixed a bug with the `view` command in the Web Scraping Shell that depended on the website's encoding to happen.
- Fixed a bug with content converting that affected the `mcp` mode and `extract` commands.

### New Contributors {#v0.3.5-new-contributors}
- @AbdullahY36 made their first contribution in #87

## [v0.3.4](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.4) - 2025-09-16 {#v0.3.4}

**Necessary release that fixes multiple issues**

### 🚀 New Stuff {#v0.3.4-new-stuff}
- Added all the fetchers session classes to the interactive shell to be available right away without import.

### 🐛 Bug Fixes {#v0.3.4-bug-fixes}
- Added a workaround for a bug with the Playwright API on Windows that happened while retrieving content while solving Cloudflare.
- Fixed an encoding issue with the `view` command in the interactive shell
- Fixed a bug with the `max_pages` argument in `AsyncStealthySession` that was crashing the code.
- Fixed an issue that happened with the last updates that made the `html_content` and `prettify` properties in the `Selector` class return bytes, depending on the encoding. Both are returning strings as they were.

## [v0.3.3](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.3) - 2025-09-15 {#v0.3.3}

- Removed the logic that is removing the default browser tab on browser-based fetchers since it caused a crashing error (Not happening on Mac, only managed to produce on Windows and Linux)

## [v0.3.2](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.2) - 2025-09-15 {#v0.3.2}

Release Notes for v0.3.2

### 🚀 New Stuff {#v0.3.2-new-stuff}

- **Optional fetcher dependencies**: All fetchers are now part of optional dependency groups, reducing core package size. So the base `scrapling` module is now the parser only, and to use the fetchers or the commandline options, you have to do: `pip install "scrapling[fetchers]"`. Check out the detailed installation instructions from [here](index.md#installation)
- **Per-page configuration in sessions**: Session classes for browser fetchers now support individual configuration per page in sessions. All fetch-level parameters are now validated like session-level ones. More details on the documentation website [here](fetching/stealthy.md#full-list-of-arguments)
    <br>Example:

    ```python
    with StealthySession(headless=True, solve_cloudflare=True) as session:
        page = session.fetch('https://nopecha.com/demo/cloudflare', google_search=False)
    ```

- **Improved browser-based fetchers**
    - A new option to control whether to wait for JavaScript execution to finish in pages or not (it's enabled by default now, as it was before)

        ```python
        with DynamicSession(headless=True, disable_resources=False, network_idle=True) as session:
           page = session.fetch('https://quotes.toscrape.com/', load_dom=False)
        ```

    - The Stealth mode is now more reliable in `DynamicFetcher` and its session classes.
    - Both `DynamicFetcher` and `StealthyFetcher` are now using fewer resources (Automatically finding and closing the default tab opened by Persistent contexts in Playwright API)
    - Fixed a vital logic bug in browser-based fetchers' pages rotation - previous pages are now replaced with fresh ones. (Tabs that get reused in rotation are possibly contaminated from previous settings used on them)
    - `StealthyFetcher` and its session classes are now slightly faster (5%)

- **Enhanced `.body` property**: Now returns the passed content as-is without processing, enabling file downloads and handling non-HTML requests. Below is an example of downloading a photo:

    ```python
    from scrapling.fetchers import Fetcher

    page = Fetcher.get('https://raw.githubusercontent.com/D4Vinci/Scrapling/main/images/poster.png')
    with open(file='poster.png', mode='wb') as f:
        f.write(page.body)
    ```

### 🐛 Bug Fixes {#v0.3.2-bug-fixes}

- **Encoding issues resolved**: Fixed multiple encoding problems that happened with some websites in parser, mcp mode, and extract commands (Also solves #80 and #81)
- **Faster parsing**: Due to many changes here and there, the library is now faster, and it's reflected in the updated benchmarks

### 🔨 Misc {#v0.3.2-misc}

- **Updated benchmarks**: Refreshed performance benchmarks to compare the current speed improvements to the latest versions of similar libraries
- **Refactored a lot of the code and replaced dead code with better implementations**: Fewer code, cleaner code, easier maintenance
- **Added YouTube video**: Included video content for MCP documentation.
- **A new issues template**: Easy new template for users who can't use the current templates.
- **CI workflow optimization**: Tests workflow now skips runs when only documentation or non-code files are changed.
- **Updated dependencies**: Bumped up various dependencies to the latest versions.
- **Code style improvements**: Applied new ruff rules across all files.
- **Pre-commit hooks**: Updated pre-commit configuration.

### 🎯 Breaking Changes {#v0.3.2-breaking-changes}

- Removed `max_pages` parameter from sync `StealthySession` to match `DynamicSession` (it's meaningless to have in the sync version)

## [v0.3.1](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3.1) - 2025-09-02 {#v0.3.1}

1. Fixed an issue with scrapling installation when you install it without the `shell` extra (#76 )
2. Added a new argument to all browser-based fetchers and their session classes to add a JS file to be executed on page creation (#56) :

```python
from scrapling.fetchers import StealthyFetcher

StealthyFetcher.fetch('https://example.com', init_script="/absolute/path/to/js/script.js")
```

## [v0.3](https://github.com/D4Vinci/Scrapling/releases/tag/v0.3) - 2025-09-01 {#v0.3}

🎉 **Major Release - Complete Architecture Overhaul**

Scrapling v0.3 represents the most significant update in the project's history, featuring a complete architectural rewrite, considerable performance improvements, and powerful new features, including AI integration and interactive Web Scraping shell capabilities.

This release includes multiple breaking changes; please review the release notes carefully.

### 🚀 Major New Features {#v0.3-major-new-features}

#### Session-Based Architecture {#v0.3-session-based-architecture}
- **New Session Classes**: Complete rewrite introducing persistent session support
    - `FetcherSession` - HTTP requests with persistent state management that works with both sync and async code
    - `DynamicSession`/`AsyncDynamicSession` - Browser automation while keeping the browser open till you finish
    - `StealthySession`/`AsyncStealthySession` - Stealth browsing while keeping the browser open till you finish
- **Async Browser Tabs Management**: A new pool of tabs feature through the `max_pages` argument that rotates browser tabs for concurrent browser fetches
- **Concurrent Sessions**: Run multiple isolated sessions simultaneously

Refer to the `Fetching` section on the website for more details.

#### A lot of new stealth/anti-bot Capabilities {#v0.3-a-lot-of-new-stealth-anti-bot-capabilities}
- **🤖 Cloudflare Solver**: Automatic [Cloudflare Turnstile challenge solving](fetching/stealthy.md#cloudflare-and-stealth-options) in `StealthyFetcher` and its session classes
- **Browser fingerprint impersonation**: Mimic real browsers' TLS fingerprints, version-matching browser headers, HTTP/3 support, and more with the all-new [Fetcher](fetching/static.md) class
- **Improved stealth mode**: The stealth mode for `DynamicFetcher` and its session classes is now more robust and reliable (AKA `PlayWrightFetcher`)

#### AI Integration & MCP Server {#v0.3-ai-integration-mcp-server}
- **Built-in MCP Server**: Model Context Protocol server for AI-assisted web scraping
- **6 Powerful Tools**: `get`, `bulk_get`, `fetch`, `bulk_fetch`, `stealthy_fetch`, `bulk_stealthy_fetch`
- **Smart Content Extraction**: Convert web pages/elements to Markdown, HTML, or extract a clean version of the text content
- **CSS Selector Support**: Use the Scrapling engine to target specific elements with precision before handing the content to the AI
- **Anti-Bot Bypass**: Handle Cloudflare Turnstile and other protections
- **Proxy Support**: Use proxies for anonymity and geo-targeting
- **Browser Impersonation**: Mimic real browsers with TLS fingerprinting, real browser headers matching that version, and more
- **Parallel Processing**: Scrape multiple URLs concurrently for efficiency
- [and more...](ai/mcp-server.md)

#### New Interactive Web Scraping Shell {#v0.3-new-interactive-web-scraping-shell}
- **A New Shell**: Custom IPython shell with many smart Built-in Shortcuts like `get`, `post`, `put`, `delete`, `fetch`, and `stealthy_fetch`
- **Smart Page Management**: New commands `page` and `pages` to automatically store the current page and history for all requests done through the shell
- **Curl Integration**: Convert browser DevTools curl commands with `uncurl` and `curl2fetcher` functions to `Fetcher` requests
- [and more...](cli/interactive-shell.md)

#### Scrape from the terminal without programming {#v0.3-scrape-from-the-terminal-without-programming}
- **New Extract Commands**: Terminal-based scraping without programming
    - `scrapling extract get/post/put/delete` - Simple HTTP requests
    - `scrapling extract fetch` - Dynamic content scraping
    - `scrapling extract stealthy-fetch` - Anti-bot bypass
- **Downloads web pages** and saves their content to files.
- **Converts HTML to readable formats** like Markdown, keeps it as HTML, or just extracts the text content of the page.
- **Supports custom CSS selectors** to extract specific parts of the page.
- **Handles HTTP requests and fetching through browsers.**
- **Highly customizable** with custom headers, cookies, proxies, and the rest of the options. Almost all the options available through the code are also accessible through the terminal.
- [and more...](cli/extract-commands.md)

### 🔧 Technical Improvements {#v0.3-technical-improvements}

#### Performance Enhancements {#v0.3-performance-enhancements}
- **Fetcher is now 4 times faster** - Yes you have read it right!
- **DynamicFetcher is now ~60% faster** - A much faster version depending on your config (especially stealth mode)
- **StealthyFetcher is now 20–30% faster** - Using the new structure, and starting to use our implementation instead of `Camoufox` Python interface
- **50%+ combined speed gains** across core selection methods (`find_by_text`, `find_similar`, `find_by_regex`, `relocate`, etc.) 🚀
- **~10% CSS/XPath first methods speed increase** - `css_first` and `xpath_first` are now faster than `css` and `xpath`
- **40% faster `get_all_text()` method** for content extraction
- **20% speed improvement** in adaptive element relocation
- **Navigation properties optimization** - Properties like `next`, `previous`, `below_elements`, and more are now noticeably faster
- **5x faster text cleaning** operations
- **Memory efficiency improvements** with optimized imports and reduced overhead
- **⚡ Lightning-fast imports**: Reduced startup time with optimized module loading
- **Better benchmarks**: All the speed improvements Scrapling got made it much faster than before, compared to other libraries (1775x faster than BeautifulSoup and 5.1x faster than AutoScraper, check [benchmarks](benchmarks.md))

#### Architecture/Code Quality, and Quality of life {#v0.3-architecture-code-quality-and-quality-of-life}
- **Persistent Context**: All browser-based fetchers now use persistent context by default. (Solves #64 too)
- **Using msgspec to validate all browser-based fetchers very fast** before running the requests, so now it's easier to debug errors.
- **All cookies** returned from fetchers are now matching the format accepted by the same fetcher. So you can retrieve cookies and pass them again to all fetchers and their session classes.
- **Faster linting and formatting** due to migrating to `ruff`
- **Modern Build System**: Migrated from setup.py to pyproject.toml 📦
- **Better GitHub actions and workflows** for smoother development and testing
- **🎨 Enhanced Type Hints**: Complete type coverage with modern Python standards for better IDE support and reliability
- **Cleaner Codebase**: Removed dead code and optimized core functions 🧹
- **🚀 Backward Compatibility**: Added shortcuts to maintain compatibility with older code

### Breaking Changes {#v0.3-breaking-changes}

#### Minimum Python Version {#v0.3-minimum-python-version}
- **Python 3.10+ Required**: Dropped support for Python 3.9 and below

#### Class and Method Naming {#v0.3-class-and-method-naming}
These renamings are intended to improve clarity and consistency, particularly for new users.

- **`Adaptor` → `Selector`**: Core parsing class renamed (But still can be imported as `Adaptor` for backward compatibility)
- **`Adaptors` → `Selectors`**: Collection class renamed (But still can be imported as `Adaptors` for backward compatibility)
- **`auto_match` → `adaptive`**: Parameter renamed across all methods
- **`adaptor_arguments` → `selector_config`**: Configuration parameter renamed
- **`automatch_domain` → `adaptive_domain`**: Domain parameter renamed
- **`additional_arguments` → `additional_args`**: Shortened parameter name
- **⚠️ `text/body` → `content`**: Selector constructor parameter is now accepting both `str` and `bytes` format
- **`PlayWrightFetcher` → `DynamicFetcher`**: Browser automation class renamed (But still can be imported as `PlayWrightFetcher` for backward compatibility)
- **DynamicFetcher doesn't have the NSTBrowser logic/arguments anymore** since it's pointless to leave this logic now anyway.
- **StealthyFetcher's headless argument can't accept 'virtual' as an argument anymore** since we are not using Camoufox's library right now in anything other than getting the browser installation path and the rest of the launch options

### 🐛 Bug Fixes {#v0.3-bug-fixes}

- Fixed nested children counting in ignored tags for `get_all_text` (#61)
- Fixed the issue with installation due to spaces in Python's executable path (#57)
- Resolved threading issues in storage with recursion handling while the adaptive feature is enabled
- Fixed argument precedence issues using the Sentinel pattern in `FetcherSession`
- Resolved proxy type handling in `StealthyFetcher`
- Fixed `referer` and `google_search` argument conflicts
- Fixed async stealth script injection problems

## [v0.2.99](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.99) - 2025-04-08 {#v0.2.99}

**This is an essential update for everyone to fully enjoy Scrapling as it's intended.**

### What's changed {#v0.2.99-what-s-changed}
#### New full documentation website {#v0.2.99-new-full-documentation-website}
- Yup, finally 😄 Check it out from [here](index.md)
#### Unified import logic for fetchers {#v0.2.99-unified-import-logic-for-fetchers}
- Now you can import all fetchers with `from scrapling.fetchers import Fetcher, AsyncFetcher, StealthyFetcher, PlayWrightFetcher`, then use them directly like `page = Fetcher.get(...)` without initialization.<br/> This replaces this old import `from scrapling.defaults import Fetcher, AsyncFetcher, StealthyFetcher, PlayWrightFetcher`.
#### Breaking change: automatch is now turned off by default {#v0.2.99-breaking-change-automatch-is-now-turned-off-by-default}
- Now there's new logic to enable automatch from fetchers or other parsing options. Check out the [documentation page](fetching/choosing.md#parser-configuration-in-all-fetchers) for details.
>  Old imports and logic are left usable with a warning for backward compatibility.
#### New options added to fetchers {#v0.2.99-new-options-added-to-fetchers}
- Now, both `StealthyFetcher` and `PlayWrightFetcher` have a new argument while fetching called `wait`. This makes the fetcher wait/sleep for a specific period (milliseconds) before closing the page and returning the response to you.
- Now `StealthyFetcher` methods `fetch` and `async_fetch` have the argument `additional_arguments` to be passed to Camoufox as additional settings, which takes higher priority than Scrapling's settings (#54 )
#### Bugs squashed {#v0.2.99-bugs-squashed}
- Fixed a bug in `async_fetch` in both `StealthyFetcher` and `PlayWrightFetcher` classes, with catching redirections.

**_Thanks for all your support and donations!_**

## [v0.2.98](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.98) - 2025-03-17 {#v0.2.98}

**This is an essential update for everyone to enjoy Scrapling as it's intended fully**

### What's changed {#v0.2.98-what-s-changed}
#### Various memory usage and speed optimizations {#v0.2.98-various-memory-usage-and-speed-optimizations}
- All selection methods' memory usage is ~40% of previous memory usage and the speed slightly increased.
- Implemented Lazy loading for all submodules of the library so now what you use is what you load, for example:
Before the update this import `from scrapling import Adaptor` was using `30-40mb` of RAM because it loaded all fetchers and stuff with it too, now it uses `~1.2mb`.
- The last update made the library use ~32% memory it used before with a large requests pool, now we adjusted the caching further to use even less than that.
- Overall speed increase in the parser by a slight 2-5%

**_Thanks for all your support and donations!_**

## [v0.2.97](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.97) - 2025-03-15 {#v0.2.97}

**This is an essential update for everyone to fully enjoy Scrapling as it's intended**

### What's changed {#v0.2.97-what-s-changed}
#### Lower memory usage and small speed increase across all Fetchers. {#v0.2.97-lower-memory-usage-and-small-speed-increase-across-all-fetchers}
- With new limitations across the library over caching size you will notice significantly lower memory usage than before while doing large numbers of requests/operations.
- Refactored big parts of the fetchers to easier maintainability and small speed increase.

#### Bugs fixed {#v0.2.97-bugs-fixed}
- Fixed a bug in `TextHandler` where importing it alone and passing a non-string value converts it to an empty string. Now anything passed to `TextHandler` is automatically converted to a string before being converted to `TextHandler`, this is forced on any value passed -- `TextHandler` as the name implies is intended to work with strings only after all! (#45 )
- Fixed a bug where the `retries` arguments weren't taken into account in most AsyncFetcher methods.

#### Miscellaneous {#v0.2.97-miscellaneous}
- Update type hints for most arguments in all fetchers to be clearer and more accurate.

**_Thanks for all your support and donations!_**

## [v0.2.96](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.96) - 2025-03-05 {#v0.2.96}

**This is an essential update for everyone to fully enjoy Scrapling as it's intended**

### What's changed {#v0.2.96-what-s-changed}
1. Added the `-f` option to `scrapling install` to force reinstall browser dependencies. I recommend you do `scrapling install -f` now to enjoy the big speed performance `StealthyFetcher` just got with the new Camoufox browser version :)
2. Fixed a bug in `TextHandler` where slicing returned `TextHandlers` instead of `TextHandler` and fixed the type hint there (#41 )
3. Fixed an issue where `scrapling install` might in some instances drop the user into a Python shell!

## [v0.2.95](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.95) - 2025-02-25 {#v0.2.95}

**This is an essential update for everyone to fully enjoy Scrapling as it's intended**

### What's changed {#v0.2.95-what-s-changed}
1. Fixed a bug in `Fetcher` that made headers generated by the `stealthy_headers` argument overwrite some of the headers provided by the user like `Accept` (#39 )
2. Improved the headers generation logic a bit so it should give a slight speed boost.

## [v0.2.94](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.94) - 2025-02-22 {#v0.2.94}

**This is an essential update for everyone to fully enjoy Scrapling as it's intended**

### What's changed {#v0.2.94-what-s-changed}
1. Added the `history` property to all fetchers to show redirections (#32 )
2. Fixed the logic of the `case_sensitive` argument logic for all `re`/`re_first`. This may make your code return different results if you were using it (but you probably deserve it because you noticed it wasn't working as intended and didn't open an issue LOL)
3. Updated dependencies and enabled `coop` back again in the Camoufox engine (StealthyFetcher).

## [v0.2.93](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.93) - 2025-01-31 {#v0.2.93}

**This is an essential update for everyone to fully enjoy Scrapling as it's intended**

### What's changed {#v0.2.93-what-s-changed}
1. The return type is now consistent across all the parser engine so you will always get a return type as one of these `Adaptor`, `Adaptors`, `TextHandler`, `TextHandlers`, `None`, and a list in case you have mixed results like combined CSS selector. This allows a better coding experience with minimum manual type checking, makes the library more stable, and makes chaining methods always possible.
2. Most of the parser engine especially the `Adaptor` class got refactored to a cleaner version and most importantly a faster version. So now almost all the methods/properties, especially the searching methods, got a speed increase between 5-40%. Some methods got bigger speed boosts like `find_by_regex` got a ~60% speed boost! The automatch feature got a small ~5% speed boost.
3. Fixed logic bugs with the `find_all`/`find` methods that made the passed filters used in OR fashion and other times as an AND. So now all elements returned need to fulfill all filters you pass.
4. Now all regex-related methods return `TextHandler`/`TextHandlers` for easier methods chaining.
5. **Added a new** `below_elements` property that returns an `Adaptors` object of all elements under the current element in the DOM tree.
6. Now all methods/properties that were returning HTML source as string are now returning it as `TextHandler` so you can do regex easily on it etc...
7. StealthyFetcher is now a bit faster and more stealthy. Also, now it's possible to click Captchas in iframes like **Cloudflare Turnstile**.
8. The auto-completion and type hints improved a lot in nearly half the library. Especially `Adaptor`, `TextHandler`, and `TextHandlers`.
9. Now slicing `TextHandler`, accessing by index, or using the `split` method returns another `TextHandler` instead of the standard Python string. Now almost all standard string operations/methods return other `Texthandler` instead of standard string to make chaining methods/functions always possible.
10. Fixed some small bugs and typos. For example, the Fetcher async_put was doing post request instead of put request 😶‍🌫️
11. Improved the README a bit till I finish the documentation website.

This was supposed to be a small update till version 0.3 but thought to make it better.

## [v0.2.92](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.92) - 2024-12-26 {#v0.2.92}

### What's changed {#v0.2.92-what-s-changed}
- Now response returned by browser-based fetchers uses more reliable data sources in cases where the page loaded uses many Iframes.
- **Now installing `Scrapling` is made even easier, you install it with pip then run `scrapling install` in the terminal and you are ready!**
- Fixed an inaccurate type hint in the parser.

## [v0.2.91](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.91) - 2024-12-19 {#v0.2.91}

### What's changed {#v0.2.91-what-s-changed}
- Fixed a bug where the logging fetch logging sentence was showing in the first request only.
- The default behavior for Playwright API while browsing a page is returning the first response that fulfills the load state given to the `goto` method `["load", "domcontentloaded", "networkidle"]` so if a website has a wait page like Cloudflare's one that redirects you to the real website afterward, Playwright will return the first status code which in this case would be something like 403. This update solves this issue for both `PlaywrightFetcher` and `StealthyFetcher` as both are using Playwright API so the result depends on Playwright's default behavior no more.
- Added support for proxies that use SOCKS proxies in the `Fetcher` class.
- Fixed the type hint for the `wait_selector_state` argument so now it will show the accurate values you should use while auto-completing.

## [v0.2.9](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.9) - 2024-12-16 {#v0.2.9}

### What's changed {#v0.2.9-what-s-changed}
##### New features {#v0.2.9-new-features}
1. Introducing the **long-awaited** async support for Scrapling! Now you have the `AsyncFetcher` class version of `Fetcher`, and both `StealthyFetcher` and `PlayWrightFetcher` have a new method called `async_fetch` with the same options.

```python
>> from scrapling import StealthyFetcher
>> page = await StealthyFetcher().async_fetch('https://www.browserscan.net/bot-detection')  # the async version of fetch
>> page.status == 200
True
```

2. Now the `StealthyFetcher` class has the `geoip` argument in its fetch methods which when enabled makes the class automatically use IP's longitude, latitude, timezone, country, and locale, then spoof the WebRTC IP address. It will also calculate and spoof the browser's language based on the distribution of language speakers in the target region.
3. Added the `retries` argument to `Fetcher`/`AsyncFetcher` classes so now you can set the number of retries of each request done by `httpx`.
4. Added the `url_join` method to `Adaptor` and Fetchers which takes a relative URL and joins it with the current URL to generate an absolute full URL!
5. Added the `keep_cdata` method to `Adaptor` and Fetchers to stop the parser from removing cdata when needed.
6. Now `Adaptor`/`Response` `body` method returns the raw HTML response when possible (without processing it in the library).
7. Adding logging for the `Response` class so now when you use the Fetchers you will get a log that gives info about the response you got.
Example:

   ```python
   >> from scrapling.defaults import Fetcher
   >> Fetcher.get('https://books.toscrape.com/index.html')
   [2024-12-16 13:33:36] INFO: Fetched (200) <GET https://books.toscrape.com/index.html> (referer: https://www.google.com/search?q=toscrape)
   >>
   ```

8. Now using all standard string methods on a `TextHandler` like `.replace()` will result in another `TextHandler`. It was returning the standard string before.
9. Big improvements to speed across the library and improvements to stealth in Fetchers classes overall.
10. Added dummy functions like `extract_first`\`extract` which returns the same result as the parent. These functions are added only to make it easy to copy code from Scrapy/Parsel to Scrapling when needed as these functions are used there!
11. Due to refactoring a lot of the code and using caching at the right positions, now doing requests in bulk will have a big speed increase.

##### Breaking changes {#v0.2.9-breaking-changes}
- Now the support for Python 3.8 has been dropped. (Mainly because Playwright stopped supporting it but it was a problematic version anyway)
- The `debug` argument has been removed from all the library, now if you want to set the library to debugging, do this after importing the library:

   ```python
   >>> import logging
   >>> logging.getLogger("scrapling").setLevel(logging.DEBUG)
   ```

##### Bugs Squashed {#v0.2.9-bugs-squashed}
1. Now WebGL is enabled by default as a lot of protections are checking if it's enabled now.
2. Some mistakes and typos in the docs/README.

##### Quality of life changes {#v0.2.9-quality-of-life-changes}
1. All logging is now unified under the logger name `scrapling` for easier and cleaner control. We were using the root logger before.
2. Restructured the tests folder into a cleaner structure and added tests for the new features. All the tests were rewritten to a cleaner version and more tests were added for higher coverage.
3. Refactored a big part of the code to be cleaner and easier to maintain.

> All these changes were part of the changes I decided before to add with 0.3 but decided to add them here because it will be some time till the next version. Now the next step is to finish the detailed documentation website and then work on version 0.3

## [v0.2.8](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.8) - 2024-11-30 {#v0.2.8}

### What's changed {#v0.2.8-what-s-changed}
- This is a small update that includes some must-have quality-of-life changes to the code and fixed a typo in the main README file (#20)

## [v0.2.7](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.7) - 2024-11-26 {#v0.2.7}

### What's changed {#v0.2.7-what-s-changed}
##### New features {#v0.2.7-new-features}
- Now if you used the `wait_selector` argument with `StealthyFetcher` and `PlayWrightFetcher` classes, Scrapling will wait again for the JS to fully load and execute like normal. If you used the `network_idle` argument, Scrapling will wait for it again too after waiting for all of that. If the states are all fulfilled then no waiting happens, of course.
- Now you can enable and disable ads on `StealthyFetcher` with the `disable_ads` argument. This is enabled by default and it installs the `ublock origin` addon.
- Now you can set the locale used by `PlayWrightFetcher` with the `locale` argument. The default value is still `en-US`.
- Now the basic requests done through `Fetcher` can accept proxies in this format `http://username:password@localhost:8030`.
- The stealth mode improved a bit for `PlayWrightFetcher`.

##### Bugs Squashed/Improvements {#v0.2.7-bugs-squashed-improvements}
1. Now enabling proxies on the `PlayWrightFetcher` class is not tied to the `stealth` mode being on or off (Thanks to [@AbdullahY36](https://github.com/AbdullahY36) for pointing that out)
2. Now the `ResponseEncoding` tests if the encoding returned from the response can be used with the page or not. If the returned encoding triggered an error, Scrapling defaults to `utf-8`

## [v0.2.6](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.6) - 2024-11-24 {#v0.2.6}

### What's changed {#v0.2.6-what-s-changed}
##### New features {#v0.2.6-new-features}
- Now the `PlayWrightFetcher` can use the real browser directly with the `real_chrome` argument passed to the `PlayWrightFetcher.fetch` function but this requires you to have Chrome browser installed. Scrapling will launch an instance of your Chrome browser and you can use most of the options as normal. (Before you only had the `cdp_url` argument to do so)
- Pumped up the version of headers generated for real browsers.

##### Bugs Squashed {#v0.2.6-bugs-squashed}
1. Turns out the format of the browser headers generated by `BrowserForge` was outdated which made Scrapling detected by some protections so now `BrowserForge` is only used to generate real useragent.
2. Now the `hide_canvas` argument is turned off by default as it's being detected by Google's ReCaptcha.

## [v0.2.5](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.5) - 2024-11-23 {#v0.2.5}

### What's changed {#v0.2.5-what-s-changed}

##### Bugs Squashed {#v0.2.5-bugs-squashed}
- Handled an error that happens with the 'wait_selector' argument if it resolved to more than 1 element. This affects the `StealthyFetcher` and the `PlayWrightFetcher` classes.
- Fixed the encoding type in cases where the `content_type` header gets value with parameters like `charset` (Thanks to @andyfcx for [#12](https://github.com/D4Vinci/Scrapling/issues/12) )

##### Quality of life {#v0.2.5-quality-of-life}
- Added more tests to cover new parts of the code and made tests run in threads.
- I updated the docs strings to be readable correctly on Sphinx's apidoc or similar tools.

##### New Contributors {#v0.2.5-new-contributors}
- @andyfcx made their first contribution at [#13 ](https://github.com/D4Vinci/Scrapling/pull/13)

## [v0.2.4](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.4) - 2024-11-20 {#v0.2.4}

### What's changed {#v0.2.4-what-s-changed}

##### Bugs Squashed {#v0.2.4-bugs-squashed}
- Fixed a bug when retrieving response bytes after using the `network_idle` argument in both the `StealthyFetcher` and `PlayWrightFetcher` classes. <br/> That was causing the following error message:

    ```
    Response.body: Protocol error (Network.getResponseBody): No resource with given identifier found
    ```

- The PlayWright API sometimes returns empty status text with responses, so now `Scrapling` will calculate it manually if that happens. This affects both the `StealthyFetcher` and `PlayWrightFetcher` classes.

## [v0.2.3](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.3) - 2024-11-19 {#v0.2.3}

### What's changed {#v0.2.3-what-s-changed}

##### Bugs Squashed {#v0.2.3-bugs-squashed}
- Fixed a bug with pip installation that prevented the stealth mode on PlayWright Fetcher from working entirely.

## [v0.2.2](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.2) - 2024-11-16 {#v0.2.2}

### What's changed {#v0.2.2-what-s-changed}
##### New features {#v0.2.2-new-features}
- Now if you don't want to pass arguments to the generated `Adaptor` object and want to use the default values, you can use this import instead for cleaner code

    ```python
    >> from scrapling.default import Fetcher, StealthyFetcher, PlayWrightFetcher
    >> page = Fetcher.get('https://example.com', stealthy_headers=True)
    ```

    Otherwise

    ```python
    >> from scrapling import Fetcher, StealthyFetcher, PlayWrightFetcher
    >> page = Fetcher(auto_match=False).get('https://example.com', stealthy_headers=True)
    ```

##### Bugs Squashed {#v0.2.2-bugs-squashed}
1. Fixed a bug with the `Response` object introduced with patch v0.2.1 yesterday that happened with some cases of nested selecting/parsing.

## [v0.2.1](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2.1) - 2024-11-15 {#v0.2.1}

### What's changed {#v0.2.1-what-s-changed}
##### New features {#v0.2.1-new-features}
1. Now the `Response` object returned from all fetchers is the same as the `Adaptor` object except it has these added attributes: `status`, `reason`, `cookies`, `headers`, and `request_headers`. All `cookies`, `headers`, and `request_headers` are always of type `dictionary`. <br/>So your code can now become like:

    ```python
    >> from scrapling import Fetcher
    >> page = Fetcher().get('https://example.com', stealthy_headers=True)
    >> print(page.status)
    200
    >> products = page.css('.product')
    ```

    Instead of before

    ```python
    >> from scrapling import Fetcher
    >> fetcher = Fetcher().get('https://example.com', stealthy_headers=True)
    >> print(fetcher.status)
    200
    >> page = fetcher.adaptor
    >> products = page.css('.product')
    ```

    But I have left the `.adaptor` property working for backward compatibility.

2. Now both the `StealthyFetcher` and `PlayWrightFetcher` classes can take a `proxy` argument with the fetch method which accepts a string or a dictionary.
3. Now the `StealthyFetcher` class has the `os_randomize` argument with the `fetch` method. If enabled, Scrapling will randomize the OS fingerprints used. The default is Scrapling matching the fingerprints with the current OS.

##### Bugs Squashed {#v0.2.1-bugs-squashed}
1. Fixed a bug that happens while passing headers with the `Fetcher` class.
2. Fixed a bug with parsing JSON responses passed from the fetcher-type classes.

##### Quality of life changes {#v0.2.1-quality-of-life-changes}
1. The text functionality behavior was to try to remove HTML comments before returning the text but that induced errors in some cases and made the code more complicated than needed. Now it has reverted to the default lxml behavior, **you will notice a slight speed increase to all operations that counts on elements' text like selectors**. Now if you want Scrapling to remove HTML comments from elements before returning the text to avoid the weird text-splitting behavior that's in lxml/parsel/scrapy, just keep the `keep_comments` argument set to True as it is by default.

## [v0.2](https://github.com/D4Vinci/Scrapling/releases/tag/v0.2) - 2024-11-11 {#v0.2}

### What's changed {#v0.2-what-s-changed}
##### New features {#v0.2-new-features}
1. Introducing the `Fetchers` feature with 3 new main types to make Scrapling fetch pages for you with a LOT of options!
    - The `Fetcher` class for basic HTTP requests
    - The `StealthyFetcher` class is a completely stealthy fetcher that uses a [stealthy modified version of Firefox](https://github.com/daijro/camoufox).
    - The `PlayWrightFetcher` class that allows doing browser-based requests with Vanilla PlayWright, PlayWright with stealth mode made by me, Real browsers through CDP, and [NSTBrowser](https://app.nstbrowser.io/r/1vO5e5)'s [docker browserless](https://hub.docker.com/r/nstbrowser/browserless)!
2. Added the completely new `find_all`/`find` methods to find elements easily on the page with dark magic!
3. Added the methods `filter` and `search` to the `Adaptors` class for easier bulk operations on `Adaptor` object groups.
4. Added methods `css_first` and `xpath_first` methods for easier usage.
5. Added the new class type `TextHandlers` which is used for bulk operations on `TextHandler` objects like the `Adaptors` class.
6. Added `generate_full_css_selector` and `generate_full_xpath_selector` methods.

##### Bugs Squashed {#v0.2-bugs-squashed}
1. Now the `Adaptors` class version of `re_first` returns the first result that matches in all `Adaptor` objects inside instead of the faulty logic of returning the results of `re_first` of all `Adaptor` objects.
2. Now if the user selects a text-type content to be returned from selected elements (like css `::text` function) with any method like `.css` or `.xpath`. The `Adaptor` object will return the `TextHandlers` class instead of returning a list of strings like before. So now you can do `page.css('something::text').re_first(r'regex_pattern').json()` instead of `page.css('something::text')[0].re_first(r'regex_pattern').json()`
3. Now `Adaptor`/`Adaptors` re/re_first arguments are consistent with the `TextHandler` ones. So now you have `clean_match` and `case_sensitive` arguments.
4. Now the `auto_match` argument is enabled by default in the initialization of `Adaptor` but still you have to enable it while selecting elements if you want to enable it. (Not a bug but a design decision)
5. A lot of type-annotations corrections here and there for better auto-completion experience while you are coding with Scrapling.

##### Quality of life changes {#v0.2-quality-of-life-changes}
1. Renamed both `css_selector` and `xpath_selector` methods to `generate_css_selector` and `generate_xpath_selector` for clarity and to not interrupt the auto-completion while coding.
2. Restructured most of the old code into a `core` subpackage and other design decisions for cleaner and easier maintenance in the future.
3. Restructured the tests folder into a cleaner structure and added tests for the new features. Also now tox environments are cached on GitHub for faster automated tests with each commit.

## [v0.1.2](https://github.com/D4Vinci/Scrapling/releases/tag/v0.1.2) - 2024-10-16 {#v0.1.2}

**Changelog**:

- Fixed a bug where the `keep_comments` argument is not working as intended.
- Adjusted the text function to automatically remove HTML comments from elements before extracting its text to prevent Lxml different behavior, for example:

    ```python
    >>> page = Adaptor('<span>CONDITION: Excellent</span>', keep_comments=True)
    >>> page.css('span::text')
    ['CONDITION: ', 'Excellent']
    ```

    previously would result in this because of Lxml default behavior but now it would return the full text 'CONDITION: Excellent'
    This behavior is known with parsel\scrapy as well so wanted to handle it here.

- Fixed a bug where the SQLite db file created by the library is not deleted when doing `pip uninstall scrapling` or similar.

## [v0.1.1](https://github.com/D4Vinci/Scrapling/releases/tag/v0.1.1) - 2024-10-14 {#v0.1.1}

Minor fixes

## [v0.1](https://github.com/D4Vinci/Scrapling/releases/tag/v0.1) - 2024-10-13 {#v0.1}

**Full Changelog**: <https://github.com/D4Vinci/Scrapling/commits/v0.1>

---

### Donate (`docs/donate.md`)

---
title: "Support Scrapling and Sponsor Its Development"
description: "Support Scrapling through GitHub Sponsors or Buy Me a Coffee. See the advertising tiers and benefits for project sponsors."
---

# Support and Advertisement

I've been creating all of these projects in my spare time and have invested considerable resources & effort in providing them to the community for free. By becoming a sponsor, you'd be directly funding my coffee reserves, helping me fulfill my responsibilities, and enabling me to continuously update existing projects and potentially create new ones.

You can sponsor me directly through the [GitHub Sponsors program](https://github.com/sponsors/D4Vinci) or [Buy Me a Coffee](https://buymeacoffee.com/d4vinci).

Thank you, stay curious, and hack the planet! ❤️

## Advertisement
If you are looking to **advertise** your business to our target audience, check out the [available tiers](https://github.com/sponsors/D4Vinci):

### 1. [The Silver tier](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=435495) ($100/month)
Perks:

1. Your logo will be featured at [the top of Scrapling's project page](https://github.com/D4Vinci/Scrapling?tab=readme-ov-file#sponsors).
2. The same logo will be featured at [the top of Scrapling's PyPI page](https://pypi.org/project/scrapling/) and [the top of Docker's image page](https://hub.docker.com/r/pyd4vinci/scrapling), the same way it was placed on the project's page.

### 2. [The Gold tier](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=591422) ($200/month)
Perks:

1. Your logo will be featured at [the top of Scrapling's project page](https://github.com/D4Vinci/Scrapling?tab=readme-ov-file#sponsors).
2. The same logo will be featured at [the top of Scrapling's PyPI page](https://pypi.org/project/scrapling/) and [the top of Docker's image page](https://hub.docker.com/r/pyd4vinci/scrapling), the same way it was placed on the project's page.
3. Your logo will be featured as a top sponsor on [Scrapling's website](https://scrapling.readthedocs.io/en/latest/) main page.

### 3. [The Platinum tier](https://github.com/sponsors/D4Vinci/sponsorships?tier_id=586646) ($300/month)
Perks:

1. Your logo will have a special placement at [the very top of Scrapling's project page](https://github.com/D4Vinci/Scrapling?tab=readme-ov-file#platinum-sponsors) with a 25-word paragraph or less.
2. The same logo will be featured at [the PyPI page](https://pypi.org/project/scrapling/)/[the Docker page](https://hub.docker.com/r/pyd4vinci/scrapling), the same way it was placed on the project's page.
3. A special placement for your logo as a top sponsor on [Scrapling's website](https://scrapling.readthedocs.io/en/latest/) main page.
4. A partner role at our Discord server and an announcement on the Twitter page and the Discord server.
5. A Shoutout at the end of each Release notes.

---

### Migrating To V0.5 (`docs/migrating-to-v0.5.md`)

---
title: "Migrating to v0.5"
description: "Move from Scrapling v0.4.15 to v0.5. Update browser imports, network capture, MCP tools, CLI commands, parser settings, and spider behavior."
---

# Migrating to v0.5 {#migrating-to-v05}

This guide covers the changes you need to check when moving from **v0.4.15 to v0.5**. It includes removed APIs, renamed tools, and fixes that can change your crawl results or saved files.

## Quick migration checklist {#quick-migration-checklist}

| If you use... | What to change |
| --- | --- |
| `DynamicFetcher`, `DynamicSession`, or `AsyncDynamicSession` | Use the matching stealthy class. |
| `capture_xhr` or `response.captured_xhr` | Use a browser session with `record_requests=True` and `session.network`. |
| `keep_cdata` | Remove it from parser and fetcher settings. |
| `scrapling extract stealthy-fetch` or the shell's `stealthy_fetch()` | Use `fetch` instead. |
| MCP tools | Update tool names, screenshot calls, and session creation response handling. |
| `response.follow()` after a POST or a request with query parameters | Pass the method, query, and body again when you need them. |
| Saved crawl checkpoints or response caches | Start a fresh crawl when your requests use the changed fingerprint inputs. |
| `robots_txt_obey=True` | Handle robots.txt fetch failures, which now block crawling for that domain. |

## Browser fetching {#browser-fetching}

### Replace the dynamic browser classes {#replace-the-dynamic-browser-classes}

The plain Playwright browser backend has been removed. All browser fetching now uses the Patchright-based stealthy backend.

| Removed API | Replacement |
| --- | --- |
| `scrapling.DynamicFetcher` | `scrapling.StealthyFetcher` |
| `scrapling.fetchers.DynamicFetcher` | `scrapling.fetchers.StealthyFetcher` |
| `scrapling.fetchers.chrome.PlayWrightFetcher` | `scrapling.fetchers.StealthyFetcher` |
| `scrapling.fetchers.DynamicSession` | `scrapling.fetchers.StealthySession` |
| `scrapling.fetchers.AsyncDynamicSession` | `scrapling.fetchers.AsyncStealthySession` |

The `scrapling.fetchers.chrome` module and the private `_browsers._controllers` module are gone. Use the public imports above.

**Before:**

```python
from scrapling.fetchers import DynamicFetcher

page = DynamicFetcher.fetch("https://example.com", headless=True)
```

**Now:**

```python
from scrapling.fetchers import StealthyFetcher

page = StealthyFetcher.fetch("https://example.com", headless=True)
```

For sessions, replace `DynamicSession` with `StealthySession`, or `AsyncDynamicSession` with `AsyncStealthySession`. Make the same change in your spider's `configure_sessions()` method. The `fetch()` and `async with` patterns still apply.

If your callbacks import browser types or catch browser errors, change `playwright.sync_api` to `patchright.sync_api`, or `playwright.async_api` to `patchright.async_api`. This includes `Page`, `Locator`, `Error`, and `TimeoutError`.

Patchright evaluates JavaScript in an isolated context by default. If a callback reads the page's own JavaScript variables, use `page.evaluate(..., isolated_context=False)`.

This changes the browser's behavior as well as its import name. Review your browser flags and fingerprint settings. Cloudflare solving still requires `solve_cloudflare=True`; it is not enabled by default. Also, `extra_flags` now adds to the built-in stealth flags instead of replacing them.

See [Browser fetching](fetching/stealthy.md) for the current options.

### Replace XHR capture with session network history {#replace-xhr-capture-with-session-network-history}

The `capture_xhr` parameter and `Response.captured_xhr` attribute have been removed. Remove the parameter even when its value is `None`. A one-shot fetch no longer has an XHR list attached to its response.

Custom integrations that call `ResponseFactory.from_playwright_response()` or `ResponseFactory.from_async_playwright_response()` must also remove `xhr_captured`. Pass `collect_history` by name to avoid the changed positional argument order.

**Before:**

```python
from scrapling.fetchers import StealthyFetcher

page = StealthyFetcher.fetch("https://example.com", capture_xhr="/api/")
for response in page.captured_xhr:
    print(response.url, response.body)
```

**Now:**

```python
from scrapling.fetchers import StealthySession

with StealthySession(record_requests=True) as session:
    page = session.fetch("https://example.com", network_idle=True)
    for response in session.network.search(url_pattern=r"/api/", limit=None):
        print(response.url, response.body)
```

Use `AsyncStealthySession` and `await session.fetch(...)` for async code. Reading `session.network` does not need `await`.

There are a few important differences:

- Set `record_requests=True` when you create the session. It is a session setting, not a per-fetch setting.
- History belongs to the **whole session**, across tabs, page loads, and actions. Use `after_id`, filters, or `session.network.clear()` if you need a smaller scope.
- Move the old `capture_xhr` regular expression to `url_pattern` when you search the history.
- `search()` returns saved `Response` objects. Read `.url`, `.status`, `.headers`, `.body`, or `.json()` directly. The recording ID, resource type, and sent body are in `response.meta["network_id"]`, `response.meta["resource_type"]`, and `response.meta["request_body"]`.
- Python history includes all resource types by default. Use `resource_type="xhr"` or `resource_type="fetch"` to select one, or `include_static=False` for XHR/fetch requests plus HTTP errors.
- `search()` returns at most 100 matches by default. Pass `limit=None` for all retained matches. Sessions retain at most 1,000 requests by default; change this with `max_recorded_requests`.
- Only completed requests are saved. Body capture is limited to supported text content types, 1 MiB per response, and 20 MiB of total retained body data. Older records can be removed as limits are reached. Check `response.meta.get("body_note")` for the reason a body was skipped.
- Reading history or closing the session does not wait for pending captures. Wait for the data you need before reading it. Saved Python history remains readable after session close.

See [Network history](fetching/stealthy.md#network-history) for filters and limits.

## Parser settings {#parser-settings}

### Remove `keep_cdata` {#remove-keep_cdata}

`keep_cdata` has been removed from `Selector`, fetcher configuration, and the settings returned by `display_config()`. Remove it from direct parser calls, `Fetcher.configure(...)`, and `selector_config` dictionaries passed to fetchers or integrations.

**Before:**

```python
from scrapling import Selector

page = Selector("<p>Hello</p>", keep_cdata=True)
```

**Now:**

```python
from scrapling import Selector

page = Selector("<p>Hello</p>")
```

There is no replacement setting. It did not affect the HTML parser's output. If you passed parser options by position, remove the old `keep_cdata` argument and use names for `adaptive` and storage options.

## Command line and interactive shell {#command-line-and-interactive-shell}

### Use `fetch` for browser requests {#use-fetch-for-browser-requests}

The CLI now has one browser command: `scrapling extract fetch`. It uses `StealthyFetcher`.

**Before:**

```bash
scrapling extract stealthy-fetch "https://example.com" page.md
```

**Now:**

```bash
scrapling extract fetch "https://example.com" page.md
```

If you already use `scrapling extract fetch`, the command name stays the same, but its backend changes from `DynamicFetcher` to `StealthyFetcher`. Options such as `--solve-cloudflare` now belong to `fetch`.

In `scrapling shell`, replace `stealthy_fetch(...)` with `fetch(...)`. The existing `fetch(...)` shortcut now calls `StealthyFetcher.fetch`. The dynamic classes are no longer added to the shell namespace.

### Read Markdown and text files as UTF-8 {#read-markdown-and-text-files-as-utf-8}

The extract commands and `Convertor.write_content_to_file()` now write `.md` and `.txt` files as **UTF-8**, regardless of the source page's charset. Update any code that reads those files with the page's original encoding. `.html` output still uses `page.encoding`.

Markdown from multiple selected elements now has blank lines between elements. This applies to `Response.markdown()` and Markdown file output. Update exact output comparisons or stored hashes that depended on concatenated text.

## MCP server {#mcp-server}

Update saved prompts, tool allowlists, wrappers, and MCP client tool definitions. Restart or reconnect your MCP client after the server update so it reads the current tools.

### Update tool names and bulk calls {#update-tool-names-and-bulk-calls}

| v0.4.15 tool | v0.5 replacement |
| --- | --- |
| `fetch`, `stealthy_fetch` | `browser_fetch_once` |
| `open_session` | `browser_open` |
| `session_fetch` | `browser_fetch` |
| `screenshot` | `browser_screenshot` |
| `bulk_fetch`, `bulk_stealthy_fetch` | One `browser_fetch_once` call per URL, or repeated `browser_fetch` calls through an open session |
| `bulk_get` | One `make_request` or `session_make_request` call per URL |

All bulk tools have been removed. Single-URL fetch tools return one `ResponseModel` with `status`, `content`, and `url`, not a list of responses. `content` itself is still a list of strings.

All MCP browser tools now use the stealthy backend. Remove `session_type` from calls to `browser_open`; there is no dynamic-browser choice. Its result has `session_type="stealthy"`. HTTP sessions still use `open_request_session` and return `session_type="static"`.

Python integrations must also stop importing `BrowserSessionType`, which was removed. `SessionType` now accepts only `"stealthy"` and `"static"`.

Calls through one browser session must run in order because they share a page. Close sessions with `close_session` when you finish.

### Read settings through `list_sessions` {#read-settings-through-list_sessions}

`browser_open` and `open_request_session` now return only:

```json
{
  "session_id": "my-session",
  "session_type": "stealthy"
}
```

The creation result no longer includes `created_at`, `is_alive`, `settings`, or `message`. Call `list_sessions` for the first three fields. The confirmation `message` is gone. Code that assumed `SessionCreatedModel` had all the fields of `SessionInfo` must change too.

### Fetch before taking a screenshot {#fetch-before-taking-a-screenshot}

`browser_screenshot` captures the **current page without reloading it**. It no longer accepts a URL or the old navigation and wait options: `wait`, `wait_selector`, `wait_selector_state`, and `network_idle`.

Use this order:

1. Call `browser_open`.
2. Call `browser_fetch` with the URL and any page-load options.
3. If needed, call `browser_actions` to interact with the page or wait for content.
4. Call `browser_screenshot` with the session ID.
5. Call `close_session` when you finish.

For example, the arguments for a full-page screenshot are:

```json
{
  "session_id": "my-session",
  "full_page": true
}
```

`timeout` on this tool now limits the screenshot operation. It does not load a page. For an element screenshot, use either `selector` or `ref`, and do not set `full_page=true`.

Screenshots still return image and text content blocks, with the current page URL in the text block. They do not return a fetch `ResponseModel`.

See the [MCP guide](ai/mcp-server.md) and [API reference](api-reference/mcp-server.md) for the full schemas.

## Spiders and HTTP requests {#spiders-and-http-requests}

### Pass request data again when following a link {#pass-request-data-again-when-following-a-link}

`response.follow()` no longer copies `method`, `params`, `data`, `json`, `files`, or `multipart` from the previous request. It also removes inherited `Content-Length` headers from `headers` and `extra_headers`.

A followed link now starts as a plain GET unless you pass request data explicitly. Other shared settings, such as the session, proxy, and callbacks, still follow the existing inheritance rules.

If your old code relied on inherited POST data, change:

```python
yield response.follow("/next")
```

to:

```python
yield response.follow("/next", method="POST", json={"page": 2})
```

Pass `params` explicitly too when the next request needs them. Let the HTTP client calculate the new `Content-Length`.

### Check request fingerprints and saved crawl state {#check-request-fingerprints-and-saved-crawl-state}

A request fingerprint is the key used to detect duplicate requests and find cached responses. Its inputs now handle three cases differently:

- `params` are merged into the URL before the key is built. Requests to the same URL with different query parameters are no longer treated as duplicates by default.
- JSON bodies such as `{}`, `[]`, `false`, `0`, and `""` are kept in the key. They no longer share the key for a missing body. `None` still means no JSON body.
- When `fp_include_headers=True`, changing only the insertion order of headers no longer changes the key.

If your crawl uses these inputs, finish it before upgrading or start a new crawl with a fresh checkpoint and response cache directory. Old saved keys can differ from the new keys. This is a change to request identity, not a new checkpoint file format.

Development mode now writes responses to the cache only after the blocked-response check. Blocked pages are not saved as successful cached results. Existing cache files are not cleaned for you; clear stale entries if you previously cached a challenge page.

Failed crawls now retain their checkpoint files. Check your cleanup code if it assumed those files disappear after an error. See [Pause and resume](spiders/advanced.md#pause-resume) and [Development mode](spiders/advanced.md#development-mode).

### Check robots.txt failures {#check-robotstxt-failures}

With `robots_txt_obey=True`, a robots.txt fetch exception or a response other than HTTP 200 or 4xx now blocks requests to that domain. Previously, those failures allowed crawling. HTTP 200 still supplies the rules, and HTTP 4xx still allows access.

The result is cached for the whole crawl. Fix the robots.txt access problem and start a new crawl; later requests in the same crawl will not retry the failed lookup. This does not change the default `robots_txt_obey=False`.

### Check link restrictions and sitemap callbacks {#check-link-restrictions-and-sitemap-callbacks}

- A `LinkExtractor` restriction that matches nothing now returns no links. It no longer falls back to the whole page. Fix the `restrict_css` or `restrict_xpath` expression if your crawl now finds fewer links.
- A restriction can now select the link element itself, not just a parent. This can add links that were previously missed. Review expected URL sets.
- `SitemapSpider` now sends page URLs to `parse()` when there are no rules, or when a matching rule has `callback=None`. It no longer sends those HTML pages back to the sitemap parser. Implement `parse()` for those cases and remove workarounds for the old routing.
- A leading Unicode byte-order mark is removed from robots.txt and CSV feeds. The first robots directive now takes effect, and the first CSV header no longer starts with `\ufeff`. If you set custom `headers`, the mark is removed from the first field value instead. Update code that worked around that hidden prefix. Sitemap XML comments and processing instructions are also skipped instead of causing a parse failure.

### Check form data, headers, and CLI JSON {#check-form-data-headers-and-cli-json}

Dictionary form data now expands list and tuple values into repeated keys. For example, `data={"tag": ["a", "b"]}` sends `tag=a&tag=b`. An empty list sends no entry for that key. A default `Content-Type: application/x-www-form-urlencoded` is added when you have not supplied one.

If you need a different wire format, pass an explicitly encoded string or bytes. `json`, raw `content`, and multipart uploads keep their own body handling. `None` values are **not dropped** from form data or query parameters; they remain the string `None`.

Per-request HTTP headers now override session headers regardless of letter case. A request header named `authorization` replaces the session's `Authorization` instead of sending both. Remove code that worked around duplicate header names.

CLI JSON values `{}`, `[]`, `false`, `0`, and `""` are now sent instead of silently dropped. Also, `curl2fetcher()` now applies curl's `-A` user agent and correctly passes `-x` proxies as a URL string. An explicit curl `-H 'User-Agent: ...'` still takes priority over `-A`.

## Other output changes to check {#other-output-changes-to-check}

These fixes do not remove APIs, but they can change stored results and exact output tests:

- Generated CSS and XPath selectors now include `:nth-of-type(1)` or `[1]` when needed to identify the first of several same-tag siblings. Refresh expected selector strings; do not remove the new position marker.
- Cleaned AI content now keeps visible elements with values such as `opacity:0.95`, removes elements hidden by more forms of inline styles and `<slot hidden>` elements, and removes all matching noise tags even when they are nested. Recheck exact Markdown, text, and sanitized HTML output.
- Browser response conversion now reads charset declarations with different letter case, spaces, or quoted values, such as `text/plain; CHARSET = "iso-8859-15"`. Non-HTML responses with these headers now use the declared encoding instead of falling back to UTF-8. Recheck text decoded from those responses.

## Verify your upgrade {#verify-your-upgrade}

Run a small crawl before your full job. Check the extracted data, followed URLs, sent request bodies, saved file encoding, and any cache or checkpoint behavior you depend on. For MCP integrations, check both tool inputs and returned data against the current schemas.

For older release changes, see the [changelog](changelog.md).

---

### Requirements (`docs/requirements.txt`)

zensical>=0.0.70
mkdocstrings>=1.0.6
mkdocstrings-python>=2.0.5
griffe-inherited-docstrings>=1.1.3
griffe-runtime-objects>=0.3.1
griffe-sphinx>=0.2.1
black>=26.1.0
pngquant

---

### Ai Agent Skill (`docs/ai/agent-skill.md`)

---
title: "Scrapling Agent Skill: Install and Use"
description: "Install the Scrapling skill for your coding agent. Give it current API examples and references for fetching, parsing and crawling."
---

# Scrapling Agent Skill

While the [MCP server](mcp-server.md) gives AI chatbots tools to scrape websites for you, the **Scrapling Agent Skill** teaches coding agents the library itself, so the code they write with Scrapling matches the current API instead of guessing from outdated training data.

The skill follows the [AgentSkills](https://agentskills.io/specification) specification, so it's readable by [Claude Code](https://claude.com/product/claude-code), [OpenClaw](https://github.com/openclaw/openclaw), and other agentic tools. It packages guides for fetching, parsing, crawls, MCP, and RAG as Markdown references that the agent loads on demand, together with ready-to-run examples, so it can answer most Scrapling questions and write correct scraping code without leaving your editor.

The skill lives in the [agent-skill](https://github.com/D4Vinci/Scrapling/tree/main/agent-skill) directory of the repository under the name `scrapling-official`, and its version always tracks the library version.

## Installation

### Skills.sh

Install the skill from the repository with the [skills.sh](https://skills.sh) CLI:
```bash
npx skills add D4Vinci/Scrapling --skill scrapling-official
```
The CLI detects the agents you have installed and adds the skill to them.

### Clawhub

If you use OpenClaw, you can install the skill through [Clawhub](https://docs.openclaw.ai/tools/clawhub):
```bash
clawhub install scrapling-official
```
Or install it from its [Clawhub page](https://clawhub.ai/D4Vinci/scrapling-official).

### Manual download

Download the skill's ZIP file [directly from the repository](https://github.com/D4Vinci/Scrapling/raw/refs/heads/main/agent-skill/Scrapling-Skill.zip) and extract it into your agent's skills directory (for Claude Code, that's `~/.claude/skills/`).

## What's inside

- **`SKILL.md`**: The entry point the agent reads first. It covers setup, which fetcher to choose, and the safety rules the agent must follow, like always passing `--ai-targeted` to the CLI commands for prompt injection protection.
- **`references/`**: Markdown mirrors of the documentation pages (parsing, fetching, spiders, MCP server, and integrations), loaded on demand so they don't consume the agent's context until needed.
- **`examples/`**: Ready-to-run scripts the agent can copy from.

We tested the skill on OpenClaw and Claude Code. If you face any issues with it, open a [ticket](https://github.com/D4Vinci/Scrapling/issues/new/choose) or reach out on our [Discord server](https://discord.gg/EMgGbDceNQ).

---

### Ai Building Rag Systems (`docs/ai/building-rag-systems.md`)

---
title: "Crawl Websites into Markdown for RAG with Scrapling"
description: "Convert page responses to Markdown or use ContentSpider to collect a website. Prepare a corpus for chunking and indexing in a RAG system."
---

# Building RAG Systems with Scrapling

RAG pipelines are only as good as the text you feed them. Raw HTML wastes tokens on markup, navigation, scripts, and tracking noise, and it can even carry hidden prompt-injection content straight into your LLM. Scrapling turns pages and whole websites into clean, sanitized Markdown with no LLM in the loop, so your ingestion runs fast and costs nothing per page.

## Installation

```bash
pip install "scrapling[rag]"

scrapling install
```

The `rag` extra installs the fetchers with Markdown conversion support (the `ai`, `shell`, and `all` extras include it too). The `scrapling install` command downloads the browser dependencies, which you only need for the browser-based fetchers.

## One page to Markdown

Every [Response](../fetching/choosing.md#response-object) has a `markdown()` method:

```python
from scrapling.fetchers import Fetcher

markdown = Fetcher.get("https://example.com").markdown(main_content_only=True)
```

It works with all fetchers, so pages behind Cloudflare are one line away too:

```python
from scrapling.fetchers import StealthyFetcher

markdown = StealthyFetcher.fetch("https://protected.example.com", solve_cloudflare=True).markdown(main_content_only=True)
```

Two arguments control the output:

- `main_content_only`: Convert only the content inside the page's `<body>` tag.
- `css_selector`: Convert only the elements matching a CSS selector (all matches are concatenated). Use it to extract exactly the part your pipeline needs and save tokens:

```python
markdown = Fetcher.get("https://example.com/docs/page").markdown(css_selector="article")
```

Whatever you pass, scripts, styles, and hidden content are always removed before conversion. This is the same cleaning the [MCP server](mcp-server.md) uses to protect AI agents from prompt injection: inline hidden elements, `aria-hidden="true"` elements, hidden slots, `<template>` tags, HTML comments, and zero-width characters are removed before conversion. The MCP server uses this cleaning with `main_content_only=True`.

## A whole website to a Markdown corpus

The `ContentSpider` template crawls a website and converts every page, powered by the [spiders framework](../spiders/architecture.md), so you get concurrency, autothrottle, robots.txt compliance, and pause/resume for free:

```python
from scrapling.spiders import ContentSpider

class DocsSpider(ContentSpider):
    name = "docs"
    start_urls = ["https://example.com/docs/"]
    allowed_domains = {"example.com"}
    output_dir = "docs_markdown"
    max_pages = 200

result = DocsSpider().start()
result.items.to_jsonl("docs.jsonl")
```

Each crawled page becomes one item with `url`, `title`, and `markdown` keys. With `output_dir` set, each page is also written to a Markdown file named after its URL, so the run above gives you both a folder of `.md` files and a `docs.jsonl` ready for ingestion.

The template requires `allowed_domains` so the crawl stays bound to the target website. The options:

- `css_selector` / `main_content_only`: Passed to `markdown()` for every page, with `main_content_only` enabled by default.
- `output_dir`: When set, writes one Markdown file per page.
- `max_pages`: Maximum number of pages to convert. Requests already queued when the cap hits may still be fetched, but they aren't converted. `0` (the default) disables it.

Every page link inside `allowed_domains` is followed by default. Since the template builds on [CrawlSpider](../spiders/generic-templates.md#crawlspider), override `rules()` with your own [LinkExtractor](../spiders/generic-templates.md#linkextractor-reference) to control the crawl: `allow` narrows it to the URL patterns you want, and `deny` drops the patterns you don't (login pages, tag listings, print views, etc.):

```python
from scrapling.spiders import CrawlRule, LinkExtractor, ContentSpider

class DocsSpider(ContentSpider):
    name = "docs"
    start_urls = ["https://example.com/"]
    allowed_domains = {"example.com"}

    def rules(self):
        return [CrawlRule(LinkExtractor(allow=r"/docs/", deny=[r"/docs/changelog/", r"\?print="]))]
```

`deny` wins over `allow`, and a rule can carry a `priority` or a `process_request` hook as with any **CrawlSpider**.

## Feeding a vector store

The JSONL output plugs into any embedding pipeline. A minimal example:

```python
import json

with open("docs.jsonl", encoding="utf-8") as f:
    for line in f:
        page = json.loads(line)
        for chunk in split_into_chunks(page["markdown"]):
            vector_store.add(text=chunk, metadata={"url": page["url"], "title": page["title"]})
```

Use `css_selector` on the spider to cut boilerplate before chunking instead of cleaning it downstream. The less noise you embed, the better your retrieval.

## Interactive alternatives

For conversational scraping instead of pipelines, the [MCP server](mcp-server.md) gives your AI chatbot the same Markdown extraction as tools, and the [Agent skill](agent-skill.md) teaches coding agents to write this code themselves.

---

--- METRICS ---
- Files Extracted: 23
- Estimated Token Budget: ~126274 tokens
- Canonical Reference: https://codewiki.google/github.com/D4Vinci/Scrapling
