Screaming Frog adalah crawler pilihan untuk kebanyakan SEO, tetapi anda mungkin sudah terlanggar dindingnya: had 500-URL pada versi percuma, RAM memuncak pada laman besar, atau ingin mengautomasi crawl tanpa mengawasi GUI. Scrapy adalah rangka kerja Python sumber terbuka yang menghapuskan had tersebut.
Jika anda boleh menjalankan npm install atau git clone, anda boleh menjalankan Scrapy. Keluk pembelajaran adalah nyata tetapi boleh diurus, terutamanya jika anda sudah selesa dengan alat CLI melalui aliran kerja pengaturcaraan agentik.
Mengapa Scrapy?
Screaming Frog berfungsi dengan baik untuk audit pantas. Tetapi ia mempunyai had:
| Had | Kesan |
|---|---|
| Had percuma 500 URL | Memerlukan lesen $259/tahun untuk laman lebih besar |
| Rakus memori | Crawl besar boleh menggunakan 8GB+ RAM |
| Bergantung pada GUI | Sukar untuk automasi atau jadual |
| Penyesuaian terhad | Pilihan konfigurasi adalah tetap |
Scrapy menyelesaikan ini:
| Scrapy | Apa yang anda dapat |
|---|---|
| Percuma dan sumber terbuka | Tiada had URL, tiada yuran lesen |
| Jejak memori lebih rendah | Baris gilir disokong cakera memastikan RAM terkawal |
| CLI-asli | Boleh skrip, boleh cron, sedia CI/CD |
| Penyesuaian Python penuh | Ekstrak apa yang anda perlukan, tapis cara yang anda mahu |
| Jeda/Sambung | Henti dan teruskan crawl besar bila-bila masa |
Pemasangan
Scrapy berjalan pada Python. Gunakan persekitaran maya untuk memastikan semuanya bersih:
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
Mencipta Projek
Dengan Scrapy dipasang:
scrapy startproject myproject
cd myproject
scrapy genspider sitename example.com
Ini mencipta:
myproject/
scrapy.cfg
myproject/
__init__.py
items.py
middlewares.py
pipelines.py
settings.py
spiders/
__init__.py
sitename.py
Kod spider masuk dalam spiders/sitename.py. Konfigurasi dalam settings.py.
Tetapan untuk Crawling Sopan
Konfigurasikan settings.py sebelum menjalankan apa-apa. Disekat membazir lebih banyak masa daripada crawling perlahan.
# Crawling sopan
CONCURRENT_REQUESTS_PER_DOMAIN = 5
DOWNLOAD_DELAY = 1
ROBOTSTXT_OBEY = True
# AutoThrottle - menyesuaikan kelajuan berdasarkan respons pelayan
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 5
AUTOTHROTTLE_MAX_DELAY = 60
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
AUTOTHROTTLE_DEBUG = True
# Had keselamatan
CLOSESPIDER_PAGECOUNT = 10000
# Output
FEED_EXPORT_ENCODING = "utf-8"
AutoThrottle
AutoThrottle memantau masa respons pelayan dan menyesuaikan kelajuan crawl secara automatik:
- Respons pantas → mempercepatkan
- Respons perlahan → memperlahankan
- Ralat/timeout → memperlahankan dengan ketara
Tidak seperti kelewatan tetap Screaming Frog, ia menyesuaikan diri dengan keadaan pelayan sebenar.
Pengendalian Kod Status
Secara lalai, HttpErrorMiddleware Scrapy menggugurkan respons bukan 2xx secara senyap. Ini bermakna 404, 301, 500 dibuang sebelum sampai ke callback anda. Crawl anda mungkin menunjukkan 100% kod status 200, bukan kerana laman sempurna, tetapi kerana ralat sedang ditapis.
Tambah ini ke kelas spider anda untuk menangkap semua kod status:
handle_httpstatus_list = [200, 301, 302, 403, 404, 500, 502, 503]
Screaming Frog menangkap semua kod status secara lalai. Tetapan ini menjadikan Scrapy selaras dengan tingkah laku tersebut.
Prestasi Dunia Sebenar
Nombor sebenar dari crawl ujian dengan 5 permintaan serentak dan AutoThrottle diaktifkan:
| Kemajuan Crawl | Halaman/Minit | Nota |
|---|---|---|
| 0-200 halaman | 14-22 | Peningkatan |
| 200-500 halaman | 10-12 | Menstabilkan |
| 500-1,000 halaman | 7-10 | AutoThrottle menyesuaikan |
| 1,000+ halaman | 5-7 | Keadaan stabil |
Perbandingan Ciri
| Ciri | Screaming Frog | Scrapy |
|---|---|---|
| Kos | Percuma <500 URL, ~$259/tahun | Percuma, sumber terbuka |
| Saiz crawl maks | Terhad memori | Baris gilir disokong cakera |
| Penyesuaian | Pilihan config terhad | Kod Python penuh |
| Penjadualan | Manual atau pihak ketiga | CLI asli, boleh cron |
| Jeda/Sambung | Ya | Ya (dengan JOBDIR) |
| Keluk pembelajaran | Rendah (GUI) | Sederhana (kod) |
| Had kadar | Kelewatan tetap asas | AutoThrottle (adaptif) |
| Rendering JavaScript | Pilihan (Chrome) | Pilihan (playwright/splash) |
| Kod status | Semua secara lalai | Memerlukan konfigurasi |
| Penapisan subdomain | Kotak pilihan GUI | Kod (regex fleksibel) |
| Format eksport | CSV, Excel, dll. | JSON, CSV, XML, tersuai |
| Integrasi CI/CD | Sukar | Asli |
Penapisan URL
Screaming Frog menggunakan kotak pilihan. Scrapy menggunakan kod. Pertukaran adalah keluk pembelajaran untuk ketepatan.
Mengecualikan laluan antarabangsa:
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/"]
# Langkau laluan antarabangsa seperti /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
Anda boleh menapis mengikut corak URL, parameter pertanyaan, pengepala respons, kandungan halaman, atau sebarang kombinasi.
Jeda dan Sambung
Untuk crawl melebihi 1,000 halaman, aktifkan jeda/sambung dengan JOBDIR:
scrapy crawl myspider -o output.json -s JOBDIR=crawl_state
Scrapy menyimpan keadaan ke crawl_state/. Tekan Ctrl+C untuk jeda. Jalankan arahan yang sama untuk menyambung.
Keadaan termasuk URL yang tertunda, URL yang dilihat, dan baris gilir permintaan. Ini lebih mantap daripada ciri simpan/muat Screaming Frog kerana ia berasaskan fail dan bertahan selepas permulaan semula sistem.
Rendering JavaScript
Scrapy mengambil HTML mentah sahaja. Ia tidak merender JavaScript. Ini sama seperti apa yang dikembalikan oleh curl.
Untuk kebanyakan crawl SEO, ini tidak menjadi masalah:
- Tag meta, canonical, dan h1 biasanya dalam HTML awal
- Enjin carian terutamanya mengindeks kandungan yang dirender pelayan
- Kebanyakan laman e-dagang dan kandungan dirender pelayan
Jika laman sasaran anda merender kandungan di sisi klien, anda mempunyai pilihan:
| Pakej | Nota |
|---|---|
| scrapy-playwright | Menggunakan Chromium/Firefox/WebKit. Disyorkan untuk laman JS moden |
| scrapy-splash | Ringan, renderer berasaskan Docker |
| scrapy-selenium | Pendekatan lama, masih berfungsi |
Rendering JS jauh lebih perlahan dan intensif sumber. Hanya tambah jika laman memerlukannya.
Screaming Frog mempunyai pertukaran yang sama. Mengaktifkan rendering JavaScript menggunakan Chrome di sebalik tabir dan melambatkan crawl dengan ketara.
Pengurusan Memori
Pada ~1,300 halaman dengan pengekstrakan medan penuh:
- Memori: ~265 MB
- CPU: ~4%
Menggunakan JOBDIR memindahkan baris gilir permintaan ke cakera, memastikan memori rendah. Untuk crawl yang sangat besar (100k+ URL), tambah tetapan ini:
MEMUSAGE_LIMIT_MB = 1024
MEMUSAGE_WARNING_MB = 800
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'
Ini mengehadkan penggunaan memori dan memaksa baris gilir disokong cakera untuk penjadual.
Data Output
Output spider asas:
{
"url": "https://www.example.com/page/",
"title": "Tajuk Halaman Di Sini",
"status": 200
}
Untuk crawl SEO, anda memerlukan medan yang serupa dengan apa yang dieksport oleh Screaming Frog:
def parse_page(self, response):
yield {
"url": response.url,
"status": response.status,
"title": response.css("title::text").get(),
"meta_description": response.css("meta[name='description']::attr(content)").get(),
"meta_robots": response.css("meta[name='robots']::attr(content)").get(),
"h1": response.css("h1::text").get(),
"canonical": response.css("link[rel='canonical']::attr(href)").get(),
"og_title": response.css("meta[property='og:title']::attr(content)").get(),
"og_description": response.css("meta[property='og:description']::attr(content)").get(),
"word_count": len(response.text.split()) if response.status == 200 else None,
"content_type": response.headers.get("Content-Type", b"").decode("utf-8", errors="ignore"),
}
Tambah atau buang medan berdasarkan apa yang anda perlukan. Pemilih CSS berfungsi untuk mana-mana elemen pada halaman.
Format eksport: JSON (-o output.json), JSON Lines (-o output.jsonl), CSV (-o output.csv), XML (-o output.xml).
JSON Lines adalah terbaik untuk crawl besar. Fail adalah sah baris demi baris semasa crawl, jadi anda boleh memantau dengan tail -f. JSON standard tidak sah sehingga crawl selesai.
Screaming Frog → Scrapy
Memetakan aliran kerja SF ke Scrapy:
| Tindakan Screaming Frog | Setara Scrapy |
|---|---|
| Mulakan crawl baru | scrapy crawl spidername |
| Tetapkan kelewatan crawl | DOWNLOAD_DELAY dalam tetapan |
| Hadkan thread serentak | CONCURRENT_REQUESTS_PER_DOMAIN |
| Hormati robots.txt | ROBOTSTXT_OBEY = True |
| Eksport ke CSV | -o output.csv |
| Simpan/Muat crawl | -s JOBDIR=crawl_state |
| Tapis subdomain | Kod dalam spider (regex) |
| Pengekstrakan tersuai | Pemilih CSS/XPath dalam parse() |
Perubahan minda:
- Konfigurasi adalah kod. Edit
settings.pydaripada mengklik kotak pilihan. - Pengekstrakan adalah eksplisit. Anda menulis data apa yang hendak ditangkap.
- Penjadualan adalah asli. Tambah arahan ke cron atau CI/CD.
- Nyahpepijat adalah log. Aktifkan
AUTOTHROTTLE_DEBUGuntuk melihat apa yang berlaku.
Aliran Kerja Penuh
Dengan tetapan standard di atas, anda boleh memasang Scrapy dan crawling dalam masa kurang 15 minit:
python3 -m venv venv
source venv/bin/activate # venv\Scripts\activate pada Windows
pip install scrapy
scrapy startproject urlcrawler
cd urlcrawler
scrapy genspider mysite example.com
# Edit settings.py dengan config crawl sopan
# Edit spiders/mysite.py dengan logik parse anda
scrapy crawl mysite -o urls.jsonl -s JOBDIR=crawl_state
Scrapy Shell
Semasa anda membina konfigurasi tersuai, gunakan Scrapy Shell untuk menguji pemilih dan tetapan anda secara interaktif:
scrapy shell "https://example.com"
Ini membuka konsol Python interaktif dengan respons sudah dimuatkan. Uji pemilih CSS dan XPath dalam masa nyata sebelum menambahnya ke spider anda:
>>> response.css('title::text').get()
'Example Domain'
>>> response.xpath('//h1/text()').get()
'Example Domain'
Scrapy Shell mengurangkan masa iterasi dengan ketara. Sahkan logik pengekstrakan tanpa menjalankan crawl penuh.
Templat Spider Lengkap
Spider sedia pengeluaran dengan penapisan URL, pengendalian kod status, dan pengekstrakan medan SEO penuh:
import re
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from urllib.parse import urlparse
class SEOSpider(CrawlSpider):
name = "seospider"
allowed_domains = ["example.com"]
start_urls = ["https://www.example.com"]
# Capture all HTTP status codes, not just 2xx
handle_httpstatus_list = [200, 301, 302, 403, 404, 500, 502, 503]
# URL patterns to exclude
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=()),
callback="parse_page",
follow=True,
process_links="filter_links",
),
)
def filter_links(self, links):
filtered = []
for link in links:
parsed = urlparse(link.url)
hostname = parsed.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
def parse_page(self, response):
yield {
"url": response.url,
"status": response.status,
"title": response.css("title::text").get(),
"meta_description": response.css("meta[name='description']::attr(content)").get(),
"meta_robots": response.css("meta[name='robots']::attr(content)").get(),
"h1": response.css("h1::text").get(),
"canonical": response.css("link[rel='canonical']::attr(href)").get(),
"og_title": response.css("meta[property='og:title']::attr(content)").get(),
"og_description": response.css("meta[property='og:description']::attr(content)").get(),
"word_count": len(response.text.split()) if response.status == 200 else None,
"content_type": response.headers.get("Content-Type", b"").decode("utf-8", errors="ignore"),
}
Gantikan example.com dengan domain sasaran anda. Sesuaikan EXCLUDED_PATTERNS untuk struktur URL laman anda.
Bila Guna Yang Mana
Screaming Frog:
- Audit pantas di bawah 500 URL
- Hasil diperlukan dalam minit
- Penerokaan laman visual
- Tidak selesa dengan CLI
- Menggunakan data Screaming Frog dengan Redirects.net
Scrapy:
- Laman melebihi 10,000 URL
- Crawl automatik dan dijadualkan
- Keperluan pengekstrakan tersuai
- Integrasi CI/CD
- Kekangan memori
- Config versi terkawal
Kesimpulan
Scrapy mempunyai keluk persediaan yang lebih curam daripada Screaming Frog, tetapi ia menghapuskan had praktikal yang dikenakan oleh crawler GUI. Tiada had URL, tiada yuran lesen, penggunaan memori lebih rendah, dan automasi asli.
Mulakan kecil. Crawl laman yang anda kenali. Gunakan tetapan konservatif. Bandingkan output dengan Screaming Frog. Data akan sepadan, tetapi anda akan mempunyai alat yang berskala.