# Xueqiu Scraper (`crawlerbros/xueqiu-scraper`) Actor

Scrape Xueqiu (xueqiu.com) - China's largest investor community. Hot stocks, real-time quotes + K-line history via the v5 API, and stock/discussion search - after a browser warm-up that clears Xueqiu's JS challenge. No login required.

- **URL**: https://apify.com/crawlerbros/xueqiu-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, News, Integrations
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Xueqiu Scraper

Scrape Xueqiu (`xueqiu.com`) — China's largest investor community. Hot stocks by popularity, real-time quotes + daily K-line history via the public v5 API, and keyword search across stocks and community discussions. A real browser warms up first to clear Xueqiu's JS challenge — no login required.

### What this actor does

- **Three modes:** `hotStocks` (default), `byStock`, `search`
- **Hot stocks** — `stock.xueqiu.com/v5/stock/hot_stock/list.json` (全球 / 沪深 / 港股 / 美股 tabs) with rank, popularity score, rank movement, price, change %
- **Quotes** — `v5/stock/quote.json` with 30+ fields: price, change %, open/high/low, volume, amount, turnover rate, volume ratio, PE (TTM/LYR/forecast), PB, EPS, dividend yield, 52-week highs/lows, market caps, limit up/down
- **K-line history** — `v5/stock/chart/kline.json`, candles (day/week/month) with date, open/high/low/close, volume
- **Search** — the `/k?q=` page: stock table (name/code/price/change %/volume/market cap) + community discussions (author, title, content preview, likes/comments/shares, post URL)
- **Warm-up:** navigates the homepage in Chromium so the WAF JS challenge sets the `xq_a_token` cookies, then reuses the session for the APIs — no captcha solving, no login
- **Typed error records** for invalid symbols
- Empty fields are omitted (`strip_nulls` before every push)

### Output fields

**Stock records** (`recordType: "stock"`): `symbol`, `stockCode`, `stockName`, `price`, `change`, `changePct`, `open`, `high`, `low`, `prevClose`, `volume`, `amount`, `turnoverRate`, `volumeRatio`, `marketCap`, `floatMarketCap`, `peTtm`, `peLyr`, `peForecast`, `pbRatio`, `eps`, `dividendYield`, `avgPrice`, `amplitude`, `ytdChangePct`, `high52w`, `low52w`, `limitUp`, `limitDown`, `lotSize`, `totalShares`, `floatShares`, `updateTime`, `currency`, `exchange`, `securityStatus`, `issueDate`, `delayed`, `navps`, `tickSize`, `pledgeRatio`, `priceExtended`, `timestampExtended`, `volumeExtended`, `amountExtended` (quote details), `hotRank` (hot lists — the item's position in the board), `popularityScore`, `scoreChange`, `rankChange` (hot lists), `industry` (search matches), `sourceUrl`

**K-line records** (`recordType: "kline"`): `klineDate`, `open`, `high`, `low`, `close`, `volume`, plus `symbol`, `stockCode`, `stockName`, `sourceUrl`

**Discussion records** (`recordType: "discussion"`): `author`, `publishTime`, `postSource`, `postTitle` (omitted for title-less posts), `postContent`, `likesCount`, `commentsCount`, `sharesCount`, `postUrl`, `sourceUrl`

**Error records** (`recordType: "error"`): `input`, `message`

All data records carry `recordType`, `scrapedAt`, `sourceUrl`; error records are diagnostics (`input`, `message`) without a `sourceUrl`.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | select | `hotStocks` | `hotStocks` / `byStock` / `search` |
| `hotListType` | select | `10` | `10` 全球 hot, `12` 沪深 hot, `13` 港股 hot, `11` 美股 hot |
| `stockSymbols` | array | `["SH600519"]` | `SH600519`, `SZ000001`, `600519`, `1.600519` |
| `includeKline` | bool | `true` | Emit K-line candles with quotes |
| `klineDays` | int (1–500) | `60` | Candles per stock |
| `klinePeriod` | select | `day` | `day` / `week` / `month` candle granularity |
| `searchQuery` | text | `茅台` | Search keyword |
| `minPrice` / `maxPrice` | number (0–100000) | – | Price filter |
| `minChangePct` / `maxChangePct` | number (−100–100) | – | Change % filter |
| `containsKeyword` | text | – | Substring on stock name / post title / author / content |
| `maxItems` | int (1–500) | `50` | Hard cap |

#### Examples

```json
{ "mode": "hotStocks", "hotListType": "10", "maxItems": 20 }
{ "mode": "byStock", "stockSymbols": ["600519", "SZ000001", "1.300750"], "includeKline": true, "klineDays": 30 }
{ "mode": "search", "searchQuery": "比亚迪", "maxItems": 30 }
```

### Data source

Xueqiu's public v5 JSON APIs (`stock.xueqiu.com/v5/...`) plus the server-rendered `/k` search page. The APIs reject cookie-less requests with `400016` and the quote pages show a slider captcha to plain clients, so the actor performs a browser warm-up on the homepage first — this satisfies the JS challenge and sets the `xq_a_token` cookies with zero user interaction. After warm-up, `byStock` and `hotStocks` need no further browsing (fast API-only mode).

### Limitations

- User profile pages (`/u/<id>`) were historically captcha-gated; **Cycle-2 QA re-verified this on Apify cloud (2026-08-05): the slider captcha no longer fires** after the homepage warm-up — profile pages render normally. However the user timeline API (`/statuses/original/timeline.json`) still returns non-200 without a login, and the profile DOM needs field-level mapping, so a `byUser` mode is not yet exposed. The diagnostic `_probeByUser` input (see input schema) reports captcha/render/timeline state on demand. Documented as in-progress.
- The `/S/<symbol>` quote page itself shows a slider captcha to fresh sessions; quotes are instead fetched from the v5 API, which works with the warm-up cookies.
- Search results are capped at the first page (the `综合` tab: top stock match + discussion stream).
- On some datacenter IPs the rendered search page omits the A-share stock table (geo-variant markup shows only HK/ADR rows); the actor then falls back to the `query/v1/search/web/stock.json` API through the warm-up session to recover the A-share match (symbol, name, price, change %, industry). Verified working from Apify cloud on 2026-08-05.
- The stock screener (`v5/stock/screener/quote/list.json`) and financial statements (`v5/stock/finance/*`) work with the same warm-up cookies but are not yet exposed as modes — noted as a future expansion axis.
- Xueqiu data is CN-market only; symbols use `SH`/`SZ`/`BJ` prefixes.

### Use cases

- A-share hot-stock monitoring (daily sentiment)
- Quote snapshots + historical series for research
- Community sentiment tracking via discussion search
- CN investor-community content pipelines

### FAQ

**Why does it need a browser?** Xueqiu's WAF serves a JS challenge (and slider captchas on some pages) to plain HTTP clients. The actor launches headless Chromium, lets the challenge resolve on the homepage, then uses the browser session's cookies for the APIs. This works fully automatically — no captcha solving service, no login.

**What do `likesCount`/`commentsCount` mean?** The discussion cards show 赞/评论/转发 counts — mapped to likes, comments and shares respectively.

**What is a `symbol`?** Xueqiu's market-qualified code: `SH600519` (Shanghai), `SZ000001` (Shenzhen), `BJ...` (Beijing). The actor normalizes bare codes and `market.code` forms automatically.

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

## `hotListType` (type: `string`):

Which hot-stock ranking to fetch (tabs on the Xueqiu hot board).

## `stockSymbols` (type: `array`):

Symbols in any form: `SH600519`, `SZ000001`, `600519`, `1.600519`. Auto-market detection for bare 6-digit codes.

## `includeKline` (type: `boolean`):

Emit daily K-line candles alongside the quote (mode=byStock).

## `klineDays` (type: `integer`):

How many daily candles to emit per stock.

## `klinePeriod` (type: `string`):

Candle granularity for the history.

## `searchQuery` (type: `string`):

Free-text keyword, e.g. `茅台`, `新能源`, `比亚迪`.

## `minPrice` (type: `number`):

Drop stock records priced below this.

## `maxPrice` (type: `number`):

Drop stock records priced above this.

## `minChangePct` (type: `number`):

Drop records with changePct below this.

## `maxChangePct` (type: `number`):

Drop records with changePct above this.

## `containsKeyword` (type: `string`):

Only emit records whose stock name or post title contains this substring.

## `maxItems` (type: `integer`):

Hard cap on emitted records.

## `_probeByUser` (type: `boolean`):

Diagnostic-only: navigate a profile page and report whether the slider captcha blocks it. Not part of the normal API.

## `_probeUserId` (type: `string`):

Diagnostic-only user id for \_probeByUser.

## Actor input object example

```json
{
  "mode": "hotStocks",
  "hotListType": "10",
  "stockSymbols": [
    "SH600519"
  ],
  "includeKline": true,
  "klineDays": 60,
  "klinePeriod": "day",
  "searchQuery": "茅台",
  "maxItems": 50,
  "_probeByUser": false,
  "_probeUserId": "7535494092"
}
```

# Actor output Schema

## `stocks` (type: `string`):

Dataset containing all scraped Xueqiu quotes, K-line candles and discussions.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "hotStocks",
    "hotListType": "10",
    "stockSymbols": [
        "SH600519"
    ],
    "includeKline": true,
    "klineDays": 60,
    "klinePeriod": "day",
    "searchQuery": "茅台",
    "maxItems": 50,
    "_probeByUser": false,
    "_probeUserId": "7535494092"
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/xueqiu-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "hotStocks",
    "hotListType": "10",
    "stockSymbols": ["SH600519"],
    "includeKline": True,
    "klineDays": 60,
    "klinePeriod": "day",
    "searchQuery": "茅台",
    "maxItems": 50,
    "_probeByUser": False,
    "_probeUserId": "7535494092",
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/xueqiu-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "hotStocks",
  "hotListType": "10",
  "stockSymbols": [
    "SH600519"
  ],
  "includeKline": true,
  "klineDays": 60,
  "klinePeriod": "day",
  "searchQuery": "茅台",
  "maxItems": 50,
  "_probeByUser": false,
  "_probeUserId": "7535494092"
}' |
apify call crawlerbros/xueqiu-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/xueqiu-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/qPNJflk3ZHzesqjdr/builds/GqChGZF0rI2ytidJM/openapi.json
