@finch_ren/x-scraper 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Finch R
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,17 +1,129 @@
1
1
  # x-scraper
2
2
 
3
- `x-scraper` 是一个面向 X/Twitter 内部 GraphQL 接口的 TypeScript SDK。
4
- 重点是让常见场景开箱即用,同时保持类型清晰、便于扩展。
3
+ English | [简体中文](./README.zh-CN.md)
5
4
 
6
- ## 特性
5
+ `x-scraper` is a TypeScript SDK for X/Twitter internal GraphQL endpoints.
6
+ It focuses on practical, ready-to-run usage while keeping strong OpenAPI-generated types.
7
7
 
8
- - 自动 Guest Token 初始化(无需手动配置 token)
9
- - 支持 Cookie 登录态客户端
10
- - 面向常用场景提供开箱即用调用入口(用户、推文、互动等)
8
+ ## Features
11
9
 
12
- ## 快速开始
10
+ - Automatic guest token initialization
11
+ - Cookie-authenticated client support
12
+ - Practical high-level APIs for common user/tweet/interaction flows
13
13
 
14
- ### Guest 模式
14
+ ## Installation
15
+
16
+ <details open>
17
+ <summary><strong>npm</strong></summary>
18
+
19
+ ```bash
20
+ npm install @finch_ren/x-scraper
21
+ ```
22
+
23
+ </details>
24
+
25
+ <details>
26
+ <summary><strong>pnpm</strong></summary>
27
+
28
+ ```bash
29
+ pnpm add @finch_ren/x-scraper
30
+ ```
31
+
32
+ </details>
33
+
34
+ <details>
35
+ <summary><strong>yarn</strong></summary>
36
+
37
+ ```bash
38
+ yarn add @finch_ren/x-scraper
39
+ ```
40
+
41
+ </details>
42
+
43
+ ## Simple Call Example
44
+
45
+ ```ts
46
+ import { XScraper } from '@finch_ren/x-scraper';
47
+
48
+ async function main() {
49
+ const scraper = new XScraper();
50
+ const client = await scraper.getClientFromCookies({
51
+ __cf_bm: '<__cf_bm>',
52
+ __cuid: '<__cuid>',
53
+ _ga: '<_ga>',
54
+ _ga_BLY4P7T5KW: '<_ga_BLY4P7T5KW>',
55
+ _twitter_sess: '<_twitter_sess>',
56
+ auth_token: '<auth_token>',
57
+ ct0: '<ct0>',
58
+ guest_id: '<guest_id>',
59
+ guest_id_ads: '<guest_id_ads>',
60
+ guest_id_marketing: '<guest_id_marketing>',
61
+ kdt: '<kdt>',
62
+ lang: '<lang>',
63
+ personalization_id: '<personalization_id>',
64
+ twid: '<twid>',
65
+ });
66
+
67
+ const res = await client.getTweetDetail({
68
+ focalTweetId: '2018440335140024383',
69
+ });
70
+ }
71
+
72
+ main().catch(console.error);
73
+ ```
74
+
75
+ <details open>
76
+ <summary><strong>Example Response (JSON) (Display only, actual response may vary)</strong></summary>
77
+
78
+ ```json
79
+ {
80
+ "raw": {
81
+ "instruction": [
82
+ { "type": "TimelineClearCache" },
83
+ { "type": "TimelineAddEntries", "entries": [/* ... */] },
84
+ { "type": "TimelineTerminateTimeline" }
85
+ ]
86
+ },
87
+ "cursor": {
88
+ "bottom": {
89
+ "typename": "TimelineTimelineCursor",
90
+ "cursorType": "Bottom",
91
+ "entryType": "TimelineTimelineCursor",
92
+ "value": "DAAKCgABHB6qs_W__pULAAIAAAGoRW1QQzZ3QUFBZlEvZ0dKTjB2R3AvQUFBQUNVY0F2UXhkOXN4dEJ3Qzl4Y3gyNkJ0SEFNbGdrOFhvU3djQXZHZ0hCZWhBeHdDODE5MVd1SGRIQUwzU3c4Ym9UMGNBdlkrcGhyeDBCd0M4VXJZMXFFZEhBTTJhdnlhTVVBY0F2Z24zSnN3TUJ3Qys2aFJHbEdvSEFOYjhqZmFrVjRjQXZtYzBadkF3UndDOE96NDJsRmtIQUwvWUxVV3NkY2NBeEM2dFJ0d1N4d0MrdFY4R3BFYUhBTDdySXNhMGNzY0F2REthRmR3UHh3REEwNnAydEFxSEFOSDA4eWFZV3NjQXhFN3I5c1JTaHdEQVpFSkc4RXFIQUwwNXpmYTBZd2NBdmJ6SHBxeFJod0M5V1BmVzREWkhBTUJ6b3ZhRVl3Y0F2R3Z0TmN4MGh3QzgzM0Myb0V0SEFMOGNBYmJzUDRjQTdxQm1ScUEyQndDK0Y1SzI4QnJIQUx5OFl5YkVaQWNBdjY5THRyeGJSd0RCQ24wVzBGdUhBTDR6TGJiRVBvY0F2UFZqRnRCVWc9PQgAAwAAAAILAAQAAAAGQm90dG9tAAA"
93
+ }
94
+ },
95
+ "data": [
96
+ {
97
+ "raw": { "typename": "Tweet", "restId": "2018440335140024383" },
98
+ "tweet": {
99
+ "id": "2018440335140024383",
100
+ "text": "SpaceX has acquired xAI, forming one of the most ambitious...",
101
+ "createdAt": "Mon Feb 02 21:44:11 +0000 2026",
102
+ "favoriteCount": 44183,
103
+ "retweetCount": 7746,
104
+ "replyCount": 3354
105
+ },
106
+ "user": {
107
+ "id": "34743251",
108
+ "name": "SpaceX",
109
+ "screenName": "SpaceX",
110
+ "followersCount": 41074731
111
+ }
112
+ },
113
+ {
114
+ "raw": { /* ... */ },
115
+ "tweet": { /* ... */ },
116
+ "user": { /* ... */ }
117
+ }
118
+ ]
119
+ }
120
+ ```
121
+
122
+ </details>
123
+
124
+ ## Quick Start
125
+
126
+ ### Guest mode
15
127
 
16
128
  ```ts
17
129
  import { XScraper } from '@finch_ren/x-scraper';
@@ -30,9 +142,9 @@ async function main() {
30
142
  main().catch(console.error);
31
143
  ```
32
144
 
33
- ### Cookie 模式
145
+ ### Cookie mode
34
146
 
35
- 方式 A:浏览器导出的 Cookie 数组
147
+ A) Browser-exported cookie array
36
148
 
37
149
  ```ts
38
150
  import { XScraper } from '@finch_ren/x-scraper';
@@ -41,17 +153,8 @@ async function main() {
41
153
  const scraper = new XScraper();
42
154
 
43
155
  const client = await scraper.getClientFromCookies([
44
- {
45
- domain: '.x.com',
46
- name: 'ct0',
47
- value: '<csrf_token>',
48
- },
49
- {
50
- domain: '.x.com',
51
- name: 'auth_token',
52
- value: '<auth_token>',
53
- },
54
- ...
156
+ { domain: '.x.com', name: 'ct0', value: '<csrf_token>' },
157
+ { domain: '.x.com', name: 'auth_token', value: '<auth_token>' },
55
158
  ]);
56
159
 
57
160
  const profile = await client.getUserByScreenName({ screenName: 'jack' });
@@ -61,7 +164,7 @@ async function main() {
61
164
  main().catch(console.error);
62
165
  ```
63
166
 
64
- 方式 B:对象映射(`name -> value`)
167
+ B) Cookie map (`name -> value`)
65
168
 
66
169
  ```ts
67
170
  import { XScraper } from '@finch_ren/x-scraper';
@@ -70,9 +173,20 @@ async function main() {
70
173
  const scraper = new XScraper();
71
174
 
72
175
  const client = await scraper.getClientFromCookies({
73
- ct0: '<csrf_token>',
176
+ __cf_bm: '<__cf_bm>',
177
+ __cuid: '<__cuid>',
178
+ _ga: '<_ga>',
179
+ _ga_BLY4P7T5KW: '<_ga_BLY4P7T5KW>',
180
+ _twitter_sess: '<_twitter_sess>',
74
181
  auth_token: '<auth_token>',
75
- ....
182
+ ct0: '<ct0>',
183
+ guest_id: '<guest_id>',
184
+ guest_id_ads: '<guest_id_ads>',
185
+ guest_id_marketing: '<guest_id_marketing>',
186
+ kdt: '<kdt>',
187
+ lang: '<lang>',
188
+ personalization_id: '<personalization_id>',
189
+ twid: '<twid>',
76
190
  });
77
191
 
78
192
  const profile = await client.getUserByScreenName({ screenName: 'jack' });
@@ -82,67 +196,35 @@ async function main() {
82
196
  main().catch(console.error);
83
197
  ```
84
198
 
85
- ## 常用 API 入口
86
-
87
- 同一能力通常有两种调用方式:
199
+ ## API Entry Styles
88
200
 
89
- - 顶层快捷方法:`client.getUserByScreenName(...)`
90
- - 分组方法:`client.user.getUserByScreenName(...)`
201
+ Most APIs support both styles:
91
202
 
92
- ### 两种写法对照(等价)
203
+ - Flat shortcut: `client.getUserByScreenName(...)`
204
+ - Grouped API: `client.user.getUserByScreenName(...)`
93
205
 
94
206
  ```ts
95
- // User
96
207
  const userA = await client.getUserByScreenName({ screenName: 'elonmusk' });
97
208
  const userB = await client.user.getUserByScreenName({ screenName: 'elonmusk' });
98
209
 
99
- // Tweet timeline
100
210
  const tweetsA = await client.getUserTweets({ userId: '44196397' });
101
211
  const tweetsB = await client.tweet.getUserTweets({ userId: '44196397' });
102
212
 
103
- // Post actions
104
213
  await client.createTweet({ tweetText: 'hello' });
105
214
  await client.post.postCreateTweet({ tweetText: 'hello' });
106
215
  ```
107
216
 
108
- ### 顶层快捷方法(高频)
217
+ ## Auth and Runtime Notes
109
218
 
110
- - `client.getUserByScreenName(...)`
111
- - `client.getUserTweets(...)`
112
- - `client.getTweetDetail(...)`
113
- - `client.createTweet(...)`
114
- - `client.deleteTweet(...)`
115
- - `client.likeTweet(...)`
116
- - `client.unlikeTweet(...)`
117
- - `client.retweet(...)`
118
- ....
219
+ ### Cookie notes
119
220
 
120
- ### 分组 API(完整入口)
221
+ - You can use the `Cookie-Editor` browser extension to export cookies as JSON and pass it to `getClientFromCookies([...])`
222
+ - Do not commit cookies to git
223
+ - Use local files or environment variables for secret injection
121
224
 
122
- - `client.tweet`
123
- - `client.user`
124
- - `client.users`
125
- - `client.userList`
126
- - `client.post`
127
- - `client.space`
128
- - `client.v11Get`
129
- - `client.v11Post`
130
- - `client.v20Get`
131
- - `client.default`
132
- - `client.initialState`
133
- ....
225
+ ### Header/platform mismatch
134
226
 
135
- ## 认证与环境说明
136
-
137
- ### 1) 关于 Cookie
138
-
139
- - 推荐从已登录浏览器导出 `ct0` / `auth_token`(可选 `gt`)。
140
- - `getClientFromCookies` 支持两种格式:对象映射或浏览器 cookie 数组。
141
- - 不要把 Cookie 写入仓库,建议走本地文件或环境变量注入。
142
-
143
- ### 2) 平台 Header 一致性
144
-
145
- 某些账号 Cookie 与 `sec-ch-ua-platform` 不一致时可能失败,可手动覆盖:
227
+ If cookie origin and `sec-ch-ua-platform` mismatch, override header manually:
146
228
 
147
229
  ```ts
148
230
  import { XScraper } from '@finch_ren/x-scraper';
@@ -153,13 +235,13 @@ scraper.setAdditionalApiHeaders({
153
235
  });
154
236
  ```
155
237
 
156
- ### 3) 风险与限制
238
+ ### Risk notice
157
239
 
158
- - 该库依赖 X 私有接口,接口字段和行为可能随时变化。
159
- - 登录态调用存在账号风控风险,请自行评估并使用低风险账号。
160
- - 可能触发动态限流,建议在业务侧做重试与退避(backoff)。
240
+ - This SDK depends on private endpoints that may change without notice
241
+ - Authenticated calls may trigger account risk controls
242
+ - Add retry + backoff in production
161
243
 
162
- ## 本地开发
244
+ ## Local Development
163
245
 
164
246
  ```bash
165
247
  pnpm install
@@ -167,48 +249,44 @@ pnpm build
167
249
  pnpm test
168
250
  ```
169
251
 
170
- ## 重新生成 OpenAPI 代码
252
+ ## Regenerate OpenAPI Code
171
253
 
172
254
  ```bash
173
255
  pnpm generate
174
256
  ```
175
257
 
176
- ## openapi/placeholder.json 说明
258
+ ## `openapi/placeholder.json`
177
259
 
178
- `openapi/placeholder.json` 是运行时使用的 GraphQL 操作模板表,不是普通示例文件。
179
- SDK 会在请求时读取这里的配置来组装参数与请求上下文。
260
+ `openapi/placeholder.json` is a runtime GraphQL operation template registry.
261
+ It is used by the SDK to build request variables/features/fieldToggles and endpoint metadata.
180
262
 
181
- 每个条目通常包含:
263
+ Typical fields:
182
264
 
183
- - `@path`:接口路径(用于 transaction id 生成等)
184
- - `@method`:HTTP 方法(用于 transaction id 生成等)
185
- - `queryId`:GraphQL queryId
186
- - `variables`:默认变量模板(可被调用参数覆盖)
187
- - `features` / `fieldToggles`:默认开关参数
265
+ - `@path`: endpoint path (used in transaction id generation)
266
+ - `@method`: HTTP method (used in transaction id generation)
267
+ - `queryId`: GraphQL query id
268
+ - `variables`: default variable template
269
+ - `features` / `fieldToggles`: default toggles
188
270
 
189
- 代码关联关系:
271
+ Code linkage:
190
272
 
191
- - `src/api.ts` 会加载该文件作为 `flagData`
192
- - `src/utils/api.ts#getKwargs` 会把 `variables/features/fieldToggles` 转成请求参数
193
- - API utils(如 `client.tweet.*`、`client.user.*`、`client.space.*`)通过 `this.flag[...]` 取对应模板
273
+ - `src/api.ts` loads it as `flagData`
274
+ - `src/utils/api.ts#getKwargs` builds request params from templates
275
+ - API groups (`client.tweet.*`, `client.user.*`, `client.space.*`) read templates via `this.flag[...]`
194
276
 
195
- 注意:
277
+ Notes:
196
278
 
197
- - `client.space.getAudioSpaceById` `client.space.getBroadcastQuery` 依赖该文件条目
198
- - `client.getLiveVideoStreamStatus`(v1.1 接口)不依赖 `placeholder.json`
279
+ - `client.space.getAudioSpaceById` and `client.space.getBroadcastQuery` depend on this file
280
+ - `client.getLiveVideoStreamStatus` (v1.1 endpoint) does not depend on this file
199
281
 
200
- ## 鸣谢
282
+ ## Acknowledgements
201
283
 
202
- 本项目核心代码来源于:
284
+ Core source is based on:
203
285
 
204
286
  - [fa0311/twitter-openapi-typescript](https://github.com/fa0311/twitter-openapi-typescript)
205
287
 
206
- 在上游基础上,本项目做了工程整合与二次封装,包括:
207
-
208
- - 整合 `twitter-openapi` 相关生成内容到当前 SDK 结构
209
- - 提供更直接的调用入口与项目化组织方式
210
-
211
- 另外补充了 Space 相关接口能力(`client.space`):
288
+ This project adds integration and higher-level SDK ergonomics on top of upstream,
289
+ including additional Space APIs:
212
290
 
213
291
  - `getAudioSpaceById`
214
292
  - `getLiveVideoStreamStatus`