Mengumpulkan ribuan gambar untuk melatih model visi komputer adalah tugas yang hampir selalu menghadapi dua masalah: pemblokiran dari sumber data (Google Images, Pinterest, marketplace, situs stok) dan pengeluaran trafik yang tidak terduga tinggi. Satu IP cepat terblokir, dan biaya trafik proksi bisa melebihi biaya penandaan dataset itu sendiri. Dalam artikel ini, kita akan membahas bagaimana merancang parser gambar yang tidak kehilangan data karena pemblokiran, dan bagaimana menghitung anggaran trafik sebelumnya.
Mengapa proksi saat mengumpulkan gambar untuk CV
Dataset untuk visi komputer jarang dikumpulkan dari satu sumber. Biasanya ini adalah kombinasi hasil pencarian gambar, kartu produk di marketplace, stok foto, media sosial, dan API terbuka. Hampir semua sumber ini memberlakukan batasan pada jumlah permintaan dari satu IP: Google Images menunjukkan captcha setelah beberapa ratus permintaan berturut-turut, Pinterest sementara memblokir akses ke API, dan Wildberries serta Ozon memberikan kartu kosong atau mengalihkan ke halaman verifikasi saat mendeteksi aktivitas mencurigakan.
Tanpa proksi, Anda akan terjebak pada batas beberapa ratus atau ribuan gambar per hari dari satu alamat. Jika Anda memerlukan dataset dengan 50.000–500.000 gambar (yang biasanya diperlukan untuk jaringan konvolusional dan transformer dalam tugas klasifikasi dan deteksi), tanpa kumpulan IP yang terdistribusi, mengumpulkannya dalam waktu yang wajar secara fisik tidak mungkin — Anda akan terus-menerus menghadapi pemblokiran atau mendapatkan sampel yang sangat terdistorsi karena batasan waktu dan geolokasi.
Alasan kedua adalah keberagaman geografis data. Jika model harus dapat mengenali objek dengan baik terlepas dari wilayah pengambilan gambar (misalnya, rambu lalu lintas di berbagai negara atau produk di marketplace lokal), parser harus terhubung dengan IP dari berbagai negara. Satu pusat data dengan satu IP keluar tidak akan memberikan keberagaman tersebut.
Berapa banyak trafik yang sebenarnya digunakan untuk dataset
Pengeluaran trafik saat mengumpulkan gambar sering kali diremehkan. Ini bukan hanya tentang ukuran gambar itu sendiri — halaman HTML, bundel JS, pratinjau, piksel pelacakan, dan CSS juga melewati proksi jika parser tidak disesuaikan dengan URL yang diperlukan.
| Tipe Konten | Berat Rata-rata | Trafik untuk 10.000 pcs. |
|---|---|---|
| Pratinjau/thumbnail (150–300 px) | 15–40 KB | ~250 MB |
| Foto resolusi menengah (800–1200 px) | 80–200 KB | ~1,4 GB |
| Foto resolusi tinggi (2000+ px) | 400 KB – 1,5 MB | ~9,5 GB |
| Halaman HTML kartu produk (tanpa gambar) | 150–400 KB | ~2,7 GB |
Dalam praktiknya, jika Anda mengumpulkan 100.000 gambar resolusi menengah bersama dengan halaman kartu (untuk ekstraksi penandaan — kategori, kotak, atribut), pengeluaran trafik akhir biasanya berkisar antara 25–45 GB. Jika Anda memerlukan gambar resolusi tinggi untuk tugas deteksi objek kecil — siapkan anggaran 80–150 GB untuk 100.000 pcs yang sama. Angka-angka ini harus dipertimbangkan saat memilih tarif proksi sebelumnya, bukan setelahnya.
Datacenter, residential, dan mobile: apa yang harus dipilih
Untuk mengumpulkan gambar, tiga parameter penting: kecepatan, biaya trafik, dan ketahanan terhadap pemblokiran. Parameter ini sangat berbeda antara berbagai jenis proksi.
| Parameter | Datacenter | Residential | Mobile |
|---|---|---|---|
| Kecepatan | Tinggi | Sedang | Rendah-sedang |
| Ketahanan terhadap pemblokiran | Rendah | Tinggi | Sangat tinggi |
| Biaya trafik | Rendah | Sedang-tinggi | Tinggi |
| Cocok untuk | API terbuka, stok tanpa perlindungan ketat | Google Images, Pinterest, marketplace | Media sosial dengan perlindungan anti-bot yang ketat |
Untuk sebagian besar tugas pengumpulan gambar, keseimbangan optimal diberikan oleh proksi residential — IP terlihat seperti pengguna biasa, sehingga sistem anti-bot di marketplace dan mesin pencari gambar lebih jarang memicu captcha. Jika sumbernya adalah stok foto terbuka atau API tanpa batasan ketat, lebih murah menggunakan proksi datacenter — mereka lebih cepat dan memungkinkan pengalihan volume trafik besar dengan harga yang lebih rendah per GB. Dan untuk mengumpulkan gambar dari aplikasi mobile atau media sosial dengan perlindungan anti-bot yang canggih, proksi mobile lebih cocok — mereka menggunakan IP nyata dari operator seluler dan hampir tidak pernah terblokir.
Parser dasar menggunakan requests dengan rotasi proksi
Untuk memulai, skrip sinkron sederhana menggunakan requests dengan rotasi proksi untuk setiap permintaan atau setelah jumlah permintaan tertentu sudah cukup. Berikut adalah contoh pengunduhan gambar berdasarkan daftar URL dengan memeriksa tipe konten dan membatasi ukuran file, untuk menghindari mengunduh file berat dengan format yang salah.
import requests
import itertools
import hashlib
import os
PROXIES = [
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
]
proxy_cycle = itertools.cycle(PROXIES)
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "image/avif,image/webp,image/*,*/*;q=0.8",
}
def download_image(url, save_dir="dataset", max_size_mb=10, timeout=15):
proxy = next(proxy_cycle)
proxies = {"http": proxy, "https": proxy}
try:
resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=timeout, stream=True)
resp.raise_for_status()
content_type = resp.headers.get("Content-Type", "")
if "image" not in content_type:
return None
content_length = int(resp.headers.get("Content-Length", 0))
if content_length > max_size_mb * 1024 * 1024:
return None
file_hash = hashlib.md5(url.encode()).hexdigest()
ext = content_type.split("/")[-1].split(";")[0]
filepath = os.path.join(save_dir, f"{file_hash}.{ext}")
os.makedirs(save_dir, exist_ok=True)
with open(filepath, "wb") as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
return filepath
except requests.exceptions.RequestException as e:
print(f"Kesalahan saat {url} melalui {proxy}: {e}")
return None
Poin kunci adalah memeriksa Content-Length sebelum mengunduh tubuh respons. Ini menghemat trafik dengan menyaring file yang terlalu berat sebelum diunduh sepenuhnya. Rotasi proksi melalui itertools.cycle secara merata mendistribusikan beban antara IP, mengurangi risiko pemblokiran alamat tertentu.
Pengumpulan asinkron melalui aiohttp
Skrip sinkron menggunakan requests baik untuk beberapa ribu gambar, tetapi untuk dataset dari 50.000 file, diperlukan asinkronitas — jika tidak, pengumpulan akan memakan waktu berhari-hari. aiohttp bersama dengan semaphore untuk membatasi paralelisme adalah pilihan yang baik untuk puluhan ribu tugas sekaligus tanpa membebani kumpulan proksi.
import asyncio
import aiohttp
import itertools
PROXIES = [
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
]
proxy_cycle = itertools.cycle(PROXIES)
sem = asyncio.Semaphore(50) # batasan permintaan paralel
async def fetch_image(session, url, idx):
proxy = next(proxy_cycle)
async with sem:
try:
async with session.get(url, proxy=proxy, timeout=15) as resp:
if resp.status != 200:
return
content_type = resp.headers.get("Content-Type", "")
if "image" not in content_type:
return
data = await resp.read()
with open(f"dataset/{idx}.jpg", "wb") as f:
f.write(data)
except Exception as e:
print(f"Kesalahan {url}: {e}")
async def main(urls):
async with aiohttp.ClientSession() as session:
tasks = [fetch_image(session, url, i) for i, url in enumerate(urls)]
await asyncio.gather(*tasks)
# asyncio.run(main(url_list))
Semaphore dengan 50 koneksi bersamaan adalah titik awal. Jika proksi residential dapat menangani beban tanpa peningkatan kesalahan 429 dan timeout, Anda dapat secara bertahap meningkatkannya hingga 100–150. Yang terpenting adalah memantau persentase permintaan yang tidak berhasil: jika meningkat di atas 5–7%, sebaiknya kurangi paralelisme, bukan terus menambah kumpulan proksi tanpa batas.
Scrapy + middleware proksi untuk pengumpulan besar-besaran
Untuk pengumpulan dataset produksi dengan antrean bawaan, pengulangan, dan deduplikasi URL, lebih nyaman menggunakan Scrapy dengan ImagesPipeline. Ini secara otomatis mengunduh gambar, memeriksa validitasnya melalui PIL, dan dapat menghasilkan pratinjau dalam berbagai ukuran.
# settings.py
ITEM_PIPELINES = {
'scrapy.pipelines.images.ImagesPipeline': 1,
}
IMAGES_STORE = 'dataset_images'
IMAGES_MIN_HEIGHT = 200
IMAGES_MIN_WIDTH = 200
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.ProxyRotationMiddleware': 350,
}
CONCURRENT_REQUESTS = 32
DOWNLOAD_DELAY = 0.5
RETRY_TIMES = 3
# middlewares.py
import random
class ProxyRotationMiddleware:
PROXIES = [
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
]
def process_request(self, request, spider):
request.meta['proxy'] = random.choice(self.PROXIES)
Parameter IMAGES_MIN_HEIGHT dan IMAGES_MIN_WIDTH secara otomatis membuang ikon kecil dan sprite yang mencemari dataset dan membuang trafik dengan sia-sia. DOWNLOAD_DELAY sebesar 0,5 detik mengurangi frekuensi permintaan dari satu proksi, yang mengurangi proporsi captcha di sumber dengan pemantauan anti-fraud yang ketat seperti Pinterest.
Cara mengurangi pengeluaran trafik
Trafik melalui proksi biasanya dikenakan biaya berdasarkan volume, jadi setiap optimasi secara langsung menghemat anggaran. Berikut adalah teknik yang efektif:
- Mintalah pratinjau, bukan yang asli, jika untuk pelatihan cukup dengan resolusi 512–1024 px — sebagian besar sumber memberikan gambar dengan ukuran yang diperlukan melalui URL terpisah atau parameter query.
- Saring berdasarkan Content-Length sebelum mengunduh tubuh — permintaan HEAD atau membaca header dari GET streaming memungkinkan Anda membuang file yang terlalu berat tanpa menghabiskan trafik untuk mengunduhnya.
- Matikan pengunduhan sumber daya terkait, jika parser bekerja melalui browser headless: blokir CSS, font, dan skrip pelacakan, hanya menyisakan HTML dan gambar yang diperlukan.
- Deduplikasi URL sebelum permintaan, bukan setelah pengunduhan — gambar yang sama di halaman kartu produk yang berbeda (misalnya, di Wildberries) tidak perlu diunduh lagi.
- Gunakan cache lokal untuk respons saat menjalankan parser berulang kali selama debugging, agar tidak menghabiskan trafik melalui proksi untuk setiap pengujian kode.
Kesalahan umum, 403, dan batasan laju
Saat mengumpulkan gambar dalam volume besar, parser pasti akan menghadapi respons 403, 429, dan pengalihan sementara ke halaman verifikasi. Penanganan kode ini dengan benar menghemat trafik dan kumpulan proksi.
| Kode/Symptom | Penyebab | Apa yang harus dilakukan |
|---|---|---|
| 403 Forbidden | IP dalam daftar hitam sumber | Rotasi proksi, ganti User-Agent |
| 429 Too Many Requests | Batas permintaan per menit terlampaui | Tingkatkan DOWNLOAD_DELAY, kurangi paralelisme |
| Pengalihan ke captcha | Analisis perilaku mencurigai bot | Berpindah ke IP residential/mobile |
| Content-Length kosong | Respons chunked atau placeholder alih-alih gambar | Periksa ukuran byte yang diunduh yang sebenarnya |
Secara terpisah, penting untuk mencatat persentase permintaan yang berhasil untuk setiap proksi. Jika IP tertentu secara konsisten memberikan 403 lebih sering daripada yang lain — keluarkan secara otomatis dari rotasi, tanpa menunggu hingga ia menarik statistik blok umum di seluruh kumpulan.
Perhitungan anggaran untuk trafik proksi
Sebelum memulai pengumpulan, berguna untuk memperkirakan volume trafik sebelumnya, bukan menghitung setelahnya. Rumusnya sederhana: jumlah gambar × berat rata-rata file × koefisien overhead (HTML, header, permintaan ulang karena kesalahan — biasanya 1.3–1.6).
Contoh perhitungan untuk dataset dengan 200.000 gambar resolusi menengah (~150 KB) dengan pengambilan kartu produk: 200.000 × 150 KB = 30 GB berat bersih gambar. Dengan mempertimbangkan halaman HTML dan permintaan ulang karena pemblokiran sementara (koefisien 1.5), pengeluaran akhir — sekitar 45 GB. Jika beberapa sumber memerlukan IP mobile karena perlindungan anti-bot, pertimbangkan ini dalam kumpulan proksi secara terpisah, karena trafik pada IP mobile biasanya lebih mahal dibandingkan dengan residential atau datacenter.
Praktik yang baik adalah mengumpulkan batch percobaan 1.000–2.000 gambar, mengukur pengeluaran trafik yang sebenarnya dan persentase kesalahan, dan kemudian mengekstrapolasi ke seluruh volume dataset yang direncanakan. Ini lebih akurat daripada perhitungan teoritis mana pun, karena mempertimbangkan spesifikasi sumber tertentu.
Kesimpulan
Mengumpulkan gambar untuk melatih model visi komputer adalah tugas yang berada di persimpangan rekayasa data dan manajemen infrastruktur jaringan yang baik. Arsitektur parser yang tepat (asinkronitas, penyaringan berdasarkan Content-Length, deduplikasi URL) menghemat trafik, sementara pemilihan proksi yang dipikirkan dengan baik menentukan apakah Anda akan mengumpulkan volume dataset yang diperlukan dalam hitungan hari atau minggu dengan pemblokiran yang konstan.
Jika sumber data menggunakan perlindungan anti-bot yang canggih — mesin pencari gambar, marketplace, media sosial — mulailah dengan proksi residential: mereka memberikan keseimbangan terbaik antara ketahanan terhadap pemblokiran dan biaya trafik. Untuk API terbuka dan stok tanpa batasan ketat, masuk akal untuk menghemat pada proksi datacenter, dan untuk aplikasi mobile yang paling terlindungi — sambungkan proksi mobile untuk bagian akhir, yang paling sulit dari pengumpulan.