@apidojo/x-scraper

中文文档
1.1.0发布于 2026/03/14MITTypeScriptESM + CJS构建来源已验证近 30 天下载 3887

The fastest and cheapest way to scrape tweets from X (Twitter). Wraps the Apify Twitter Scraper Lite actor with a developer-friendly API.

原始使用文档
文档目录33 节
  1. Prerequisites
  2. Installation
  3. CLI Usage
  4. Setup
  5. Commands
  6. Output Options
  7. Global Flags
  8. Quick Start (Library)
  9. Core Methods
  10. execute(input, options?)
  11. search(input, options?)
  12. searchAsync(input, options?)
  13. stream(input, options?)
  14. Convenience Methods
  15. Profiles
  16. Search
  17. Single Tweet & URLs
  18. Conversations
  19. Mentions
  20. Media Filters
  21. Engagement & Filters
  22. Location
  23. Full Response Mode
  24. Async Runs with RunHandle
  25. Error Handling
  26. Tweet Object Shape
  27. API Reference
  28. Constructor
  29. Core Methods
  30. Convenience Methods
  31. RunHandle
  32. Pricing
  33. License

x-scraper

The fastest and cheapest way to scrape tweets from X (Twitter). Battle-tested infrastructure used by tens of thousands of customers including enterprise teams.

Wraps the Apify Twitter Scraper Lite actor with a developer-friendly, class-based API. Every method creates an Apify actor run under the hood.

Prerequisites

Installation

npm install @apidojo/x-scraper

CLI Usage

Install globally to use from the command line:

npm install -g @apidojo/x-scraper

Setup

# Store your Apify token (saved to ~/.x-scraper/config.json)
x-scraper init

# Or pass it per-command
x-scraper profile NASA --token apify_api_xxx

# Or set as environment variable
export APIFY_TOKEN=apify_api_xxx

Commands

# Fetch tweets from a profile
x-scraper profile NASA --sort Latest --max-items 50

# Search by keyword
x-scraper keyword "artificial intelligence" --lang en --sort Latest

# Search by multiple keywords (joined with OR)
x-scraper keywords bitcoin ethereum solana

# Search by hashtag
x-scraper hashtag AI MachineLearning --sort Latest

# Fetch a single tweet by URL
x-scraper url https://x.com/elonmusk/status/1728108619189874825

# Fetch from multiple URLs
x-scraper urls https://x.com/a/status/1 https://x.com/b/status/2

# Tweets from a handle within a date range
x-scraper profile-date-range NASA --since 2024-01-01 --until 2024-06-01

# Tweets near a location
x-scraper location coffee --location "San Francisco" --radius 10mi

# Tweets with minimum engagement
x-scraper engagement bitcoin --min-likes 1000 --min-retweets 100

# Multiple profiles in one run
x-scraper profiles elonmusk naval paulg

# Mentions, media filters, cashtags, verified users, and more
x-scraper mention NASA
x-scraper media NASA
x-scraper images NASA
x-scraper videos NASA
x-scraper cashtag BTC ETH SOL
x-scraper verified cryptocurrency
x-scraper no-retweets elonmusk
x-scraper links TechCrunch
x-scraper conversation 1728108619189874825

# Raw actor input (full control)
x-scraper search --input '{"searchTerms":["from:NASA filter:media"]}'
x-scraper execute --input '{"searchTerms":["test"],"maxItems":10}'

Output Options

# Pretty JSON (default)
x-scraper profile NASA

# Compact JSON (pipe-friendly)
x-scraper profile NASA --json

# JSONL (one object per line)
x-scraper profile NASA --jsonl

# Save to file
x-scraper profile NASA --output tweets.json

# Debug mode (shows internal logs)
x-scraper profile NASA --debug

Global Flags

FlagDescription
--token <token>Apify API token (overrides env/config)
--sort <order>Latest, Top, or "Latest + Top"
--max-items <n>Maximum number of items
--lang <code>Language filter (ISO 639-1)
--timeout <secs>Run timeout in seconds
--output <file>Save output to file
--jsonCompact JSON output
--jsonlJSONL output (one JSON per line)
--debugEnable debug mode

Quick Start (Library)

// ESM
import { XScraper } from '@apidojo/x-scraper';

// CommonJS
const { XScraper } = require('@apidojo/x-scraper');

const scraper = new XScraper({ token: 'apify_api_xxxxxxxxxxxx' });

// Fetch latest tweets from NASA
const tweets = await scraper.getTweetsByProfile('NASA', { sort: 'Latest', maxItems: 50 });
console.log(tweets);

Core Methods

execute(input, options?)

Raw passthrough — pass any valid actor input object directly. Use this when you know exactly what input the actor expects.

const tweets = await scraper.execute({
  searchTerms: ['from:NASA filter:media'],
  sort: 'Latest',
  maxItems: 100,
});

search(input, options?)

Run the scraper synchronously — waits for the run to finish and returns all items. Options like sort, maxItems, and lang are merged into the input automatically.

const tweets = await scraper.search(
  { searchTerms: ['from:NASA'] },
  { sort: 'Latest', maxItems: 50, lang: 'en' }
);

searchAsync(input, options?)

Start a run without waiting. Returns a RunHandle for polling and fetching results later. Use this for large runs that may exceed the sync timeout.

const run = await scraper.searchAsync(
  { searchTerms: ['from:NASA'] },
  { sort: 'Latest' }
);

await run.waitForFinish();
const tweets = await run.getItems();

stream(input, options?)

Run the scraper and stream results as an async iterator. Items are yielded one by one, with auto-pagination.

for await (const tweet of scraper.stream({ searchTerms: ['from:NASA'] })) {
  console.log(tweet.text);
}

Convenience Methods

All convenience methods accept an options object:

OptionTypeDescription
sortstring'Latest', 'Top', or 'Latest + Top'
maxItemsnumberMaximum number of items to return
langstringISO 639-1 language code (e.g. 'en')
timeoutnumberTimeout in seconds (default: 120)
fullResponsebooleanReturn { items, runId, datasetId } instead of just items

Profiles

// Tweets from a single profile
const tweets = await scraper.getTweetsByProfile('NASA', { sort: 'Latest' });

// Tweets from multiple profiles in one run
const tweets = await scraper.getTweetsByMultipleProfiles(
  ['elonmusk', 'naval', 'paulg'],
  { sort: 'Latest' }
);

// Tweets from a handle within a date range
const tweets = await scraper.getTweetsByHandleInDateRange(
  'NASA', '2024-01-01', '2024-06-01',
  { sort: 'Latest' }
);

// Exclude retweets from a handle
const tweets = await scraper.getTweetsExcludingRetweetsByHandle('elonmusk', {
  sort: 'Latest',
});
// Search by keyword
const tweets = await scraper.getTweetsByKeyword('artificial intelligence', {
  lang: 'en',
  sort: 'Latest',
});

// searchTweets is an alias for getTweetsByKeyword
const tweets = await scraper.searchTweets('artificial intelligence');

// Search by multiple keywords (joined with OR)
const tweets = await scraper.getTweetsByKeywords(
  ['bitcoin', 'ethereum', 'solana'],
  { lang: 'en', sort: 'Latest' }
);

// searchTweetsByMultipleKeywords is an alias for getTweetsByKeywords
const tweets = await scraper.searchTweetsByMultipleKeywords(['AI', 'ML', 'deep learning']);

// Search by hashtag
const tweets = await scraper.getTweetsByHashtag(['AI', 'MachineLearning'], {
  sort: 'Latest',
});

// Search by cashtag
const tweets = await scraper.getTweetsByCashtag(['BTC', 'ETH', 'SOL'], {
  lang: 'en',
  sort: 'Latest',
});

Single Tweet & URLs

// Fetch a single tweet by URL
const tweets = await scraper.getTweetByUrl(
  'https://x.com/elonmusk/status/1728108619189874825'
);

// Fetch from multiple URLs (tweets, lists, profiles)
const tweets = await scraper.getTweetsByUrls([
  'https://x.com/elonmusk/status/1728108619189874825',
  'https://twitter.com/i/lists/1234567890',
]);

Conversations

// Fetch replies in a conversation thread
const replies = await scraper.getTweetsByConversationId('1728108619189874825', {
  sort: 'Latest',
});

Mentions

// Tweets mentioning a user
const tweets = await scraper.getTweetsByMention('NASA', { sort: 'Latest' });

Media Filters

// Tweets with any media (images or videos)
const tweets = await scraper.getTweetsWithMediaByHandle('NASA');

// Tweets with images only
const tweets = await scraper.getTweetsWithImagesByHandle('NASA');

// Tweets with videos only
const tweets = await scraper.getTweetsWithVideosByHandle('NASA');

// Tweets with links
const tweets = await scraper.getTweetsWithLinksByHandle('TechCrunch');

Engagement & Filters

// Tweets with minimum engagement
const tweets = await scraper.getTweetsWithMinEngagement('bitcoin', {
  minLikes: 1000,
  minRetweets: 100,
  sort: 'Top',
});

// Tweets from verified users only
const tweets = await scraper.getTweetsByVerifiedUsers('cryptocurrency', {
  sort: 'Top',
});

Location

// Tweets near a location
const tweets = await scraper.getTweetsByLocation('coffee', 'San Francisco', '10mi', {
  sort: 'Latest',
});

Full Response Mode

By default, methods return just the items array. Pass { fullResponse: true } to get run metadata:

const result = await scraper.getTweetsByProfile('NASA', {
  sort: 'Latest',
  fullResponse: true,
});

console.log(result.items);     // Array of tweet objects
console.log(result.runId);     // Apify run ID
console.log(result.datasetId); // Apify dataset ID

Async Runs with RunHandle

For large runs that may take longer than the sync timeout:

const run = await scraper.searchAsync({ searchTerms: ['from:NASA'], sort: 'Latest' });

// Poll until the run finishes
await run.waitForFinish();

// Get all items
const tweets = await run.getItems();

// Or stream items
for await (const tweet of run.stream()) {
  console.log(tweet.text);
}

// Access run metadata
console.log(run.runId);
console.log(run.datasetId);
console.log(run.status);

Error Handling

All errors from Apify are thrown directly. Wrap calls in try/catch:

try {
  const tweets = await scraper.getTweetsByProfile('NASA');
} catch (error) {
  // Apify errors: 401 unauthorized, 404 not found, 429 rate limit, run failures
  console.error('Scraper error:', error.message);
}

The constructor throws immediately if no token is provided:

try {
  const scraper = new XScraper({});
} catch (error) {
  // "APIFY_TOKEN is required. Pass it as: new XScraper({ token: "apify_api_xxx" })"
}

Tweet Object Shape

Each item returned is a tweet object:

{
  "type": "tweet",
  "id": "1728108619189874825",
  "url": "https://x.com/elonmusk/status/1728108619189874825",
  "text": "More than 10 per human on average",
  "retweetCount": 11311,
  "replyCount": 6526,
  "likeCount": 104121,
  "quoteCount": 2915,
  "createdAt": "Fri Nov 24 17:49:36 +0000 2023",
  "lang": "en",
  "isReply": false,
  "isRetweet": false,
  "isQuote": true,
  "author": {
    "userName": "elonmusk",
    "name": "Elon Musk",
    "id": "44196397",
    "followers": 172669889,
    "isVerified": true,
    "isBlueVerified": true
  }
}

API Reference

Constructor

ParameterTypeDefaultDescription
tokenstringrequiredApify API token
timeoutnumber120Default timeout in seconds for sync runs

Core Methods

MethodReturnsDescription
execute(input, options?)Promise<items|FullResponse>Raw input passthrough
search(input, options?)Promise<items|FullResponse>Sync run with option merging
searchAsync(input, options?)Promise<RunHandle>Async run, returns handle
stream(input, options?)AsyncGenerator<tweet>Async iterator over items

Convenience Methods

MethodParametersBuilds Query
getTweetsByProfile(handle, opts?)from:{handle}
getTweetsByHandleInDateRange(handle, since, until, opts?)from:{handle} since:... until:...
getTweetsByHashtag(hashtags, opts?)#tag1 #tag2
getTweetsByKeyword(keyword, opts?){keyword}
searchTweets(keyword, opts?)Alias for getTweetsByKeyword
getTweetsByKeywords(keywords[], opts?)kw1 OR kw2 OR kw3
searchTweetsByMultipleKeywords(keywords[], opts?)Alias for getTweetsByKeywords
getTweetsByConversationId(id, opts?)conversation_id:{id}
getTweetByUrl(url, opts?)startUrls: [url]
getTweetsByUrls(urls[], opts?)startUrls: [...urls]
getTweetsByLocation(query, location, radius, opts?){q} near:"{loc}" within:{r}
getTweetsByMultipleProfiles(handles[], opts?)["from:a","from:b"]
getTweetsByCashtag(cashtags, opts?)$X OR $Y
getTweetsByMention(handle, opts?)@{handle}
getTweetsWithMediaByHandle(handle, opts?)from:{handle} filter:media
getTweetsWithImagesByHandle(handle, opts?)from:{handle} filter:images
getTweetsWithVideosByHandle(handle, opts?)from:{handle} filter:videos
getTweetsWithMinEngagement(query, opts?){q} min_faves:{n} min_retweets:{n}
getTweetsByVerifiedUsers(query, opts?){q} filter:verified
getTweetsExcludingRetweetsByHandle(handle, opts?)from:{handle} -filter:retweets
getTweetsWithLinksByHandle(handle, opts?)from:{handle} filter:links

RunHandle

Property/MethodTypeDescription
runIdstringThe Apify run ID
datasetIdstringThe default dataset ID
statusstringLast known run status
waitForFinish(opts?)Promise<RunHandle>Poll until terminal status
getItems(opts?)Promise<items|FullResponse>Fetch all dataset items
stream()AsyncGenerator<tweet>Async iterator over items

Pricing

This package uses the Apify Twitter Scraper Lite actor with event-based pricing. You only pay for what you use. See the actor pricing page for current rates.

License

MIT

版本与发布记录

@apidojo/x-scraper 共发布 1 个版本,首次发布于 2026/03/14;过去 12 个月发布了 1 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.1.0latest2026/03/147 个月前

关于 @apidojo/x-scraper 的常见问题

@apidojo/x-scraper 是什么?

The fastest and cheapest way to scrape tweets from X (Twitter). Wraps the Apify Twitter Scraper Lite actor with a developer-friendly API.

如何安装 @apidojo/x-scraper?

在项目目录运行 npm install @apidojo/x-scraper,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 x-scraper,可以用 npx x-scraper 直接运行。

@apidojo/x-scraper 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@apidojo/x-scraper 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@apidojo/x-scraper 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@apidojo/x-scraper 可以商用吗?

@apidojo/x-scraper 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@apidojo/x-scraper 的下载量有多少?

根据 npm 官方下载统计,@apidojo/x-scraper 在 2026/10/06 – 2026/11/04 这 30 天内被下载 3,887 次,日均约 130 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@apidojo/x-scraper 还在维护吗?

最新版本 1.1.0 发布于 2026/03/14(7 个月前);至今共发布 1 个版本,其中过去 12 个月发布了 1 个;首次发布于 2026/03/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。