Skip to content

fix: switch kuaishou route from HTML scraping to GraphQL API#141

Open
RyoSXu wants to merge 2 commits into
imsyy:masterfrom
RyoSXu:fix/kuaishou-api
Open

fix: switch kuaishou route from HTML scraping to GraphQL API#141
RyoSXu wants to merge 2 commits into
imsyy:masterfrom
RyoSXu:fix/kuaishou-api

Conversation

@RyoSXu

@RyoSXu RyoSXu commented Jul 2, 2026

Copy link
Copy Markdown

Summary

The kuaishou route was relying on scraping the __APOLLO_STATE__ data embedded in the HTML homepage. Kuaishou has changed their page structure and the visionHotRank data is no longer present in the initial HTML, causing the route to fail with 快手页面结构变更 errors.

This PR replaces the HTML scraping approach with a direct GraphQL API request to https://www.kuaishou.com/graphql using the visionHotRank query, which still returns the hot ranking data reliably.

Changes

  • Replace get() HTML request with post() GraphQL request
  • Remove APOLLO_STATE parsing logic (~50 lines of fragile JSON extraction)
  • Simplify KuaishouHotItem interface for GraphQL response shape
  • Add fallback search URL when photoId is unavailable

Testing

  • ESLint passes (0 errors)
  • TypeScript compilation passes (tsc --noEmit)
  • Prettier formatting passes
  • Manual test: server returns 50 items with correct titles, hot values, and video URLs
GET /kuaishou -> 200 OK
Total: 50 items
FromCache: false

Fixes #127

The kuaishou route was relying on scraping the __APOLLO_STATE__ data
embedded in the HTML homepage. Kuaishou has changed their page structure
and the visionHotRank data is no longer present in the initial HTML,
causing the route to fail with '快手页面结构变更' errors.

This replaces the HTML scraping approach with a direct GraphQL API
request to https://www.kuaishou.com/graphql using the visionHotRank
query, which still returns the hot ranking data reliably.

Changes:
- Replace get() HTML request with post() GraphQL request
- Remove APOLLO_STATE parsing logic (~50 lines)
- Simplify KuaishouHotItem interface for GraphQL response shape
- Add fallback search URL when photoId is unavailable

Fixes imsyy#127

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the Kuaishou route to fetch hot ranking data directly via a GraphQL POST request instead of scraping the HTML page and parsing the Apollo state. This significantly simplifies the data retrieval logic and types. The review feedback highlights two important improvements: throwing an error if the GraphQL response structure is missing or malformed to prevent silent failures, and wrapping decodeURIComponent in a try-catch block to prevent potential URIError crashes from malformed external URLs.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/routes/kuaishou.ts Outdated
id: hotItem.id,
title: hotItem.name,

const items = result.data?.data?.visionHotRank?.items || [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the GraphQL API response structure changes or the request fails, result.data?.data?.visionHotRank?.items will be undefined, and items will default to an empty array []. This causes the route to silently return an empty list (with a 200 OK status) instead of throwing an error, making it difficult to detect and monitor failures.

We should throw an error if the expected data structure is missing, similar to how the previous implementation handled structural changes.

  const items = result.data?.data?.visionHotRank?.items;
  if (!items) {
    throw new Error("快手接口返回数据格式异常,未找到 visionHotRank.items");
  }

Comment thread src/routes/kuaishou.ts Outdated
const items = result.data?.data?.visionHotRank?.items || [];
const listData: ListItem[] = items.map((item: KuaishouHotItem, index: number) => {
const photoId = item.photoIds?.[0];
const poster = item.poster ? decodeURIComponent(item.poster) : undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Calling decodeURIComponent directly on external data (item.poster) without error handling is risky. If Kuaishou returns a malformed URL containing an invalid percent-encoded sequence (e.g., a single % not followed by two hex digits), decodeURIComponent will throw a URIError and crash the entire request.

It is safer to wrap this in a try-catch block or use a safe decoding helper to ensure the route remains resilient.

    let poster: string | undefined;
    if (item.poster) {
      try {
        poster = decodeURIComponent(item.poster);
      } catch {
        poster = item.poster;
      }
    }

Address Gemini Code Assist review feedback on PR imsyy#141:

1. Throw an error when visionHotRank.items is missing from the GraphQL
   response instead of silently returning an empty list, making failures
   easier to detect and monitor.

2. Wrap decodeURIComponent in a try-catch block to prevent URIError
   crashes when Kuaishou returns a poster URL with invalid percent-encoded
   sequences. Falls back to the raw URL on decode failure.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

快手接口无法使用

1 participant