Skip to content
Intermediate / 1 min read

نحوه راه‌اندازی پروکسی‌های دیتاسنتری Smartproxy روی لینوکس برای پایش قیمت با پایتون

درخواست‌های زمان‌بندی‌شدهٔ پایش قیمت با پایتون را روی لینوکس از طریق پروکسی‌های دیتاسنتری Smartproxy مسیردهی کنید، با نگه‌داشتن اعتبارنامه‌ها بیرون از کد، تلاش‌های مجدد و عقب‌نشینی، راهنمای چرخش، ثبت CSV و زمان‌بندی cron.

لینوکس SOCKS5 HTTP(S) وب اسکرپینگ

مرور کلی

Smartproxy یک شبکهٔ پروکسی مناسب برای مبتدیان با استخرهای residential و datacenter است که از طریق HTTP و SOCKS5 قابل دسترسی هستند و بر اساس مدل هزینهٔ ثابت ماهانه صورت‌حساب می‌شوند. این آموزش استخر datacenter آن را به یک کار مشخص و رایج روی لینوکس اختصاص می‌دهد: پایش زمان‌بندی‌شدهٔ قیمت با پایتون.

پایش قیمت با IPهای دیتاسنتر خوب جور درمی‌آید. درخواست‌ها سریع هستند، هدف‌ها صفحات محصول عمومی‌اند و بار کاری بیشتر خواندنی است. اگر خرده‌فروش خاصی شروع به مسدود کردن محدوده‌های دیتاسنتر کند، همان اسکریپت روی استخر residential اجرا می‌شود — فقط endpoint و اعتبارنامه‌ها تغییر می‌کنند.

در پایان خواهید داشت:

  • اعتبارنامه‌هایی که بیرون از کد منبع شما ذخیره شده‌اند
  • یک درخواست پروکسی تأییدشده از خط فرمان
  • یک اسکریپت پایتون که صفحات محصول را از طریق پروکسی با تلاش مجدد و عقب‌نشینی واکشی می‌کند
  • قیمت‌هایی که با برچسب زمانی به یک فایل CSV افزوده می‌شوند
  • یک ورودی cron که کار را طبق زمان‌بندی اجرا می‌کند

برای هیچ‌کدام از این‌ها به رابط گرافیکی نیاز ندارید. Smartproxy افزونه‌های مرورگر هم ارائه می‌دهد، اما یک کار headless روی لینوکس فقط به host، port، username و password از داشبورد شما نیاز دارد.

پیش‌نیازها

  • یک میزبان لینوکس — دستورات زیر روی خانواده‌های Debian/Ubuntu و Fedora/RHEL کار می‌کنند
  • Python 3.9 یا جدیدتر
  • یک حساب Smartproxy با دسترسی پروکسی datacenter
  • host، port، username و password پروکسی که در داشبورد Smartproxy شما فهرست شده‌اند

دیتاسنتر یا Residential؟

هر دو نوع استخر در کد به‌صورت یکسان پیکربندی می‌شوند، بنابراین تصمیم دربارهٔ سایت هدف است، نه دربارهٔ ابزار.

عامل دیتاسنتر Residential
سرعت به‌ازای هر درخواست سریع متوسط
هزینه به‌ازای هر GB کمتر بیشتر
ریسک مسدود شدن در خرده‌فروشان بزرگ بیشتر کمتر
بهترین تناسب خواندن‌های پرحجم از سایت‌های مقاوم سایت‌های محافظت‌شده و قیمت‌گذاری جغرافیایی دقیق

قواعد سرانگشتی:

  • با datacenter شروع کنید، چون راه ارزان‌تر و سریع‌تری برای اثبات کارکرد parser شماست.
  • یک هدف سرسخت را به residential منتقل کنید، نه اینکه کل کار را مهاجرت دهید.
  • طرح پروکسی و احراز هویت را بین استخرها یکسان نگه دارید تا جابه‌جایی یک تغییر پیکربندی باشد، نه بازنویسی.

مراحل

مرحله ۱ — اعتبارنامه‌ها را export کنید و endpoint را تأیید کنید

چهار مقدار داشبورد خود را به‌عنوان متغیرهای محیطی برای نشست shell فعلی تنظیم کنید. جای‌نگهدارها را با مقادیر خودتان جایگزین کنید.

export SMART_HOST=\"<host-from-dashboard>\"
export SMART_PORT=\"<port-from-dashboard>\"
export SMART_USER=\"<username>\"
export SMART_PASS=\"<password>\"

یک درخواست تکی را از طریق پروکسی اجرا کنید. ارسال اعتبارنامه‌ها با -U از مشکلات مربوط به کاراکترهای خاص در password جلوگیری می‌کند.

curl -sS --max-time 20 -x \"http://${SMART_HOST}:${SMART_PORT}\" -U \"${SMART_USER}:${SMART_PASS}\" https://api.ipify.org

پاسخ باید یک آدرس IP باشد که IP خود سرور شما نیست. اگر به‌جای آن خطای 407 دیدید، به جدول عیب‌یابی در انتها بروید.

مرحله ۲ — پروژه را ایجاد کنید و اسرار را به یک فایل منتقل کنید

  1. یک دایرکتوری و یک محیط مجازی ایجاد کنید.
  2. requests به‌همراه python-dotenv را نصب کنید، که فایل .env را در زمان اجرا در محیط بارگذاری می‌کند.
mkdir -p ~/price-monitor && cd ~/price-monitor
python3 -m venv .venv && source .venv/bin/activate
pip install requests python-dotenv

فایل اسرار را ایجاد کنید و مجوزهای آن را محدود کنید. این فایل هرگز نباید commit شود.

# ~/price-monitor/.env
SMART_HOST=<host-from-dashboard>
SMART_PORT=<port-from-dashboard>
SMART_USER=<username>
SMART_PASS=<password>
chmod 600 .env
cat > .gitignore <<'EOF'
.env
.venv/
EOF

مرحله ۳ — آدرس پروکسی را در پایتون بسازید

آدرس را یک‌بار بسازید و دوباره استفاده کنید. quote کردن username و password با quote() از کاراکترهایی مانند @، : یا # محافظت می‌کند که در غیر این صورت تجزیه URL را می‌شکنند.

# ~/price-monitor/proxy_config.py
import os
from urllib.parse import quote
from dotenv import load_dotenv

load_dotenv()

def proxy_url(scheme='http'):
    user = quote(os.environ['SMART_USER'], safe='')
    password = quote(os.environ['SMART_PASS'], safe='')
    host = os.environ['SMART_HOST']
    port = os.environ['SMART_PORT']
    return f'{scheme}://{user}:{password}@{host}:{port}'

PROXIES = {'http': proxy_url(), 'https': proxy_url()}

اگر endpoint شما برای ترافیک HTTPS از پورت دیگری استفاده می‌کند، هر دو کلید را جداگانه تنظیم کنید، نه اینکه فرض کنید پورت مشترک است.

مرحله ۴ — صفحه‌ای را از طریق پروکسی با تلاش مجدد واکشی کنید

درخواست را در یک حلقهٔ کوچک تلاش مجدد بپیچید. عقب‌نشینی نمایی مانع از کوبیدن مداوم روی هدفی می‌شود که به شما محدودیت نرخ اعمال می‌کند.

# ~/price-monitor/fetch_price.py
import time
import requests
from proxy_config import PROXIES

HEADERS = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 '
                  '(KHTML, like Gecko) Chrome/124.0 Safari/537.36',
    'Accept-Language': 'en-US,en;q=0.9',
}

def fetch(url, retries=3, timeout=25):
    last_error = None
    for attempt in range(1, retries + 1):
        try:
            response = requests.get(url, headers=HEADERS, proxies=PROXIES, timeout=timeout)
            if response.status_code == 200:
                return response.text
            last_error = 'HTTP %s' % response.status_code
        except requests.RequestException as exc:
            last_error = str(exc)
        time.sleep(2 ** attempt)
    raise RuntimeError('Failed to fetch %s: %s' % (url, last_error))

if __name__ == '__main__':
    html = fetch('https://example.com/product/123')
    print(html[:500])

مرحله ۵ — قیمت را استخراج کنید و به CSV بیفزایید

پارسرهای HTML مانند BeautifulSoup یا selectolax استخراج مقاوم‌تری ارائه می‌دهند، اما یک regex برای اعتبارسنجی خط لوله پیش از سرمایه‌گذاری روی selectorها کافی است.

# ~/price-monitor/parse_price.py
import csv
import datetime
import re
import sys
from fetch_price import fetch

def parse_price(html):
    # Replace this pattern with a selector that matches the target site's markup.
    match = re.search(r'data-price=([0-9.]+)', html)
    return float(match.group(1)) if match else None

def main(url):
    price = parse_price(fetch(url))
    with open('prices.csv', 'a', newline='', encoding='utf-8') as handle:
        writer = csv.writer(handle)
        writer.writerow([datetime.datetime.now(datetime.UTC).isoformat(), url, price])

if __name__ == '__main__':
    main(sys.argv[1] if len(sys.argv) > 1 else 'https://example.com/product/123')

مرحله ۶ — تصمیم بگیرید چرخش برای endpoint شما چگونه کار کند

رفتار چرخش به endpointی که به شما داده شده بستگی دارد، بنابراین پیش از هر فرضی داشبورد خود را بررسی کنید:

  • اگر پورت در هر درخواست IP خروجی را می‌چرخاند، فراخوانی دوبارهٔ fetch() کافی است — هر اتصال جدید می‌تواند از IP متفاوتی خارج شود.
  • اگر پورت یک نشست sticky را نگه می‌دارد، بین پورت‌های فهرست‌شده در داشبورد بچرخید و برای هر worker یک پورت نگه دارید.
  • فقط زمانی دوباره از همان requests.Session() استفاده کنید که نشست sticky می‌خواهید؛ یک نشست تازه به‌ازای هر درخواست، پیش‌فرض امن‌تری برای پایش است.

برای تأیید چرخش، چند بار پشت‌سرهم endpoint مربوط به IP را درخواست کنید.

def check_ip():
    return fetch('https://api.ipify.org').strip()

if __name__ == '__main__':
    for _ in range(5):
        print(check_ip())

مرحله ۷ — همروندی متعادل اضافه کنید

یک thread pool فهرست طولانی URLها را کوتاه‌تر می‌کند، اما همروندی سریع‌ترین راه برای مسدود شدن هم هست. کوچک شروع کنید و تعداد worker را فقط تا زمانی که نرخ خطا ثابت می‌ماند افزایش دهید.

workerهای همروند زمان منطقی بودن
۱ تا ۳ اولین اجرا روی یک هدف جدید
۴ تا ۶ اجرای پایدار datacenter، بدون پاسخ‌های محدودیت نرخ
۸ یا بیشتر فقط پس از تست، و معمولاً با IPهای residential
from concurrent.futures import ThreadPoolExecutor, as_completed
from fetch_price import fetch

urls = [f'https://example.com/product/{sku}' for sku in range(1, 6)]

with ThreadPoolExecutor(max_workers=5) as pool:
    futures = {pool.submit(fetch, url): url for url in urls}
    for future in as_completed(futures):
        url = futures[future]
        try:
            print(url, len(future.result()))
        except Exception as exc:
            print(url, 'failed:', exc)

مرحله ۸ — کار را با cron زمان‌بندی کنید

crontab خود را ویرایش کنید و یک خط اضافه کنید. cd مهم است چون اسکریپت به قرار داشتن فایل .env در دایرکتوری کاری وابسته است.

crontab -e
0 */6 * * * cd /home/<user>/price-monitor && .venv/bin/python parse_price.py https://example.com/product/123 >> run.log 2>&1

از مسیر مطلق Python محیط مجازی استفاده کنید. python خالی زیر cron اغلب به مفسر سیستمی اشاره می‌کند و بسته‌های نصب‌شدهٔ شما را نمی‌بیند.

استفاده از SOCKS5 به‌جای HTTP

Smartproxy در کنار HTTP از SOCKS5 هم پشتیبانی می‌کند و جابه‌جایی یک تغییر یک‌خطی است. پورت SOCKS5 را در داشبورد خود تأیید کنید، چون ممکن است با پورت HTTP متفاوت باشد.

pip install 'requests[socks]'
PROXIES = {'http': proxy_url('socks5'), 'https': proxy_url('socks5')}

SOCKS5 زمانی مفید است که می‌خواهید resolution DNS هم از طریق پروکسی انجام شود، یا وقتی ابزار دیگری در خط لولهٔ شما فقط به SOCKS5 حرف می‌زند.

عیب‌یابی

نشانه علت احتمالی چه‌کار کنید
407 Proxy Authentication Required اعتبارنامه اشتباه یا کهنه، یا password با کاراکترهای خاص escape‌نشده مقادیر را از داشبورد دوباره کپی کنید، با دستور curl -U از مرحله ۱ تأیید کنید، و در پایتون به quote() تکیه کنید
403 یا صفحهٔ CAPTCHA هدف محدوده‌های datacenter را مسدود می‌کند، یا هدرها خودکار به نظر می‌رسند اجرا را کند کنید، هدرهای مرورگر واقع‌گرایانه بفرستید و آن هدف را به استخر residential منتقل کنید
429 Too Many Requests workerهای همروند بیش از حد زیاد max_workers را کاهش دهید، عقب‌نشینی نمایی را نگه دارید و بین دسته‌ها وقفه بیندازید
timeout اتصال در هر درخواست host یا port اشتباه، یا ترافیک خروجی روی آن پورت مسدود است بررسی curl را دوباره اجرا کنید؛ ufw، iptables یا هر سیاست خروج سازمانی برای پورت پروکسی را مرور کنید
با یک IP checker کار می‌کند اما روی هدف شکست می‌خورد محافظت ضدربات مخصوص آن سایت یک درخواست را در یک نشست مرورگر عادی تست کنید، هدرها را تنظیم کنید و انتظار داشته باشید برخی اهداف به IPهای residential نیاز داشته باشند
CERTIFICATE_VERIFY_FAILED بستهٔ CA قدیمی روی میزبان ca-certificates و بسته‌های محیط مجازی را به‌روزرسانی کنید، نه اینکه تأیید را غیرفعال کنید

خلاصه

  • استخر datacenter Smartproxy یک پیش‌فرض عملی برای پایش قیمت پرحجم و فقط‌خواندنی روی لینوکس است.
  • host، port، username و password را در یک فایل .env با مجوزهای 600 نگه دارید و آن‌ها را با python-dotenv بارگذاری کنید.
  • پیش از قرار دادن اعتبارنامه‌ها در URL پروکسی، آن‌ها را quote کنید، وگرنه کاراکترهای خاص تجزیه را می‌شکنند.
  • همیشه timeout درخواست را تنظیم کنید، با عقب‌نشینی دوباره تلاش کنید، و همروندی را پایین نگه دارید تا نرخ خطا ثابت کند افزایش آن امن است.
  • داشبورد خود را بررسی کنید تا بدانید endpoint شما در هر درخواست می‌چرخد یا نشست sticky را نگه می‌دارد، سپس اجرا را بر آن اساس طراحی کنید.
  • یک هدف مسدودشدهٔ تکی را به استخر residential تغییر دهید، نه اینکه کار را از نو بسازید، و از SOCKS5 فقط زمانی استفاده کنید که برای DNS یا دلایل ابزاری به آن نیاز دارید.