تبدأ كل جلسة متصفح جديدة من الصفر - بدون ملفات تعريف الارتباط، ولا حالة محفوظة، ولا سجل تشغيل معروف. في التطبيقات المملوكة قد يؤدي ذلك إلى اختلاف سلوك CAPTCHA بين تشغيل وآخر. تساعد الجلسات المستمرة بين عمليات التشغيل على إعادة إنتاج نفس الحالة الوظيفية وتقليل التفاوت غير المقصود بين اختبارات QA.
لماذا يؤدي استمرار الجلسة إلى تقليل اختبارات CAPTCHA
| حالة الجلسة | تردد الكابتشا | لماذا |
|---|---|---|
| جلسة جديدة (بدون ملفات تعريف الارتباط) | عالية | لا توجد حالة تطبيق محفوظة بعد |
| جلسة سابقة داخل التطبيق نفسه | متوسطة | يمكن إعادة استخدام بيانات الاعتماد والحالة الوظيفية |
| جلسة مهيأة داخل صفحات مملوكة | أقل | تكون عناصر التطبيق والخطوات المسبقة قد اكتملت |
| ملف شخصي مستمر لعمر اختباري معروف | أقل نسبيًا | يسهل إعادة إنتاج نفس الحالة بين التشغيلات |
ثبات ملفات تعريف الارتباط (السيلينيوم/Python)
حفظ واستعادة ملفات تعريف الارتباط
import json
import os
import time
from selenium import webdriver
class PersistentSession:
def __init__(self, profile_name="default", cookie_dir="./sessions"):
self.profile_name = profile_name
self.cookie_dir = cookie_dir
self.cookie_file = os.path.join(cookie_dir, f"{profile_name}_cookies.json")
os.makedirs(cookie_dir, exist_ok=True)
def create_driver(self):
options = webdriver.ChromeOptions()
options.add_argument("--window-size=1920,1080")
return webdriver.Chrome(options=options)
def save_cookies(self, driver):
"""Save all cookies to disk."""
cookies = driver.get_cookies()
with open(self.cookie_file, "w") as f:
json.dump(cookies, f, indent=2)
print(f"Saved {len(cookies)} cookies to {self.cookie_file}")
def load_cookies(self, driver, domain=None):
"""Restore cookies from disk."""
if not os.path.exists(self.cookie_file):
print("No saved cookies found")
return False
with open(self.cookie_file) as f:
cookies = json.load(f)
loaded = 0
for cookie in cookies:
# Filter by domain if specified
if domain and domain not in cookie.get("domain", ""):
continue
# Remove problematic fields
cookie.pop("sameSite", None)
cookie.pop("storeId", None)
try:
driver.add_cookie(cookie)
loaded += 1
except Exception as e:
print(f"Skip cookie {cookie.get('name')}: {e}")
print(f"Loaded {loaded}/{len(cookies)} cookies")
return loaded > 0
def run_with_session(self, url, callback):
"""Run a task with persistent session."""
driver = self.create_driver()
try:
# Navigate to domain first (required for cookie loading)
driver.get(url)
time.sleep(1)
# Load saved cookies
self.load_cookies(driver)
# Refresh to apply cookies
driver.get(url)
time.sleep(2)
# Execute task
result = callback(driver)
# Save updated cookies
self.save_cookies(driver)
return result
finally:
driver.quit()
# Usage
session = PersistentSession("target-site")
def my_task(driver):
# Check if already logged in
if "dashboard" in driver.current_url:
print("Session restored — no login needed")
return driver.page_source
else:
print("Need to login + solve CAPTCHA")
# Solve CAPTCHA with CaptchaAI...
return None
result = session.run_with_session("https://example.com", my_task)
دليل بيانات مستخدم Chrome (استمرارية الملف الشخصي بالكامل)
الثبات الأكثر اكتمالًا - يحفظ ملفات تعريف الارتباط والتخزين المحلي وذاكرة التخزين المؤقت والسجل وحالة المتصفح:
import os
from selenium import webdriver
PROFILE_DIR = os.path.abspath("./chrome-profiles/profile-1")
def create_persistent_driver():
options = webdriver.ChromeOptions()
options.add_argument(f"--user-data-dir={PROFILE_DIR}")
options.add_argument("--profile-directory=Default")
options.add_argument("--no-sandbox")
return webdriver.Chrome(options=options)
# First run: builds fresh profile
driver = create_persistent_driver()
driver.get("https://example.com")
# ... solve CAPTCHA, login, etc.
driver.quit()
# Second run: same profile, cookies and state preserved
driver = create_persistent_driver()
driver.get("https://example.com")
# Often skips CAPTCHA because session is recognized
driver.quit()
فوائد دليل بيانات المستخدم
| ما تم حفظه | التأثير على اختبارات CAPTCHA |
|---|---|
| ملفات تعريف الارتباط | رموز الجلسة والتفضيلات الصادرة من تطبيقك |
| localStorage | رموز الثقة الخاصة بالموقع |
| مفهرسةDB | reCAPTCHA الحالة الداخلية |
| ذاكرة التخزين المؤقت | تحميل أسرع للصفحة |
| التاريخ | إشارات نمط التصفح |
| عمال الخدمة | الشيكات الخلفية CAPTCHA |
Puppeteer السياق المستمر
const puppeteer = require("puppeteer");
const path = require("path");
const USER_DATA_DIR = path.resolve("./chrome-profiles/profile-1");
async function runWithPersistentProfile() {
const browser = await puppeteer.launch({
headless: false,
userDataDir: USER_DATA_DIR,
args: [
"--no-sandbox",
"--window-size=1920,1080",
],
});
const page = await browser.newPage();
await page.goto("https://example.com", { waitUntil: "networkidle0" });
// Check if session is active
const isLoggedIn = await page.evaluate(() =>
document.querySelector(".user-menu") !== null
);
if (isLoggedIn) {
console.log("Session active — no CAPTCHA needed");
} else {
console.log("Session expired — solving CAPTCHA");
// Solve with CaptchaAI...
}
await browser.close();
}
التخزين المحلي وتخزين الجلسة
def save_storage(driver, filepath):
"""Save localStorage and sessionStorage."""
storage = driver.execute_script("""
return {
localStorage: Object.fromEntries(
Object.entries(localStorage)
),
sessionStorage: Object.fromEntries(
Object.entries(sessionStorage)
),
};
""")
with open(filepath, "w") as f:
json.dump(storage, f, indent=2)
def restore_storage(driver, filepath):
"""Restore localStorage and sessionStorage."""
if not os.path.exists(filepath):
return
with open(filepath) as f:
storage = json.load(f)
for key, value in storage.get("localStorage", {}).items():
driver.execute_script(
f"localStorage.setItem('{key}', '{value}')"
)
for key, value in storage.get("sessionStorage", {}).items():
driver.execute_script(
f"sessionStorage.setItem('{key}', '{value}')"
)
تهيئة جلسة الاختبار داخل التطبيق المملوك
بدل استخدام صفحات خارجية أو محاكاة سلوك غير مرتبط بالموقع، جهّز الجلسة عبر خطوات تملكها أنت، مثل صفحة الصحة، وصفحة تسجيل الدخول الاختبارية، وصفحة المساعدة الداخلية. هذا يمنح الفريق حالة تشغيل معروفة وقابلة للتكرار.
import time
def prime_session(driver, owned_urls=None):
"""Load owned application pages to establish a known QA session state."""
default_urls = [
"https://staging.example.com/health",
"https://staging.example.com/help",
"https://staging.example.com/login",
]
urls = owned_urls or default_urls
for url in urls:
driver.get(url)
time.sleep(2)
print(f"Prepared QA session with {len(urls)} owned pages")
driver = create_persistent_driver()
prime_session(driver)
driver.get("https://staging.example.com/form")
مدير جلسة متعدد الملفات الشخصية
import os
import json
import time
from datetime import datetime
class SessionManager:
"""Manage multiple persistent browser profiles."""
def __init__(self, base_dir="./sessions"):
self.base_dir = base_dir
self.meta_file = os.path.join(base_dir, "profiles.json")
os.makedirs(base_dir, exist_ok=True)
if os.path.exists(self.meta_file):
with open(self.meta_file) as f:
self.profiles = json.load(f)
else:
self.profiles = {}
def _save_meta(self):
with open(self.meta_file, "w") as f:
json.dump(self.profiles, f, indent=2)
def get_profile_dir(self, name):
return os.path.join(self.base_dir, f"profile-{name}")
def create_profile(self, name, network_label=None):
"""Create a new browser profile."""
profile_dir = self.get_profile_dir(name)
os.makedirs(profile_dir, exist_ok=True)
self.profiles[name] = {
"created": datetime.now().isoformat(),
"last_used": None,
"use_count": 0,
"network_label": network_label,
"captcha_solves": 0,
}
self._save_meta()
return profile_dir
def get_least_used_profile(self):
"""Get the profile used least recently."""
if not self.profiles:
return None
return min(
self.profiles.items(),
key=lambda x: x[1].get("last_used") or ""
)[0]
def record_use(self, name, solved_captcha=False):
"""Record profile usage."""
if name in self.profiles:
self.profiles[name]["last_used"] = datetime.now().isoformat()
self.profiles[name]["use_count"] += 1
if solved_captcha:
self.profiles[name]["captcha_solves"] += 1
self._save_meta()
def get_stats(self):
"""Print profile statistics."""
for name, meta in self.profiles.items():
print(f"Profile: {name}")
print(f" Uses: {meta['use_count']}")
print(f" CAPTCHAs: {meta['captcha_solves']}")
print(f" Last used: {meta.get('last_used', 'never')}")
print()
# Usage
manager = SessionManager()
# Create 5 rotating profiles
for i in range(5):
manager.create_profile(f"worker-{i}")
# Get next profile to use
profile_name = manager.get_least_used_profile()
profile_dir = manager.get_profile_dir(profile_name)
# Use with Selenium
options = webdriver.ChromeOptions()
options.add_argument(f"--user-data-dir={os.path.abspath(profile_dir)}")
driver = webdriver.Chrome(options=options)
# After task
manager.record_use(profile_name, solved_captcha=True)
manager.get_stats()
دوران ملفات تعريف الارتباط وانتهاء الصلاحية
from datetime import datetime, timezone
def clean_expired_cookies(cookie_file):
"""Remove expired cookies from saved file."""
if not os.path.exists(cookie_file):
return
with open(cookie_file) as f:
cookies = json.load(f)
now = datetime.now(timezone.utc).timestamp()
valid = [c for c in cookies if c.get("expiry", float("inf")) > now]
removed = len(cookies) - len(valid)
if removed > 0:
with open(cookie_file, "w") as f:
json.dump(valid, f, indent=2)
print(f"Removed {removed} expired cookies")
def merge_cookies(existing_file, new_cookies):
"""Merge new cookies with existing, preferring newer values."""
existing = []
if os.path.exists(existing_file):
with open(existing_file) as f:
existing = json.load(f)
# Index by (name, domain)
cookie_map = {}
for c in existing:
key = (c["name"], c.get("domain", ""))
cookie_map[key] = c
for c in new_cookies:
key = (c["name"], c.get("domain", ""))
cookie_map[key] = c # Newer overwrites
merged = list(cookie_map.values())
with open(existing_file, "w") as f:
json.dump(merged, f, indent=2)
return len(merged)
استكشاف الأخطاء وإصلاحها
| المشكلة | السبب | الإجراء |
|---|---|---|
| لا يتم تحميل ملفات تعريف الارتباط | لم تنتقل إلى المجال أولاً | اتصل بـ driver.get(url) قبل add_cookie |
| خطأ في قفل الملف الشخصي | لم يتم إغلاق Chrome السابق | قم بإنهاء عمليات Chrome، وإزالة SingletonLock |
| لا تزال الجلسة منتهية الصلاحية | ملف تعريف الارتباط sameSite غير متطابق |
قم بإزالة sameSite قبل التحميل |
| تم حظر التخزين | سياق CORS/security | قم بتحميل التخزين بعد الانتقال إلى الأصل الصحيح |
| معدل CAPTCHA أعلى مع مرور الوقت | تغيّر في بيئة الشبكة أو الجلسة | راجع فصل الشبكة بين سيناريوهات QA وسجل تغييرات البيئة |
الأسئلة الشائعة
ما المدة التي تستغرقها جلسات المتصفح في تقليل تكرار اختبار CAPTCHA؟
لا توجد مدة ثابتة تصلح لكل تطبيق. المقياس الصحيح هو عمر الجلسة داخل نظامك نفسه ومدة صلاحية ملفات تعريف الارتباط أو الرموز التي يصدرها تطبيقك أو بوابة الحماية التي تملكها.
هل يمكنني مشاركة الجلسات بين الأجهزة؟
نعم، إذا كان ذلك جزءًا من بنية الاختبار لديك. عند النقل بين الأجهزة، طابق إصدار المتصفح وإعدادات التطبيق والبيئة الزمنية حتى يبقى السيناريو قابلًا للمقارنة.
هل يعمل استمرار الجلسة مع Chrome مقطوعة الرأس؟
نعم. تعمل أدلة بيانات المستخدم وملفات تعريف الارتباط بشكل مماثل في وضع مقطوعة الرأس، لكن يجب اختبار ذلك داخل بيئتك لأن سلوك الصفحة قد يختلف حسب إطار التشغيل.
كم عدد الملفات الشخصية التي يجب أن أحتفظ بها؟
احتفظ بعدد محدود من الملفات الشخصية لكل سيناريو QA تحتاج إلى إعادة إنتاجه. ابدأ بعدد صغير، ثم زد فقط عندما يظهر احتياج تشخيصي واضح.
هل يستفيد CaptchaAI من ثبات الجلسة؟
بشكل غير مباشر — يؤدي استمرار الجلسة إلى تقليل تكرار اختبار CAPTCHA، مما يقلل عدد مكالمات CaptchaAI المطلوبة (توفير التكلفة). عندما تظهر اختبارات CAPTCHA، يقوم CaptchaAI بحلها كالمعتاد.
أدلة ذات صلة
- عزل ملف تعريف المتصفح + تكامل CaptchaAI
- امتداد المتصفح مقابل واجهة برمجة التطبيقات: ما هو نهج حل CAPTCHA الأفضل؟
إنشاء جلسات متصفح مستمرة تقلل من تحديات اختبار CAPTCHA —احصل على مفتاح CaptchaAI الخاص بكعندما لا تزال التحديات تظهر.