عندما تكون لديك جدول بيانات يحوي روابط صور، يصبح تنزيلها يدويًا غير عملي. يقرأ هذا السكربت ملف CSV يكون عموده الأول هو الرابط وعموده الثاني الاختياري اسم الملف المفضّل، ثم يجلب كل صورة بالتوازي باستخدام مجموعة خيوط (thread pool). التوازي مثالي هنا لأن تنزيل الصور مقيّد بالإدخال والإخراج، فثمانية عمال (قابلة للضبط) تقلّص الوقت الكلي بشكل كبير مقارنة بحلقة متسلسلة. يُنزّل كل طلب على دفعات 8 كيلوبايت لإبقاء الذاكرة منخفضة حتى مع الملفات الكبيرة، وتمنع المهلة لكل طلب رابطًا بطيئًا أو معطلًا من تعطيل الدفعة كاملة. وعند عدم تحديد اسم، يُشتق من مسار الرابط ويُنظّف من الأحرف الممنوعة في أسماء الملفات عبر أنظمة التشغيل. تُلتقط الأخطاء فرديًا ويُبلّغ عنها فلا يوقف رابط معطوب التشغيل، ويُعرض ملخص نهائي بالنجاحات والإخفاقات. التثبيت: pip install requests.
تنزيل الصور بالجملة من ملف CSV يحوي الروابط
تنزيل عدد كبير من الصور بالتوازي من قائمة روابط في ملف CSV مع تسمية آمنة للملفات ومهلة لكل طلب.
15 مشاهدة
مشاركة
السكربت
تحميل .pypython
#!/usr/bin/env python3
"""Download images in parallel from a CSV list of URLs.
CSV: first column is the URL; optional second column is a file name.
Dependency: pip install requests
"""
import argparse
import csv
import os
import re
from concurrent.futures import ThreadPoolExecutor, as_completed
from urllib.parse import urlparse
import requests
def read_url_rows(path):
"""Yield (url, name_or_None) tuples from the CSV."""
with open(path, newline="", encoding="utf-8") as f:
for row in csv.reader(f):
if not row or not row[0].strip():
continue
url = row[0].strip()
if url.lower() == "url": # skip a header line
continue
name = row[1].strip() if len(row) > 1 and row[1].strip() else None
yield url, name
def filename_from_url(url, index):
"""Derive a safe file name from the URL path."""
path = urlparse(url).path
base = os.path.basename(path) or f"image_{index}"
base = re.sub(r"[^A-Za-z0-9._-]+", "_", base)
return base
def download_one(url, name, outdir, index, timeout):
"""Download a single image; return (url, status_string)."""
try:
resp = requests.get(url, timeout=timeout, stream=True)
resp.raise_for_status()
fname = name or filename_from_url(url, index)
out_path = os.path.join(outdir, fname)
with open(out_path, "wb") as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
return url, f"OK -> {out_path}"
except requests.RequestException as exc:
return url, f"FAILED ({exc})"
def main():
parser = argparse.ArgumentParser(description="Bulk image downloader.")
parser.add_argument("csv_file", help="CSV with image URLs.")
parser.add_argument("-o", "--outdir", default="images",
help="Output directory (default: images).")
parser.add_argument("-j", "--workers", type=int, default=8,
help="Parallel download workers (default: 8).")
parser.add_argument("-t", "--timeout", type=float, default=20.0,
help="Per-request timeout seconds (default: 20).")
args = parser.parse_args()
os.makedirs(args.outdir, exist_ok=True)
rows = list(read_url_rows(args.csv_file))
ok = 0
fail = 0
with ThreadPoolExecutor(max_workers=args.workers) as pool:
futures = {
pool.submit(download_one, url, name, args.outdir, i, args.timeout): url
for i, (url, name) in enumerate(rows, start=1)
}
for fut in as_completed(futures):
url, status = fut.result()
print(status)
if status.startswith("OK"):
ok += 1
else:
fail += 1
print(f"\nDone. {ok} succeeded, {fail} failed, {len(rows)} total.")
if __name__ == "__main__":
main()كيفية التشغيل
راجع السكربت أولاً، ثم حمّله أو انسخه وشغّله في بيئتك.
قد يعجبك أيضاً
bashlinuxمبتدئ
عرض نسخ الحوسبة في GCP
إظهار كل آلة افتراضية في Compute Engine ضمن مشروع مع المنطقة ونوع الآلة والحالة وعناوين IP.
bashlinuxمتوسط
مزامنة مجلد إلى مضيف بعيد عبر rsync فوق SSH
يطابق مجلداً محلياً مع خادم بعيد بأمان عبر SSH.
bashlinuxمتقدم
تنظيف صور AMI واللقطات القديمة
إلغاء تسجيل صور AMI القديمة بعد فترة الاحتفاظ وحذف لقطات EBS الداعمة لها.