Update cloud_monitor.py
Browse files- cloud_monitor.py +88 -50
cloud_monitor.py
CHANGED
|
@@ -122,79 +122,117 @@ async def run_monitor():
|
|
| 122 |
print(" Page load timed out, trying to continue...")
|
| 123 |
|
| 124 |
# ============================================================
|
| 125 |
-
# STEP 2: Click "Live Betting"
|
| 126 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
# ============================================================
|
| 128 |
live_clicked = False
|
| 129 |
|
| 130 |
-
#
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
-
#
|
| 141 |
if not live_clicked:
|
| 142 |
try:
|
| 143 |
-
el = await page.query_selector("span
|
| 144 |
if el:
|
| 145 |
await el.evaluate("el => el.click()")
|
| 146 |
live_clicked = True
|
| 147 |
-
print(" Clicked Live Betting (method
|
| 148 |
except Exception:
|
| 149 |
pass
|
| 150 |
|
| 151 |
-
#
|
|
|
|
| 152 |
if not live_clicked:
|
| 153 |
try:
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
except Exception:
|
| 158 |
pass
|
| 159 |
|
| 160 |
if not live_clicked:
|
| 161 |
-
print(" WARNING: Could not
|
|
|
|
|
|
|
|
|
|
| 162 |
await asyncio.sleep(CHECK_INTERVAL)
|
| 163 |
continue
|
| 164 |
|
| 165 |
await asyncio.sleep(5)
|
| 166 |
|
| 167 |
-
#
|
| 168 |
-
#
|
| 169 |
-
# "
|
| 170 |
-
# The local monitor doesn't do this because Selenium keeps
|
| 171 |
-
# the URL context. In Playwright, the Live Betting page
|
| 172 |
-
# may show a generic sports list first.
|
| 173 |
-
# ============================================================
|
| 174 |
-
try:
|
| 175 |
-
vfootball_link = await page.query_selector("text=vFootball")
|
| 176 |
-
if vfootball_link:
|
| 177 |
-
await vfootball_link.evaluate("el => el.click()")
|
| 178 |
-
await asyncio.sleep(3)
|
| 179 |
-
print(" Clicked 'vFootball' in sidebar")
|
| 180 |
-
except Exception:
|
| 181 |
-
pass
|
| 182 |
-
|
| 183 |
-
# Now click England specifically
|
| 184 |
-
try:
|
| 185 |
-
# Look for England link in the left panel
|
| 186 |
-
england_link = await page.query_selector("div.league-cell:has-text('England')")
|
| 187 |
-
if england_link:
|
| 188 |
-
await england_link.evaluate("el => el.click()")
|
| 189 |
-
await asyncio.sleep(3)
|
| 190 |
-
print(" Clicked 'England' in league list")
|
| 191 |
-
else:
|
| 192 |
-
# Try broader match
|
| 193 |
-
await page.click("text=England", timeout=5000)
|
| 194 |
-
await asyncio.sleep(3)
|
| 195 |
-
print(" Clicked 'England' (text match)")
|
| 196 |
-
except Exception:
|
| 197 |
-
print(" Could not click England")
|
| 198 |
|
| 199 |
# ============================================================
|
| 200 |
# STEP 4: Wait for England Virtual matches β RETRY LOOP
|
|
|
|
| 122 |
print(" Page load timed out, trying to continue...")
|
| 123 |
|
| 124 |
# ============================================================
|
| 125 |
+
# STEP 2: Click the "Live Betting" TOGGLE inside the vFootball
|
| 126 |
+
# page content β NOT the "Live Betting" in the top nav bar!
|
| 127 |
+
#
|
| 128 |
+
# The page has TWO elements with "Live Betting" text:
|
| 129 |
+
# - Top nav bar link β navigates AWAY (WRONG!)
|
| 130 |
+
# - In-page toggle β shows live matches (CORRECT!)
|
| 131 |
+
#
|
| 132 |
+
# The local monitor targets it with these XPATHs:
|
| 133 |
+
# //div[@role='text leaf' and contains(text(),'Live Betting')]
|
| 134 |
+
# //div[contains(@class,'league-title')]//span[@data-cms-key='live_betting']
|
| 135 |
+
# //div[contains(@class,'league-title')]//span[contains(text(),'Live Betting')]
|
| 136 |
# ============================================================
|
| 137 |
live_clicked = False
|
| 138 |
|
| 139 |
+
# Method 1: role='text leaf' (exact from local monitor line 58)
|
| 140 |
+
if not live_clicked:
|
| 141 |
+
try:
|
| 142 |
+
el = await page.query_selector("div[role='text leaf']")
|
| 143 |
+
if el:
|
| 144 |
+
text = await el.inner_text()
|
| 145 |
+
if 'Live Betting' in text:
|
| 146 |
+
await el.evaluate("el => el.click()")
|
| 147 |
+
live_clicked = True
|
| 148 |
+
print(" Clicked Live Betting (method 1: role text leaf)")
|
| 149 |
+
except Exception:
|
| 150 |
+
pass
|
| 151 |
+
|
| 152 |
+
# Method 2: inside league-title with data-cms-key (local monitor line 69)
|
| 153 |
+
if not live_clicked:
|
| 154 |
+
try:
|
| 155 |
+
el = await page.query_selector("div.league-title span[data-cms-key='live_betting']")
|
| 156 |
+
if el:
|
| 157 |
+
await el.evaluate("el => el.click()")
|
| 158 |
+
live_clicked = True
|
| 159 |
+
print(" Clicked Live Betting (method 2: league-title cms-key)")
|
| 160 |
+
except Exception:
|
| 161 |
+
pass
|
| 162 |
|
| 163 |
+
# Method 3: inside league-title with text (local monitor line 64)
|
| 164 |
if not live_clicked:
|
| 165 |
try:
|
| 166 |
+
el = await page.query_selector("div.league-title span:has-text('Live Betting')")
|
| 167 |
if el:
|
| 168 |
await el.evaluate("el => el.click()")
|
| 169 |
live_clicked = True
|
| 170 |
+
print(" Clicked Live Betting (method 3: league-title span text)")
|
| 171 |
except Exception:
|
| 172 |
pass
|
| 173 |
|
| 174 |
+
# Method 4: Look for the checkbox/link that says "Live Betting" with a number
|
| 175 |
+
# In the screenshot it shows "Live Betting 39" β target the one with a number
|
| 176 |
if not live_clicked:
|
| 177 |
try:
|
| 178 |
+
# Find all elements with "Live Betting", skip the top nav one
|
| 179 |
+
elements = await page.query_selector_all("*:has-text('Live Betting')")
|
| 180 |
+
for el in elements:
|
| 181 |
+
text = (await el.inner_text()).strip()
|
| 182 |
+
tag = await el.evaluate("el => el.tagName")
|
| 183 |
+
# The in-page one has a number like "Live Betting 39"
|
| 184 |
+
# The top nav just says "Live Betting"
|
| 185 |
+
if 'Live Betting' in text and any(c.isdigit() for c in text) and tag != 'NAV':
|
| 186 |
+
parent_class = await el.evaluate("el => el.className || ''")
|
| 187 |
+
if 'nav' not in parent_class.lower() and 'header' not in parent_class.lower():
|
| 188 |
+
await el.evaluate("el => el.click()")
|
| 189 |
+
live_clicked = True
|
| 190 |
+
print(f" Clicked Live Betting (method 4: element with number '{text[:30]}')")
|
| 191 |
+
break
|
| 192 |
+
except Exception:
|
| 193 |
+
pass
|
| 194 |
+
|
| 195 |
+
# Method 5: Use JavaScript to find and click (nuclear option)
|
| 196 |
+
if not live_clicked:
|
| 197 |
+
try:
|
| 198 |
+
clicked = await page.evaluate("""() => {
|
| 199 |
+
// Find all elements containing "Live Betting"
|
| 200 |
+
const walker = document.createTreeWalker(
|
| 201 |
+
document.body, NodeFilter.SHOW_ELEMENT
|
| 202 |
+
);
|
| 203 |
+
while (walker.nextNode()) {
|
| 204 |
+
const el = walker.currentNode;
|
| 205 |
+
const text = el.textContent || '';
|
| 206 |
+
const cls = el.className || '';
|
| 207 |
+
// Target elements inside league-title or with role text
|
| 208 |
+
if (text.includes('Live Betting') &&
|
| 209 |
+
(cls.includes('league-title') || el.getAttribute('role') === 'text leaf' ||
|
| 210 |
+
cls.includes('league-tab'))) {
|
| 211 |
+
el.click();
|
| 212 |
+
return 'clicked: ' + cls;
|
| 213 |
+
}
|
| 214 |
+
}
|
| 215 |
+
return null;
|
| 216 |
+
}""")
|
| 217 |
+
if clicked:
|
| 218 |
+
live_clicked = True
|
| 219 |
+
print(f" Clicked Live Betting (method 5: JS walker - {clicked})")
|
| 220 |
except Exception:
|
| 221 |
pass
|
| 222 |
|
| 223 |
if not live_clicked:
|
| 224 |
+
print(" WARNING: Could not find in-page Live Betting toggle!")
|
| 225 |
+
# Debug: screenshot to see current state
|
| 226 |
+
if cycle <= 10:
|
| 227 |
+
await page.screenshot(path=f"debug_livebtn_fail_{cycle}.png")
|
| 228 |
await asyncio.sleep(CHECK_INTERVAL)
|
| 229 |
continue
|
| 230 |
|
| 231 |
await asyncio.sleep(5)
|
| 232 |
|
| 233 |
+
# No need to click vFootball or England β the URL already targets
|
| 234 |
+
# the correct league. The Live Betting toggle just switches from
|
| 235 |
+
# "scheduled" to "live" matches within that league.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
|
| 237 |
# ============================================================
|
| 238 |
# STEP 4: Wait for England Virtual matches β RETRY LOOP
|