Screaming Frog ज़्यादातर SEOs के लिए पसंदीदा क्रॉलर है, लेकिन आपने शायद इसकी सीमाओं को महसूस किया है: मुफ्त वर्जन पर 500-URL की लिमिट, बड़ी साइट्स पर RAM का ओवरलोड होना, या GUI की निगरानी के बिना क्रॉल्स को ऑटोमेट करने की इच्छा। Scrapy वह ओपन-सोर्स Python फ्रेमवर्क है जो इन सीमाओं को हटाता है।
अगर आप npm install या git clone चला सकते हैं, तो आप Scrapy चला सकते हैं। लर्निंग कर्व असली है लेकिन मैनेज करने योग्य है, खासकर अगर आप एजेंटिक कोडिंग वर्कफ्लो के माध्यम से CLI टूल्स के साथ पहले से सहज हो रहे हैं।
Scrapy क्यों?
Screaming Frog त्वरित ऑडिट के लिए अच्छा काम करता है। लेकिन इसकी सीमाएं हैं:
| सीमा | प्रभाव |
|---|---|
| 500 URL मुफ्त लिमिट | बड़ी साइट्स के लिए $259/वर्ष लाइसेंस की आवश्यकता |
| मेमोरी-हंग्री | बड़े क्रॉल्स 8GB+ RAM खपत कर सकते हैं |
| GUI-डिपेंडेंट | ऑटोमेट या शेड्यूल करना मुश्किल |
| सीमित कस्टमाइज़ेशन | कॉन्फ़िगरेशन विकल्प फिक्स्ड हैं |
Scrapy इन्हें हल करता है:
| Scrapy | आपको क्या मिलता है |
|---|---|
| मुफ्त और ओपन-सोर्स | कोई URL लिमिट नहीं, कोई लाइसेंस फीस नहीं |
| कम मेमोरी फुटप्रिंट | डिस्क-बैक्ड क्यू RAM को नियंत्रण में रखते हैं |
| CLI-नेटिव | स्क्रिप्टेबल, cron-एबल, CI/CD-रेडी |
| पूर्ण Python कस्टमाइज़ेशन | जो चाहिए एक्सट्रैक्ट करें, जैसे चाहें फ़िल्टर करें |
| पॉज़/रिज़्यूम | बड़े क्रॉल्स को कभी भी रोकें और जारी रखें |
इंस्टॉलेशन
Scrapy Python पर चलता है। चीज़ों को साफ रखने के लिए वर्चुअल एनवायरनमेंट का उपयोग करें:
Debian/Ubuntu:
sudo apt install python3.11-venv
python3 -m venv venv
source venv/bin/activate
pip install scrapy
macOS:
python3 -m venv venv
source venv/bin/activate
pip install scrapy
Windows:
python -m venv venv
venv\Scripts\activate
pip install scrapy
प्रोजेक्ट बनाना
Scrapy इंस्टॉल होने के बाद:
scrapy startproject myproject
cd myproject
scrapy genspider sitename example.com
यह बनाता है:
myproject/
scrapy.cfg
myproject/
__init__.py
items.py
middlewares.py
pipelines.py
settings.py
spiders/
__init__.py
sitename.py
Spider कोड spiders/sitename.py में जाता है। कॉन्फ़िगरेशन settings.py में रहता है।
पोलाइट क्रॉलिंग के लिए सेटिंग्स
कुछ भी चलाने से पहले settings.py कॉन्फ़िगर करें। ब्लॉक होना धीमे क्रॉलिंग से ज़्यादा समय बर्बाद करता है।
# पोलाइट क्रॉलिंग
CONCURRENT_REQUESTS_PER_DOMAIN = 5
DOWNLOAD_DELAY = 1
ROBOTSTXT_OBEY = True
# AutoThrottle - सर्वर रिस्पॉन्स के आधार पर स्पीड एडजस्ट करता है
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 5
AUTOTHROTTLE_MAX_DELAY = 60
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
AUTOTHROTTLE_DEBUG = True
# सेफ्टी लिमिट्स
CLOSESPIDER_PAGECOUNT = 10000
# आउटपुट
FEED_EXPORT_ENCODING = "utf-8"
AutoThrottle
AutoThrottle सर्वर रिस्पॉन्स टाइम को मॉनिटर करता है और क्रॉल स्पीड को ऑटोमैटिकली एडजस्ट करता है:
- फास्ट रिस्पॉन्स → स्पीड अप
- स्लो रिस्पॉन्स → स्लो डाउन
- एरर्स/टाइमआउट्स → काफी स्लो डाउन
Screaming Frog के फिक्स्ड डिले के विपरीत, यह वास्तविक सर्वर कंडीशंस के अनुसार एडाप्ट होता है।
स्टेटस कोड हैंडलिंग
डिफ़ॉल्ट रूप से, Scrapy का HttpErrorMiddleware नॉन-2xx रिस्पॉन्सेस को चुपचाप ड्रॉप कर देता है। इसका मतलब 404s, 301s, 500s आपके callback तक पहुंचने से पहले ही हटा दिए जाते हैं। आपका क्रॉल 100% 200 स्टेटस कोड दिखा सकता है, इसलिए नहीं कि साइट परफेक्ट है, बल्कि इसलिए कि एरर्स फ़िल्टर किए जा रहे हैं।
सभी स्टेटस कोड्स कैप्चर करने के लिए यह अपनी spider क्लास में जोड़ें:
handle_httpstatus_list = [200, 301, 302, 403, 404, 500, 502, 503]
Screaming Frog डिफ़ॉल्ट रूप से सभी स्टेटस कोड्स कैप्चर करता है। यह सेटिंग Scrapy को उस व्यवहार के साथ अलाइन करती है।
रियल-वर्ल्ड परफॉर्मेंस
5 कॉनकरेंट रिक्वेस्ट्स और AutoThrottle इनेबल के साथ टेस्ट क्रॉल के वास्तविक नंबर:
| क्रॉल प्रोग्रेस | पेज/मिनट | नोट्स |
|---|---|---|
| 0-200 पेज | 14-22 | रैंप-अप |
| 200-500 पेज | 10-12 | स्टेबलाइज़िंग |
| 500-1,000 पेज | 7-10 | AutoThrottle एडजस्टिंग |
| 1,000+ पेज | 5-7 | स्टेडी स्टेट |
फीचर कम्पैरिज़न
| फीचर | Screaming Frog | Scrapy |
|---|---|---|
| कॉस्ट | मुफ्त <500 URLs, ~$259/वर्ष | मुफ्त, ओपन सोर्स |
| मैक्स क्रॉल साइज़ | मेमोरी-लिमिटेड | डिस्क-बैक्ड क्यू |
| कस्टमाइज़ेशन | लिमिटेड कॉन्फिग ऑप्शंस | फुल Python कोड |
| शेड्यूलिंग | मैनुअल या थर्ड-पार्टी | नेटिव CLI, cron-एबल |
| पॉज़/रिज़्यूम | हां | हां (JOBDIR के साथ) |
| लर्निंग कर्व | लो (GUI) | मीडियम (कोड) |
| रेट लिमिटिंग | बेसिक फिक्स्ड डिले | AutoThrottle (एडैप्टिव) |
| JavaScript रेंडरिंग | ऑप्शनल (Chrome) | ऑप्शनल (playwright/splash) |
| स्टेटस कोड्स | सभी डिफ़ॉल्ट रूप से | कॉन्फ़िगरेशन आवश्यक |
| सबडोमेन फ़िल्टरिंग | GUI चेकबॉक्स | कोड (फ्लेक्सिबल regex) |
| एक्सपोर्ट फॉर्मेट्स | CSV, Excel, etc. | JSON, CSV, XML, कस्टम |
| CI/CD इंटीग्रेशन | मुश्किल | नेटिव |
URL फ़िल्टरिंग
Screaming Frog चेकबॉक्स उपयोग करता है। Scrapy कोड उपयोग करता है। ट्रेडऑफ है लर्निंग कर्व प्रिसीज़न के लिए।
इंटरनेशनल पाथ्स को एक्सक्लूड करना:
import re
from urllib.parse import urlparse
class MySiteSpider(scrapy.Spider):
name = "mysite"
allowed_domains = ["example.com", "www.example.com"]
start_urls = ["https://www.example.com/"]
# /uk/, /fr/, /de/ जैसे इंटरनेशनल पाथ्स स्किप करें
EXCLUDED_PATTERNS = re.compile(
r"/(in|au|th|es|hk|sg|ph|my|ca|cn|uk|kr|id|fr|vn|de|jp|nl|it|tw)/"
)
def filter_links(self, links):
filtered = []
for link in links:
hostname = urlparse(link.url).hostname or ""
if hostname not in ("example.com", "www.example.com"):
continue
if self.EXCLUDED_PATTERNS.search(link.url):
continue
filtered.append(link)
return filtered
आप URL पैटर्न्स, क्वेरी पैरामीटर्स, रिस्पॉन्स हेडर्स, पेज कंटेंट या किसी भी कॉम्बिनेशन से फ़िल्टर कर सकते हैं।
साइटमैप इंटीग्रेशन
Screaming Frog में एक सिंपल “use sitemap” चेकबॉक्स है। Scrapy को कस्टम कोड की ज़रूरत है, लेकिन यह आपको साइटमैप्स को पार्स करने और अपने क्रॉल के साथ इंटीग्रेट करने पर पूर्ण नियंत्रण देता है।
साइटमैप सपोर्ट क्यों जोड़ें?
- मुख्य नेविगेशन से लिंक नहीं किए गए URLs खोजता है
- ऑर्फन पेज ढूंढता है जो लिंक-बेस्ड क्रॉलिंग मिस कर देगी
- तुलना के लिए साइट की “ऑफिशियल” URL लिस्ट मिलती है
- केवल लिंक्स फॉलो करने से ज़्यादा पेज मिल सकते हैं
- पूर्ण SEO ऑडिट के लिए आवश्यक
साइटमैप डिटेक्शन और पार्सिंग इनेबल करने के लिए अपने CrawlSpider में ये मेथड्स जोड़ें:
def start_requests(self):
# First, fetch robots.txt to find sitemaps
yield Request(
"https://www.example.com/robots.txt",
callback=self.parse_robots,
errback=self.handle_error,
dont_filter=True,
)
# Also try common sitemap locations directly
common_sitemaps = [
"https://www.example.com/sitemap.xml",
"https://www.example.com/sitemap_index.xml",
]
for sitemap_url in common_sitemaps:
yield Request(
sitemap_url,
callback=self.parse_sitemap,
errback=self.handle_error,
meta={"sitemap_url": sitemap_url},
)
# Also start normal crawl from homepage
for url in self.start_urls:
yield Request(url, callback=self.parse_start_url)
def parse_robots(self, response):
"""Parse robots.txt to find sitemap declarations"""
if response.status != 200:
return
for line in response.text.splitlines():
line = line.strip()
if line.lower().startswith("sitemap:"):
sitemap_url = line.split(":", 1)[1].strip()
if self.is_valid_url(sitemap_url):
self.logger.info(f"Found sitemap in robots.txt: {sitemap_url}")
yield Request(
sitemap_url,
callback=self.parse_sitemap,
errback=self.handle_error,
meta={"sitemap_url": sitemap_url},
)
def parse_sitemap(self, response):
"""Parse XML sitemap or sitemap index"""
if response.status != 200:
return
content_type = response.headers.get("Content-Type", b"").decode("utf-8", errors="ignore")
# Check if this is XML content
if "xml" not in content_type and not response.text.strip().startswith("<?xml"):
return
# Check for sitemap index (contains other sitemaps)
sitemap_locs = response.xpath("//sitemap/loc/text()").getall()
if sitemap_locs:
self.logger.info(f"Found sitemap index with {len(sitemap_locs)} sitemaps")
for loc in sitemap_locs:
if self.is_valid_url(loc):
yield Request(
loc,
callback=self.parse_sitemap,
errback=self.handle_error,
meta={"sitemap_url": loc},
)
# Parse URL entries from sitemap
url_locs = response.xpath("//url/loc/text()").getall()
if url_locs:
self.logger.info(f"Found {len(url_locs)} URLs in sitemap: {response.url}")
for loc in url_locs:
if self.is_valid_url(loc) and self.should_crawl_url(loc):
yield Request(
loc,
callback=self.parse_page,
errback=self.handle_error,
)
def parse_start_url(self, response):
"""Handle the start URL and trigger rules"""
yield from self.parse_page(response)
yield from self._requests_to_follow(response)
def is_valid_url(self, url):
"""Check if URL is valid and within allowed domains"""
try:
parsed = urlparse(url)
hostname = parsed.hostname or ""
return hostname in ("example.com", "www.example.com")
except Exception:
return False
def should_crawl_url(self, url):
"""Apply the same filtering as filter_links"""
if self.EXCLUDED_PATTERNS.search(url):
return False
return True
def handle_error(self, failure):
"""Handle request errors gracefully"""
self.logger.warning(f"Request failed: {failure.request.url}")
यह कैसे काम करता है:
start_requests()पहले साइटमैप्स फेच करने के लिए डिफ़ॉल्ट व्यवहार को ओवरराइड करता हैparse_robots()robots.txt मेंSitemap:लाइनें ढूंढता हैparse_sitemap()साइटमैप इंडेक्सेस और रेगुलर साइटमैप्स दोनों हैंडल करता है- XPath
//sitemap/locसाइटमैप इंडेक्स फाइल्स में नेस्टेड साइटमैप्स ढूंढता है - XPath
//url/locवास्तविक पेज URLs ढूंढता है - साइटमैप URLs पर भी वही डोमेन और पैटर्न फ़िल्टरिंग लागू होती है
- Scrapy का बिल्ट-इन deduplication साइटमैप और लिंक्स दोनों में मिले पेजों को डबल-क्रॉलिंग से रोकता है
| फीचर | Screaming Frog | Scrapy |
|---|---|---|
| साइटमैप डिटेक्शन | चेकबॉक्स | कस्टम कोड |
| robots.txt पार्सिंग | ऑटोमैटिक | कस्टम कोड |
| साइटमैप इंडेक्स सपोर्ट | हां | हां (कोड के साथ) |
| URL फ़िल्टरिंग | GUI ऑप्शंस | कोड (पूर्ण नियंत्रण) |
| क्रॉल के साथ मर्ज | हां | हां |
| कस्टम साइटमैप लोकेशन्स | मैनुअल एंट्री | कोई भी लोकेशन कोड करें |
साइटमैप इंटीग्रेशन के साथ, आप नेविगेशन से लिंक नहीं किए गए ऑर्फन पेज, साइटमैप्स में अभी भी लिस्टेड पुराना आर्काइव्ड कंटेंट, trailing slashes के साथ या बिना URL वेरिएशंस, और robots.txt द्वारा ब्लॉक लेकिन साइटमैप में मौजूद पेज खोज सकते हैं। यह SEO ऑडिट के लिए साइट की अधिक पूर्ण तस्वीर देता है।
पॉज़ और रिज़्यूम
1,000 पेजों से ज़्यादा के क्रॉल्स के लिए, JOBDIR के साथ पॉज़/रिज़्यूम इनेबल करें:
scrapy crawl myspider -o output.json -s JOBDIR=crawl_state
Scrapy crawl_state/ में स्टेट सेव करता है। पॉज़ करने के लिए Ctrl+C दबाएं। रिज़्यूम करने के लिए वही कमांड चलाएं।
स्टेट में पेंडिंग URLs, देखे गए URLs और रिक्वेस्ट क्यू शामिल है। यह Screaming Frog की सेव/लोड फीचर से ज़्यादा रोबस्ट है क्योंकि यह फाइल-बेस्ड है और सिस्टम रीस्टार्ट्स में भी बना रहता है।
JavaScript रेंडरिंग
Scrapy केवल रॉ HTML फेच करता है। यह JavaScript रेंडर नहीं करता। यह वही है जो curl रिटर्न करता है।
ज़्यादातर SEO क्रॉल्स के लिए, यह ठीक है:
- मेटा टैग्स, canonicals और h1s आमतौर पर इनीशियल HTML में होते हैं
- सर्च इंजन मुख्य रूप से सर्वर-रेंडर्ड कंटेंट इंडेक्स करते हैं
- ज़्यादातर ई-कॉमर्स और कंटेंट साइट्स सर्वर-रेंडर्ड होती हैं
अगर आपकी टारगेट साइट क्लाइंट-साइड कंटेंट रेंडर करती है, आपके पास ऑप्शंस हैं:
| पैकेज | नोट्स |
|---|---|
| scrapy-playwright | Chromium/Firefox/WebKit उपयोग करता है। मॉडर्न JS साइट्स के लिए रेकमेंडेड |
| scrapy-splash | लाइटवेट, Docker-बेस्ड रेंडरर |
| scrapy-selenium | पुराना अप्रोच, अभी भी काम करता है |
JS रेंडरिंग काफी धीमी और रिसोर्स-इंटेंसिव है। इसे तभी जोड़ें जब साइट को इसकी ज़रूरत हो।
Screaming Frog का भी यही ट्रेडऑफ है। JavaScript रेंडरिंग इनेबल करना Chrome को अंडर द हुड उपयोग करता है और क्रॉल्स को काफी धीमा करता है।
मेमोरी मैनेजमेंट
~1,300 पेजों पर पूर्ण फील्ड एक्सट्रैक्शन के साथ:
- मेमोरी: ~265 MB
- CPU: ~4%
JOBDIR उपयोग करने से रिक्वेस्ट क्यू डिस्क पर मूव हो जाती है, मेमोरी कम रखते हुए। बहुत बड़े क्रॉल्स (100k+ URLs) के लिए, ये सेटिंग्स जोड़ें:
MEMUSAGE_LIMIT_MB = 1024
MEMUSAGE_WARNING_MB = 800
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'
यह मेमोरी उपयोग को कैप करता है और scheduler के लिए डिस्क-बैक्ड क्यू फोर्स करता है।
आउटपुट डेटा
Scrapy आपको वो एक्सट्रैक्ट करने देता है जो आपको चाहिए। यहां एक comprehensive parse मेथड है जो common SEO फील्ड्स कैप्चर करता है:
def parse_page(self, response):
yield {
# बेसिक इन्फो
"url": response.url,
"status": response.status,
"response_time": response.meta.get("download_latency"),
# SEO फील्ड्स
"title": response.css("title::text").get(),
"meta_description": response.css('meta[name="description"]::attr(content)').get(),
"h1": response.css("h1::text").get(),
"h2_count": len(response.css("h2").getall()),
# टेक्निकल
"canonical": response.css('link[rel="canonical"]::attr(href)').get(),
"robots": response.css('meta[name="robots"]::attr(content)').get(),
"content_type": response.headers.get("Content-Type", b"").decode("utf-8"),
"word_count": len(response.css("body *::text").getall()),
# लिंक्स
"internal_links": len([
a for a in response.css("a::attr(href)").getall()
if a.startswith("/") or "example.com" in a
]),
"external_links": len([
a for a in response.css("a::attr(href)").getall()
if a.startswith("http") and "example.com" not in a
]),
}
यह Screaming Frog के “Internal:All” टैब के समान डेटा देता है, लेकिन आपके कंट्रोल में।
एक्सपोर्ट फॉर्मेट्स: JSON (-o output.json), JSON Lines (-o output.jsonl), CSV (-o output.csv), XML (-o output.xml)।
बड़े क्रॉल्स के लिए JSON Lines बेस्ट है। आप रियल-टाइम में आउटपुट मॉनिटर कर सकते हैं।
Screaming Frog → Scrapy
SF वर्कफ्लो को Scrapy में मैप करना:
| Screaming Frog एक्शन | Scrapy इक्विवेलेंट |
|---|---|
| नया क्रॉल शुरू करें | scrapy crawl spidername |
| क्रॉल डिले सेट करें | सेटिंग्स में DOWNLOAD_DELAY |
| कॉनकरेंट थ्रेड्स लिमिट करें | CONCURRENT_REQUESTS_PER_DOMAIN |
| robots.txt रिस्पेक्ट करें | ROBOTSTXT_OBEY = True |
| CSV में एक्सपोर्ट करें | -o output.csv |
| क्रॉल सेव/लोड करें | -s JOBDIR=crawl_state |
| सबडोमेन फ़िल्टर करें | spider में कोड (regex) |
| कस्टम एक्सट्रैक्शन | parse() में CSS/XPath सेलेक्टर्स |
माइंडसेट शिफ्ट्स:
- कॉन्फ़िगरेशन कोड है। चेकबॉक्स क्लिक करने के बजाय
settings.pyएडिट करें। - एक्सट्रैक्शन एक्सप्लिसिट है। आप लिखते हैं कि क्या डेटा कैप्चर करना है।
- शेड्यूलिंग नेटिव है। cron या CI/CD में कमांड्स जोड़ें।
- डीबगिंग लॉग्स है। क्या हो रहा है देखने के लिए
AUTOTHROTTLE_DEBUGइनेबल करें।
फुल वर्कफ्लो
ऊपर दी गई स्टैंडर्ड सेटिंग्स के साथ, आप 15 मिनट से कम में Scrapy इंस्टॉल और क्रॉलिंग कर सकते हैं:
python3 -m venv venv
source venv/bin/activate # Windows पर venv\Scripts\activate
pip install scrapy
scrapy startproject urlcrawler
cd urlcrawler
scrapy genspider mysite example.com
# पोलाइट क्रॉलिंग कॉन्फिग के साथ settings.py एडिट करें
# अपनी parse लॉजिक के साथ spiders/mysite.py एडिट करें
scrapy crawl mysite -o urls.jsonl -s JOBDIR=crawl_state
Scrapy Shell
जब आप कस्टम कॉन्फ़िगरेशन बना रहे हों, अपने सेलेक्टर्स और सेटिंग्स को इंटरैक्टिवली टेस्ट करने के लिए Scrapy Shell उपयोग करें:
scrapy shell "https://example.com"
यह रिस्पॉन्स पहले से लोडेड के साथ एक इंटरैक्टिव Python कंसोल खोलता है। अपने spider में जोड़ने से पहले रियल-टाइम में CSS और XPath सेलेक्टर्स टेस्ट करें:
>>> response.css('title::text').get()
'Example Domain'
>>> response.xpath('//h1/text()').get()
'Example Domain'
Scrapy Shell इटरेशन टाइम को काफी कम करता है। फुल क्रॉल्स चलाए बिना एक्सट्रैक्शन लॉजिक वैलिडेट करें।
Complete Spider Template
यहां एक production-ready spider template है जो इस गाइड की सभी best practices को combine करता है:
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from urllib.parse import urlparse
import re
class SEOSpider(CrawlSpider):
name = "seo_spider"
allowed_domains = ["example.com", "www.example.com"]
start_urls = ["https://www.example.com/"]
# सभी स्टेटस कोड्स कैप्चर करें
handle_httpstatus_list = [200, 301, 302, 403, 404, 500, 502, 503]
# इंटरनेशनल पाथ्स एक्सक्लूड करें
EXCLUDED_PATTERNS = re.compile(
r"/(in|au|th|es|hk|sg|ph|my|ca|cn|uk|kr|id|fr|vn|de|jp|nl|it|tw)/"
)
rules = (
Rule(
LinkExtractor(
allow_domains=["example.com", "www.example.com"],
deny=[r"\?", r"#"], # क्वेरी स्ट्रिंग्स और फ्रैगमेंट्स स्किप करें
),
callback="parse_page",
follow=True,
),
)
def parse_page(self, response):
# एक्सक्लूडेड पाथ्स स्किप करें
if self.EXCLUDED_PATTERNS.search(response.url):
return
yield {
# बेसिक इन्फो
"url": response.url,
"status": response.status,
"response_time": response.meta.get("download_latency"),
# SEO फील्ड्स
"title": response.css("title::text").get(),
"meta_description": response.css(
'meta[name="description"]::attr(content)'
).get(),
"h1": response.css("h1::text").get(),
"h2_count": len(response.css("h2").getall()),
# टेक्निकल
"canonical": response.css('link[rel="canonical"]::attr(href)').get(),
"robots": response.css('meta[name="robots"]::attr(content)').get(),
"content_type": response.headers.get("Content-Type", b"").decode("utf-8"),
"word_count": len(response.css("body *::text").getall()),
# लिंक्स
"internal_links": len([
a for a in response.css("a::attr(href)").getall()
if a.startswith("/") or "example.com" in a
]),
"external_links": len([
a for a in response.css("a::attr(href)").getall()
if a.startswith("http") and "example.com" not in a
]),
}
इसे spiders/seo_spider.py में सेव करें और चलाएं:
scrapy crawl seo_spider -o results.jsonl -s JOBDIR=crawl_state
कब क्या उपयोग करें
Screaming Frog:
- 500 URLs से कम के त्वरित ऑडिट
- मिनटों में रिजल्ट्स चाहिए
- विज़ुअल साइट एक्सप्लोरेशन
- CLI के साथ सहज नहीं
- Screaming Frog डेटा को Redirects.net के साथ उपयोग करना
Scrapy:
- 10,000 URLs से ज़्यादा की साइट्स
- ऑटोमेटेड, शेड्यूल्ड क्रॉल्स
- कस्टम एक्सट्रैक्शन ज़रूरतें
- CI/CD इंटीग्रेशन
- मेमोरी कंस्ट्रेंट्स
- वर्जन-कंट्रोल्ड कॉन्फिग्स
निष्कर्ष
Scrapy की सेटअप कर्व Screaming Frog से ज़्यादा स्टीप है, लेकिन यह उन प्रैक्टिकल लिमिट्स को हटाता है जो GUI क्रॉलर्स लगाते हैं। कोई URL कैप्स नहीं, कोई लाइसेंस फीस नहीं, कम मेमोरी यूसेज और नेटिव ऑटोमेशन।
छोटे से शुरू करें। जो साइट आप जानते हैं उसे क्रॉल करें। कंज़र्वेटिव सेटिंग्स उपयोग करें। आउटपुट की तुलना Screaming Frog से करें। डेटा मैच होगा, लेकिन आपके पास एक ऐसा टूल होगा जो स्केल करता है।