UNPKG

rsshub

Version:
95 lines (94 loc) 3.93 kB
import { t as getPlaywrightPage } from "./playwright-CFVkq6JF.mjs"; import { t as getSignedHeaders } from "./sign-JzOJfAzW.mjs"; //#region lib/routes/zhihu/browser.ts const origin = "https://www.zhihu.com"; const allowedResources = /* @__PURE__ */ new Set([ "document", "script", "xhr", "fetch" ]); const parseApiResponse = (body) => { try { return JSON.parse(body); } catch { throw new Error("zhihu: browser API request did not return JSON"); } }; const createBrowserClient = async (url, configuredCookies, initialApiPath) => { const { page, context, destroy } = await getPlaywrightPage(url, { noGoto: true, closeTimeout: 0 }); let phase = "cookie setup"; try { const cookies = configuredCookies.split(";").map((pair) => pair.trim()).filter((pair) => pair.indexOf("=") > 0).map((pair) => { const separator = pair.indexOf("="); return { name: pair.slice(0, separator), value: pair.slice(separator + 1), domain: ".zhihu.com", path: "/" }; }); if (cookies.length) await context.addCookies(cookies); await page.route("**/*", (route) => allowedResources.has(route.request().resourceType()) ? route.continue() : route.abort()); if (cookies.every((cookie) => cookie.name !== "d_c0" || !cookie.value)) { phase = "guest cookie initialization"; await page.goto(`${origin}/explore`, { waitUntil: "domcontentloaded" }); if ((await context.cookies(origin)).every((cookie) => cookie.name !== "d_c0" || !cookie.value)) throw new Error("The browser did not receive a guest d_c0 cookie"); } phase = "page navigation"; const response = await page.goto(initialApiPath ? `${origin}${initialApiPath}` : url, { waitUntil: "domcontentloaded" }); const isJson = response?.headers()["content-type"]?.includes("application/json"); if (!isJson) { phase = "session cookie wait"; await page.waitForFunction(() => document.cookie.split(";").some((pair) => pair.trimStart().startsWith("__zse_ck=")), void 0, { timeout: 1e4 }); } phase = "session cookie validation"; const browserCookies = await context.cookies(origin); if ((isJson ? ["d_c0"] : ["d_c0", "__zse_ck"]).some((name) => browserCookies.every((cookie) => cookie.name !== name || !cookie.value))) throw new Error("The browser did not receive the required cookies"); let initialResponse = initialApiPath && isJson && response && response.status() >= 200 && response.status() < 300 ? { apiPath: initialApiPath, body: await response.text() } : void 0; return { get: async (apiPath) => { if (initialResponse?.apiPath === apiPath) { const { body } = initialResponse; initialResponse = void 0; return parseApiResponse(body); } if (new URL(page.url()).origin !== origin) await page.goto(`${origin}/explore`, { waitUntil: "domcontentloaded" }); const dc0 = (await context.cookies(origin)).find((cookie) => cookie.name === "d_c0")?.value; if (!dc0) throw new Error("zhihu: the browser session lost its d_c0 cookie"); const result = await page.evaluate(async ({ apiUrl, headers }) => { const response = await fetch(apiUrl, { headers, credentials: "include", signal: window.AbortSignal.timeout(3e4) }); return { status: response.status, body: await response.text() }; }, { apiUrl: `${origin}${apiPath}`, headers: getSignedHeaders(apiPath, dc0) }); if (result.status < 200 || result.status >= 300) throw new Error(`zhihu: browser API request failed with HTTP ${result.status}`); return parseApiResponse(result.body); }, getPage: async () => { await page.goto(url, { waitUntil: "domcontentloaded" }); return page.content(); }, close: destroy }; } catch { await destroy(); throw new Error(`zhihu: browser session failed during ${phase}. Configure ZHIHU_COOKIES with an accessible session containing d_c0 and __zse_ck.`); } }; //#endregion export { createBrowserClient };