chore: remove cf-fetch.ts (puppeteer CF bypass not working for Leet/Hubbly/Habblet)
Cloudflare has strengthened protection on these hotels. Puppeteer-based bypass returns HTML instead of JSON. cloudscraper has dependency issues with Node.js v26. Reverting to simple HTTP fetch with clear error messages.
This commit is contained in:
1 parent
cef068ff3c
commit
5c60ce364c
3 files changed
+389
-107
No files matched your search
@@ -1,103 +0,0 @@
|
||||
import puppeteer from "puppeteer";
|
||||
|
||||
const UA =
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) " +
|
||||
"Chrome/125.0.0.0 Safari/537.36";
|
||||
|
||||
let browser: Awaited<ReturnType<typeof puppeteer.launch>> | null = null;
|
||||
|
||||
async function getBrowser() {
|
||||
if (browser) return browser;
|
||||
browser = await puppeteer.launch({
|
||||
headless: true,
|
||||
args: [
|
||||
"--no-sandbox",
|
||||
"--disable-setuid-sandbox",
|
||||
"--disable-web-security",
|
||||
"--disable-blink-features=AutomationControlled",
|
||||
"--user-agent=" + UA,
|
||||
],
|
||||
});
|
||||
return browser;
|
||||
}
|
||||
|
||||
export async function fetchWithCfBypass(
|
||||
url: string,
|
||||
timeout = 30000,
|
||||
): Promise<string> {
|
||||
const b = await getBrowser();
|
||||
const page = await b.newPage();
|
||||
await page.setUserAgent(UA);
|
||||
await page.setDefaultTimeout(timeout);
|
||||
|
||||
try {
|
||||
const response = await page.goto(url, {
|
||||
waitUntil: "networkidle2",
|
||||
timeout,
|
||||
});
|
||||
|
||||
const status = response?.status() ?? 0;
|
||||
const body = await page.content();
|
||||
|
||||
const isCfChallenge =
|
||||
body.includes("Attention Required") ||
|
||||
body.includes("Checking your browser") ||
|
||||
body.includes("Just a moment") ||
|
||||
body.includes("cf-challenge") ||
|
||||
status === 403;
|
||||
|
||||
if (isCfChallenge) {
|
||||
try {
|
||||
await page.waitForFunction(
|
||||
() =>
|
||||
document.body.innerHTML.includes("cf-captcha") ||
|
||||
document.body.innerHTML.includes("challenge-platform"),
|
||||
{ timeout: 5000 },
|
||||
);
|
||||
} catch {
|
||||
// CF challenge might have been solved already
|
||||
}
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
|
||||
const finalBody = await page.content();
|
||||
return finalBody;
|
||||
} finally {
|
||||
try {
|
||||
await page.close();
|
||||
} catch {
|
||||
// ignore cleanup errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchJsonWithCfBypass<T = unknown>(
|
||||
url: string,
|
||||
timeout = 30000,
|
||||
): Promise<T> {
|
||||
const html = await fetchWithCfBypass(url, timeout);
|
||||
const match = html.match(
|
||||
/<pre[^>]*class="[^"]*json[^"]*"[^>]*>([\s\S]*?)<\/pre>/i,
|
||||
);
|
||||
if (match) {
|
||||
return JSON.parse(match[1].trim()) as T;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(html) as T;
|
||||
} catch {
|
||||
throw new Error(`cf-fetch: could not parse JSON from ${url}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function closeCfBrowser(): Promise<void> {
|
||||
if (browser) {
|
||||
try {
|
||||
await browser.close();
|
||||
} catch {
|
||||
// ignore cleanup errors
|
||||
}
|
||||
browser = null;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user