boto3 را به Endpoint پارسپک وصل کنید
برای boto3 به کتابخانهٔ اختصاصی پارسپک نیاز ندارید. کافی است هنگام ساخت Client، Endpoint، Region، Credential و path-style را مشخص کنید. کد همراه این صفحه یک CLI کوچک است تا هر عملیات را جداگانه بسنجید.

ابزار نمونه با فایل hello.txt یک چرخهٔ کامل را اجرا میکند: نوشتن، خواندن متادیتا، دانلود، تولید لینک موقت و حذف.
اجرای هر فرمان مستقل است، اما head و download فقط پس از آپلود معنی دارند. اگر از وسط مسیر شروع کنید، خطای 404 طبیعی است.
پیشنیاز و ساختار پروژه
Python 3.10 یا جدیدتر و pip برای نصب boto3 کافی است.
python3 --version
python3 -m pip --versionexamples/python/
├── .env # پس از کپیکردن فایل نمونه ساخته میشود
├── .venv/ # محیط مجازی پس از نصب
├── requirements.txt # بازه نسخه boto3
├── requirements.lock # نسخههای دقیق تستشده
└── parspack_s3.py # Client و هفت فرمان مدیریت فایلساخت محیط مجازی و نصب boto3
محیط مجازی کتابخانه این نمونه را از Python سیستم جدا نگه میدارد تا نسخه boto3 قاطی نشود.
python3 -m venv examples/python/.venv
examples/python/.venv/bin/pip install -r examples/python/requirements.txtrequirements.txt فایل requirements.lock را به pip بدهید.ساخت فایل .env
پنج مقدار را از پنل فضای ابری پارسپک کپی کنید. معنی هر متغیر و شکل معمول Endpoint در صفحه شروع آمده است.
upload با خطای امضا میخوابد.cp examples/.env.example examples/python/.envPARSPACK_S3_ENDPOINT=https://c123456.parspack.net
PARSPACK_S3_BUCKET=c123456
PARSPACK_S3_REGION=us-east-1
PARSPACK_S3_ACCESS_KEY=YOUR_ACCESS_KEY
PARSPACK_S3_SECRET_KEY=YOUR_SECRET_KEY| متغیر | چه چیزی در آن میگذارید | اگر اشتباه باشد |
|---|---|---|
PARSPACK_S3_ENDPOINT | آدرس HTTPS پنل، بدون / در انتها؛ شکل معمول https://c123456.parspack.net | Timeout یا خطای امضا |
PARSPACK_S3_BUCKET | نام باکت؛ اغلب با شناسه داخل Endpoint یکی است | NoSuchBucket |
PARSPACK_S3_REGION | فقط برای امضای Signature V4 است. اگر پنل Region نداد، us-east-1 را ثابت نگه دارید | SignatureDoesNotMatch |
PARSPACK_S3_ACCESS_KEY / SECRET_KEY | کلیدهای API از پنل؛ فقط روی سرور | AccessDenied یا خطای امضا |
فایل .env را Commit نکنید. Access Key و Secret Key فقط روی سرور میمانند؛ مرورگر فقط لینک کوتاهعمر میگیرد.
اتصال برنامه به فضای پارسپک
Client را یک بار با مقدارهای .env بسازید. همین شیء برای هر هفت فرمان کافی است.
endpoint_url همان آدرس HTTPS پنل است؛ اسلش انتها را بردارید. region_name موقعیت سرور نیست؛ اگر پنل چیزی نگفت us-east-1 را عوض نکنید. addressing_style باید path باشد تا URL به شکل /bucket/key ساخته شود.def load_dot_env(path: Path) -> None:
for raw_line in path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
name, value = line.split("=", 1)
os.environ.setdefault(name.strip(), value.strip().strip('"\''))
load_dot_env(Path(__file__).with_name(".env"))s3 = boto3.client(
"s3",
endpoint_url=os.environ["PARSPACK_S3_ENDPOINT"].rstrip("/"),
region_name=os.environ["PARSPACK_S3_REGION"],
aws_access_key_id=os.environ["PARSPACK_S3_ACCESS_KEY"],
aws_secret_access_key=os.environ["PARSPACK_S3_SECRET_KEY"],
config=Config(
signature_version="s3v4",
s3={"addressing_style": "path"},
retries={"max_attempts": 3, "mode": "standard"},
),
)آپلود فایل با put_object
اولین فرمان سناریو: فایل محلی را با یک نام مشخص در باکت بگذارید.
./hello.txt است؛ داخل باکت با نام tutorial/hello.txt ذخیره میشود. اسلش پوشه واقعی نمیسازد، فقط بخشی از نام است. فایل را با حالت Binary (rb) باز کنید. ETag اثر انگشت محتواست. اگر همین نام از قبل در باکت باشد، محتوای قبلی عوض میشود.local_file = Path("./hello.txt")
object_key = "tutorial/hello.txt"
content_type = mimetypes.guess_type(local_file.name)[0] or "application/octet-stream"
with local_file.open("rb") as body:
result = s3.put_object(
Bucket=bucket,
Key=object_key,
Body=body,
ContentType=content_type,
)
print(result["ETag"])| پارامتر | مثال | کاربرد |
|---|---|---|
Bucket | از .env | محل ذخیره Object |
Key | tutorial/hello.txt | نام کامل Object |
Body | فایل بازشده با rb | بایتهای فایل |
ContentType | text/plain | نوع محتوای فایل |
printf 'hello ParsPack\n' > hello.txt
PY=examples/python/.venv/bin/python
$PY examples/python/parspack_s3.py upload ./hello.txt tutorial/hello.txtاگر Object با همین Key وجود داشته باشد، put_object محتوای آن را جایگزین میکند. قبل از فراخوانی نیز وجود فایل محلی بررسی شود.
فهرست فایلها و مشخصات یک فایل
بعد از آپلود، اول ببینید فایل در فهرست هست؛ بعد حجم و نوع را بدون دانلود بخوانید.
list tutorial/ خود فایل را نمیآورد؛ فقط نام، حجم و زمان تغییر فایلهایی را برمیگرداند که با این Prefix شروع میشوند. اگر آرایه خالی بود، یا آپلود انجام نشده یا Prefix را اشتباه نوشتهاید.head وقتی لازم است که فقط بخواهید بدانید فایل هست یا نه، یا حجم و نوعش چیست. اگر Key نباشد معمولاً 404 میگیرید. این فرمان را با دانلود عوض نکنید؛ بدنه فایل را منتقل نمیکند.paginator = s3.get_paginator("list_objects_v2")
for page in paginator.paginate(Bucket=bucket, Prefix="tutorial/"):
for item in page.get("Contents", []):
print(item["Key"], item["Size"], item["LastModified"])info = s3.head_object(
Bucket=bucket,
Key="tutorial/hello.txt",
)
print(info["ContentLength"])
print(info.get("ContentType"))
print(info["ETag"])$PY examples/python/parspack_s3.py list tutorial/$PY examples/python/parspack_s3.py head tutorial/hello.txtContents ممکن است در صفحه نباشد؛ از page.get("Contents", []) استفاده کنید.دانلود روی سرور
فایل را از باکت بگیرید و روی دیسک همین برنامه بنویسید. این کار لینک برای کاربر نمیسازد.
result = s3.get_object(
Bucket=bucket,
Key="tutorial/hello.txt",
)
try:
with open("./downloads/hello.txt", "wb") as destination:
shutil.copyfileobj(result["Body"], destination)
finally:
result["Body"].close()$PY examples/python/parspack_s3.py download tutorial/hello.txt ./downloads/hello.txtلینک موقت دانلود برای کاربر
این فرمان را با دانلود روی سرور قاطی نکنید. اینجا فایل روی دیسک شما نوشته نمیشود؛ فقط یک آدرس زماندار ساخته میشود. جریان کامل در صفحه شروع است.
<a href> بگذارید، یا با curl --output file.pdf "$URL" بگیرید. Header اضافه لازم نیست. 900 یعنی پانزده دقیقه؛ بعد از آن آدرس کار نمیکند.url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": bucket, "Key": "tutorial/hello.txt"},
ExpiresIn=900,
)$PY examples/python/parspack_s3.py presign-get tutorial/hello.txt 900curl --output invoice.pdf "$SIGNED_DOWNLOAD_URL"لینک را کوتاه نگه دارید؛ بین ۱ ثانیه تا ۷ روز (۶۰۴۸۰۰ ثانیه). فقط همان Key را میخواند. لینک را فقط بعد از ورود کاربر و چک مجوز بسازید.
لینک موقت آپلود مستقیم
کاربر فایل را از مرورگر به باکت میفرستد. فایل از سرور شما رد نمیشود و کلید API هم به کاربر نمیرسد.
Content-Type را دقیقاً همان مقدار زمان ساخت لینک بگذارید؛ وگرنه معمولاً خطای امضا میگیرید. از مرورگر فقط وقتی کار میکند که CORS باکت سایت شما را مجاز کرده باشد؛ وگرنه از curl یا سرور خودتان استفاده کنید.content_type = "text/plain"
upload_url = s3.generate_presigned_url(
"put_object",
Params={
"Bucket": bucket,
"Key": "tutorial/upload.txt",
"ContentType": content_type,
},
ExpiresIn=900,
)$PY examples/python/parspack_s3.py presign-put tutorial/upload.txt text/plain 900curl -X PUT -H 'Content-Type: text/plain' \
--upload-file ./hello.txt "$SIGNED_UPLOAD_URL"await fetch(signed.url, {
method: "PUT",
headers: { "Content-Type": signed.headers["Content-Type"] },
body: file,
});اگر موقع ساخت لینک text/plain گذاشتهاید، هنگام ارسال هم باید همان را بفرستید. از مرورگر این کار فقط وقتی درست است که CORS باکت سایت شما را مجاز کرده باشد؛ وگرنه از curl یا سرور خودتان استفاده کنید.
حذف فایل با delete_object
نام را از باکت برمیدارد. لازم نیست اول دانلودش کنید. فایل روی سیستم شما دست نمیخورد.
s3.delete_object(
Bucket=bucket,
Key="tutorial/hello.txt",
)PY=examples/python/.venv/bin/python
$PY examples/python/parspack_s3.py delete tutorial/hello.txtClientError را از خطای شبکه جدا کنید
نمونه پاسخ سرویس و خطای ارتباطی را جداگانه روی stderr چاپ میکند. در خطای سرویس، کد AWS و Status Code را بخوانید؛ در خطای ارتباطی، Endpoint، DNS و TLS را بررسی کنید.
try:
s3.put_object(Bucket=bucket, Key=key, Body=body)
except ClientError as error:
detail = error.response.get("Error", {})
print(detail.get("Code"), detail.get("Message"))
except BotoCoreError as error:
print(f"SDK or network error: {error}")| خطا | علت معمول | بررسی |
|---|---|---|
Local file not found | مسیر فایل محلی اشتباه است | مسیر ورودی Command |
AccessDenied | کلید یا دسترسی Bucket کافی نیست | مقدارهای پنل و نوع دسترسی کاربر فضای ابری |
SignatureDoesNotMatch | امضای درخواست با تنظیمات یکی نیست | Slash انتهای Endpoint، Region، کلیدها و Content-Type در PUT |
NoSuchBucket | نام Bucket با مقدار پنل یکی نیست | PARSPACK_S3_BUCKET |
| Connection / timeout | Endpoint در دسترس نیست یا HTTPS قطع است | آدرس پنل را بدون تغییر و بدون / انتها وارد کنید |
اجرای کامل همین سناریو
فایل همراه، Parser فرمانها، Loader فایل .env، تشخیص MIME و خروجی JSON را یکجا دارد. اگر خروجی هر فرمان شبیه نمونههای بالا بود، میتوانید Key و مسیر را با نام فایلهای برنامه خودتان عوض کنید.
python3 -m venv examples/python/.venv
examples/python/.venv/bin/pip install -r examples/python/requirements.txt
cp examples/.env.example examples/python/.env
# مقدارهای examples/python/.env را کامل کنید
printf 'hello ParsPack\n' > hello.txt
PY=examples/python/.venv/bin/python
$PY examples/python/parspack_s3.py upload ./hello.txt tutorial/hello.txt
$PY examples/python/parspack_s3.py list tutorial/
$PY examples/python/parspack_s3.py head tutorial/hello.txt
$PY examples/python/parspack_s3.py download tutorial/hello.txt ./downloads/hello.txt
$PY examples/python/parspack_s3.py presign-get tutorial/hello.txt 900
$PY examples/python/parspack_s3.py presign-put tutorial/upload.txt text/plain 900
$PY examples/python/parspack_s3.py delete tutorial/hello.txt