Scweet 5.2__tar.gz → 5.3__tar.gz
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.
- {scweet-5.2 → scweet-5.3}/CHANGELOG.md +15 -0
- {scweet-5.2 → scweet-5.3}/DOCUMENTATION.md +19 -9
- scweet-5.3/PKG-INFO +314 -0
- scweet-5.3/README.md +273 -0
- {scweet-5.2 → scweet-5.3}/Scweet/__version__.py +1 -1
- {scweet-5.2 → scweet-5.3}/Scweet/cli.py +3 -0
- {scweet-5.2 → scweet-5.3}/Scweet/client.py +8 -0
- scweet-5.3/Scweet.egg-info/PKG-INFO +314 -0
- scweet-5.2/PKG-INFO +0 -210
- scweet-5.2/README.md +0 -169
- scweet-5.2/Scweet.egg-info/PKG-INFO +0 -210
- {scweet-5.2 → scweet-5.3}/LICENSE.txt +0 -0
- {scweet-5.2 → scweet-5.3}/MANIFEST.in +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/__init__.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/__main__.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/account_session.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/api_engine.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/async_tools.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/auth.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/config.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/cooldown.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/db.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/default_manifest.json +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/exceptions.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/http_utils.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/limiter.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/logging_config.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/manifest.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/models.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/outputs.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/query.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/queue.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/repos.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/resume.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/runner.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/scheduler.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/schema.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/storage.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/transaction.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/user_identity.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet/utils.py +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet.egg-info/SOURCES.txt +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet.egg-info/dependency_links.txt +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet.egg-info/entry_points.txt +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet.egg-info/requires.txt +0 -0
- {scweet-5.2 → scweet-5.3}/Scweet.egg-info/top_level.txt +0 -0
- {scweet-5.2 → scweet-5.3}/pyproject.toml +0 -0
- {scweet-5.2 → scweet-5.3}/requirements.txt +0 -0
- {scweet-5.2 → scweet-5.3}/setup.cfg +0 -0
- {scweet-5.2 → scweet-5.3}/setup.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_accounts_repo.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_api_engine.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_auth.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_cli.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_client.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_config.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_cooldown.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_db.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_env_loaders.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_follows.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_integration.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_manifest.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_outputs.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_query.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_resume.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_runner.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_schema.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_session_builder.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_transaction.py +0 -0
- {scweet-5.2 → scweet-5.3}/tests/test_utils.py +0 -0
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [5.3.0] - 2026-04-14
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`manifest_scrape_on_init=` constructor shorthand** — pass `manifest_scrape_on_init=True` directly to `Scweet()` without needing `ScweetConfig`. Overrides the config value (same pattern as `proxy=`).
|
|
10
|
+
- **`--manifest-scrape-on-init` CLI flag** — scrape fresh GraphQL query IDs from X's `main.js` bundle on startup from the command line.
|
|
11
|
+
- **`save_name=` parameter** on `search`, `get_profile_tweets`, `get_followers`, `get_following`, and `get_user_info` — set a custom base filename for saved output (without extension).
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Documentation now marks `ct0` as optional in cookies examples — Scweet bootstraps it automatically from `auth_token`.
|
|
16
|
+
- Manifest scrape docs updated to reflect the new top-level constructor arg and CLI flag.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
5
20
|
## [5.2.0] - 2026-04-03
|
|
6
21
|
|
|
7
22
|
### Added
|
|
@@ -30,11 +30,13 @@ Create a `cookies.json` file:
|
|
|
30
30
|
[
|
|
31
31
|
{
|
|
32
32
|
"username": "your_account",
|
|
33
|
-
"cookies": { "auth_token": "..."
|
|
33
|
+
"cookies": { "auth_token": "..." }
|
|
34
34
|
}
|
|
35
35
|
]
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
`ct0` is optional — Scweet bootstraps it automatically from `auth_token`. You can include it if you have it:
|
|
39
|
+
|
|
38
40
|
```python
|
|
39
41
|
s = Scweet(cookies_file="cookies.json")
|
|
40
42
|
```
|
|
@@ -43,8 +45,8 @@ For multiple accounts with per-account proxies (enables concurrent scraping and
|
|
|
43
45
|
|
|
44
46
|
```json
|
|
45
47
|
[
|
|
46
|
-
{ "username": "account1", "cookies": { "auth_token": "..."
|
|
47
|
-
{ "username": "account2", "cookies": { "auth_token": "..."
|
|
48
|
+
{ "username": "account1", "cookies": { "auth_token": "..." }, "proxy": "http://user1:pass1@host1:port1" },
|
|
49
|
+
{ "username": "account2", "cookies": { "auth_token": "..." }, "proxy": "http://user2:pass2@host2:port2" }
|
|
48
50
|
]
|
|
49
51
|
```
|
|
50
52
|
|
|
@@ -211,6 +213,7 @@ tweets = s.search(
|
|
|
211
213
|
| `resume` | `bool` | `False` | Resume from last checkpoint |
|
|
212
214
|
| `save` | `bool` | `False` | Save results to disk |
|
|
213
215
|
| `save_format` | `str` | config value | `"csv"`, `"json"`, or `"both"` |
|
|
216
|
+
| `save_name` | `str` | auto-generated | Base filename for saved output (without extension) |
|
|
214
217
|
|
|
215
218
|
### Async variant
|
|
216
219
|
|
|
@@ -245,6 +248,7 @@ tweets = s.get_profile_tweets(
|
|
|
245
248
|
| `resume` | `bool` | `False` | Resume from last checkpoint |
|
|
246
249
|
| `save` | `bool` | `False` | Save results to disk |
|
|
247
250
|
| `save_format` | `str` | config value | `"csv"`, `"json"`, or `"both"` |
|
|
251
|
+
| `save_name` | `str` | auto-generated | Base filename for saved output (without extension) |
|
|
248
252
|
|
|
249
253
|
Async: `await s.aget_profile_tweets(["elonmusk"], limit=100)`
|
|
250
254
|
|
|
@@ -269,6 +273,7 @@ users = s.get_following(["OpenAI"], limit=500)
|
|
|
269
273
|
| `raw_json` | `bool` | `False` | Include full Twitter user payload under `raw` key |
|
|
270
274
|
| `save` | `bool` | `False` | Save results to disk |
|
|
271
275
|
| `save_format` | `str` | config value | `"csv"`, `"json"`, or `"both"` |
|
|
276
|
+
| `save_name` | `str` | auto-generated | Base filename for saved output (without extension) |
|
|
272
277
|
|
|
273
278
|
### raw_json option
|
|
274
279
|
|
|
@@ -297,6 +302,7 @@ profiles = s.get_user_info(["elonmusk", "OpenAI"])
|
|
|
297
302
|
| `users` | `list[str]` | *required* | Usernames or profile URLs |
|
|
298
303
|
| `save` | `bool` | `False` | Save results to disk |
|
|
299
304
|
| `save_format` | `str` | config value | `"csv"`, `"json"`, or `"both"` |
|
|
305
|
+
| `save_name` | `str` | auto-generated | Base filename for saved output (without extension) |
|
|
300
306
|
|
|
301
307
|
Async: `await s.aget_user_info(["elonmusk"])`
|
|
302
308
|
|
|
@@ -485,14 +491,17 @@ s = Scweet(
|
|
|
485
491
|
Twitter/X rotates GraphQL query IDs periodically. When IDs go stale, requests return 404. Scweet ships with default IDs that work at release time, but you can auto-fetch fresh ones:
|
|
486
492
|
|
|
487
493
|
```python
|
|
488
|
-
s = Scweet(
|
|
489
|
-
cookies_file="cookies.json",
|
|
490
|
-
config=ScweetConfig(manifest_scrape_on_init=True),
|
|
491
|
-
)
|
|
494
|
+
s = Scweet(cookies_file="cookies.json", manifest_scrape_on_init=True)
|
|
492
495
|
```
|
|
493
496
|
|
|
494
497
|
This fetches the current `main.js` bundle from X on init and extracts the latest query IDs. It adds a few seconds to startup but ensures your requests use current IDs.
|
|
495
498
|
|
|
499
|
+
From the CLI:
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
scweet --auth-token TOKEN --manifest-scrape-on-init search "query" --limit 100
|
|
503
|
+
```
|
|
504
|
+
|
|
496
505
|
---
|
|
497
506
|
|
|
498
507
|
## Account Management (ScweetDB)
|
|
@@ -629,7 +638,7 @@ The sync methods (`search`, `get_followers`, etc.) wrap their async counterparts
|
|
|
629
638
|
|
|
630
639
|
## Error Handling
|
|
631
640
|
|
|
632
|
-
All Scweet methods raise exceptions on failure
|
|
641
|
+
All Scweet methods raise exceptions on failure. Wrap calls in try/except to handle errors explicitly:
|
|
633
642
|
|
|
634
643
|
```python
|
|
635
644
|
from Scweet import Scweet, AccountPoolExhausted, RateLimitError, AuthError, NetworkError, RunFailed
|
|
@@ -699,7 +708,7 @@ from Scweet import (
|
|
|
699
708
|
|
|
700
709
|
**`RunFailed` / `NetworkError`**
|
|
701
710
|
- Check your internet connection and proxy configuration
|
|
702
|
-
- X may have rotated GraphQL query IDs —
|
|
711
|
+
- X may have rotated GraphQL query IDs — pass `manifest_scrape_on_init=True` to `Scweet()` (or `--manifest-scrape-on-init` in the CLI) to auto-fetch fresh ones
|
|
703
712
|
- 404 errors in logs mean stale query IDs (transient) — not bad auth
|
|
704
713
|
|
|
705
714
|
---
|
|
@@ -731,6 +740,7 @@ scweet [auth options] [config options] <subcommand> [subcommand options]
|
|
|
731
740
|
|------|-------------|
|
|
732
741
|
| `--proxy PROXY` | Proxy URL or JSON string |
|
|
733
742
|
| `--concurrency N` | Worker concurrency (default: `5`) |
|
|
743
|
+
| `--manifest-scrape-on-init` | Scrape fresh query IDs from X's main.js on startup |
|
|
734
744
|
|
|
735
745
|
### Output options
|
|
736
746
|
|
scweet-5.3/PKG-INFO
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: Scweet
|
|
3
|
+
Version: 5.3
|
|
4
|
+
Summary: Scrape tweets, profiles, followers and more from Twitter/X — no API key needed
|
|
5
|
+
Home-page: https://github.com/Altimis/Scweet
|
|
6
|
+
Download-URL: https://github.com/Altimis/Scweet/archive/v5.3.tar.gz
|
|
7
|
+
Author: Yassine AIT JEDDI
|
|
8
|
+
Author-email: aitjeddiyassine@gmail.com
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: twitter,x,scraper,twitter-scraper,x-scraper,tweets,tweet-search,twitter-search,followers,following,twitter-api-alternative,graphql,web-scraping,social-media,data-collection,python
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: python-dotenv
|
|
24
|
+
Requires-Dist: sqlmodel>=0.0.22
|
|
25
|
+
Requires-Dist: SQLAlchemy>=2.0
|
|
26
|
+
Requires-Dist: curl_cffi
|
|
27
|
+
Requires-Dist: XClientTransaction>=1.0.2
|
|
28
|
+
Requires-Dist: pydantic>=2.0
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: download-url
|
|
35
|
+
Dynamic: home-page
|
|
36
|
+
Dynamic: keywords
|
|
37
|
+
Dynamic: license
|
|
38
|
+
Dynamic: requires-dist
|
|
39
|
+
Dynamic: requires-python
|
|
40
|
+
Dynamic: summary
|
|
41
|
+
|
|
42
|
+
<h1 align="center">Scweet</h1>
|
|
43
|
+
|
|
44
|
+
<p align="center">
|
|
45
|
+
<strong>Scrape Twitter / X without the official API.</strong>
|
|
46
|
+
<br>
|
|
47
|
+
Hosted on Apify, or run locally with Python and CLI.
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
<p align="center">
|
|
51
|
+
<a href="https://apify.com/altimis/scweet?fpr=a40q9">
|
|
52
|
+
<img alt="Run on Apify" src="https://img.shields.io/badge/Run%20on-Apify-246DFF?logo=apify&logoColor=white">
|
|
53
|
+
</a>
|
|
54
|
+
<a href="#python-quickstart">
|
|
55
|
+
<img alt="Python Quickstart" src="https://img.shields.io/badge/Python-Quickstart-3776AB?logo=python&logoColor=white">
|
|
56
|
+
</a>
|
|
57
|
+
<a href="#cli">
|
|
58
|
+
<img alt="CLI Quickstart" src="https://img.shields.io/badge/CLI-Quickstart-111111?logo=gnu-bash&logoColor=white">
|
|
59
|
+
</a>
|
|
60
|
+
<a href="#documentation">
|
|
61
|
+
<img alt="Documentation" src="https://img.shields.io/badge/Docs-Full%20Reference-0A66C2">
|
|
62
|
+
</a>
|
|
63
|
+
</p>
|
|
64
|
+
|
|
65
|
+
<p align="center">
|
|
66
|
+
<a href="https://github.com/Altimis/Scweet/actions/workflows/tests.yml">
|
|
67
|
+
<img alt="Tests" src="https://github.com/Altimis/Scweet/actions/workflows/tests.yml/badge.svg">
|
|
68
|
+
</a>
|
|
69
|
+
<a href="https://pypi.org/project/scweet/">
|
|
70
|
+
<img alt="PyPI Version" src="https://img.shields.io/pypi/v/scweet.svg">
|
|
71
|
+
</a>
|
|
72
|
+
<a href="https://pepy.tech/projects/scweet">
|
|
73
|
+
<img alt="PyPI Downloads" src="https://static.pepy.tech/badge/scweet/month">
|
|
74
|
+
</a>
|
|
75
|
+
<a href="https://github.com/Altimis/scweet/blob/main/LICENSE">
|
|
76
|
+
<img alt="License" src="https://img.shields.io/github/license/Altimis/scweet">
|
|
77
|
+
</a>
|
|
78
|
+
<a href="https://apify.com/altimis/scweet">
|
|
79
|
+
<img alt="Scweet Actor Status" src="https://apify.com/actor-badge?actor=altimis/scweet">
|
|
80
|
+
</a>
|
|
81
|
+
</p>
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
<p align="center">
|
|
86
|
+
<strong>Scrape tweets, profiles, followers and more from Twitter/X. Uses X's own web GraphQL API, authenticated with your browser cookies. No official API key or developer account needed.<strong>
|
|
87
|
+
</p>
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
**What you can scrape:**
|
|
92
|
+
- [**Tweets**](DOCUMENTATION.md#search-api) — by keyword, hashtag, user, date range, engagement filters, language, location
|
|
93
|
+
- [**Profile timelines**](DOCUMENTATION.md#profile-tweets) — a user's full tweet history
|
|
94
|
+
- [**Followers / Following**](DOCUMENTATION.md#followers--following) — full account lists at scale
|
|
95
|
+
- [**User profiles**](DOCUMENTATION.md#user-info) — bio, follower count, verification status, and more
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Hosted — no setup needed
|
|
100
|
+
|
|
101
|
+
> [Run Scweet on Apify](https://apify.com/altimis/scweet?fpr=a40q9&fp_sid=jeb97) with no code, no cookies, and no account management. Free tier included.
|
|
102
|
+
|
|
103
|
+
> Running Scweet locally at any real volume usually means dedicated accounts and proxies. You can use a single proxy, a rotating proxy, or assign one per account. If you need a provider, [Webshare](https://www.webshare.io/?referral_code=kdgjcc09945q) works well. Disclosure: affiliate link.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Quickstart
|
|
108
|
+
|
|
109
|
+
**1. Install**
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pip install -U Scweet
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**2. Get your `auth_token`**
|
|
116
|
+
|
|
117
|
+
Log into [x.com](https://x.com) → DevTools `F12` → **Application** → **Cookies** → `https://x.com` → copy the `auth_token` value.
|
|
118
|
+
|
|
119
|
+
Scweet auto-bootstraps the `ct0` CSRF token from `auth_token` alone — or use the [`cookies.json` format](#multiple-accounts--proxies) for multiple accounts at once.
|
|
120
|
+
|
|
121
|
+
**3. Scrape**
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from Scweet import Scweet
|
|
125
|
+
|
|
126
|
+
# Credentials are stored in scweet_state.db automatically on first run
|
|
127
|
+
s = Scweet(auth_token="YOUR_AUTH_TOKEN", proxy="http://user:pass@host:port")
|
|
128
|
+
|
|
129
|
+
# Search tweets — save to CSV (save_format="json" or "both" also works)
|
|
130
|
+
tweets = s.search("bitcoin", since="2025-01-01", limit=500, save=True)
|
|
131
|
+
|
|
132
|
+
# Reuse provisioned accounts on subsequent runs — no credentials needed
|
|
133
|
+
s = Scweet(db_path="scweet_state.db")
|
|
134
|
+
tweets = s.search("ethereum", limit=500, save=True)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
> Always set `limit` — without it, scraping continues until your account's daily cap is hit.
|
|
138
|
+
|
|
139
|
+
> All methods have async variants: `asearch()`, `aget_profile_tweets()`, `aget_followers()`, etc.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Common tasks
|
|
144
|
+
|
|
145
|
+
### Search tweets
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
tweets = s.search(
|
|
149
|
+
"AI agents",
|
|
150
|
+
since="2026-01-01",
|
|
151
|
+
from_users=["elonmusk"],
|
|
152
|
+
min_likes=50,
|
|
153
|
+
limit=200,
|
|
154
|
+
save=True,
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Profile timeline
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
tweets = s.get_profile_tweets(["elonmusk"], limit=200)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Followers / Following
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
followers = s.get_followers(["elonmusk"], limit=1000)
|
|
168
|
+
following = s.get_following(["elonmusk"], limit=1000)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### User profiles
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
profiles = s.get_user_info(["githubstatus", "elonmusk"])
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
For the full list of supported search operators, see [twitter-advanced-search](https://github.com/igorbrigadir/twitter-advanced-search).
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## CLI
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Search with proxy, save to CSV
|
|
185
|
+
scweet --auth-token YOUR_AUTH_TOKEN --proxy http://user:pass@host:port \
|
|
186
|
+
search "bitcoin" --since 2025-01-01 --limit 500 --save
|
|
187
|
+
|
|
188
|
+
# Followers, saved as JSON
|
|
189
|
+
scweet --auth-token YOUR_AUTH_TOKEN \
|
|
190
|
+
followers elonmusk --limit 1000 --save --save-format json
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
For multi-account runs, use `--cookies-file cookies.json`.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Multiple accounts & proxies
|
|
198
|
+
|
|
199
|
+
For higher throughput and reduced ban risk, use multiple dedicated accounts with per-account proxies.
|
|
200
|
+
|
|
201
|
+
**`cookies.json` format:**
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
[
|
|
205
|
+
{ "username": "acct1", "cookies": { "auth_token": "..." }, "proxy": "http://user1:pass1@host1:port1" },
|
|
206
|
+
{ "username": "acct2", "cookies": { "auth_token": "..." }, "proxy": "http://user2:pass2@host2:port2" }
|
|
207
|
+
]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
s = Scweet(cookies_file="cookies.json") # proxies are read from the file, one per account
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
> **Never use your personal Twitter/X account for scraping.** Use dedicated accounts only.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Why Scweet?
|
|
219
|
+
|
|
220
|
+
| | twint | snscrape | twscrape | **Scweet** |
|
|
221
|
+
|---|---|---|---|---|
|
|
222
|
+
| **Works in 2026** | ❌ unmaintained | ❌ broken | ✅ | ✅ |
|
|
223
|
+
| Cookie / token auth | ❌ | ❌ | ✅ | ✅ |
|
|
224
|
+
| Multi-account pooling | ❌ | ❌ | ✅ | ✅ |
|
|
225
|
+
| Proxy support | ❌ | ❌ | ✅ | ✅ |
|
|
226
|
+
| Resume interrupted scrapes | ❌ | ❌ | ❌ | ✅ |
|
|
227
|
+
| Built-in CSV / JSON output | ✅ | ✅ | ❌ | ✅ |
|
|
228
|
+
| Sync + async API | ❌ | ❌ | Async only | ✅ both |
|
|
229
|
+
| Hosted, no-setup option | ❌ | ❌ | ❌ | ✅ Apify |
|
|
230
|
+
| Active maintenance | ❌ | ❌ | ⚠️ | ✅ |
|
|
231
|
+
|
|
232
|
+
[twint](https://github.com/twintproject/twint) has been unmaintained since 2023. [snscrape](https://github.com/JustAnotherArchivist/snscrape) broke after X's backend changes. [twscrape](https://github.com/vladkens/twscrape) is the closest active alternative — worth knowing, but async-only, no built-in file output, and no resume support.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Limitations
|
|
237
|
+
|
|
238
|
+
- Only publicly visible content is accessible — private/protected accounts are not supported
|
|
239
|
+
- Relies on undocumented X web endpoints; breakage is always possible after platform changes. Scweet can self-heal by scraping fresh query IDs and feature flags from X's `main.js` bundle at startup — pass `manifest_scrape_on_init=True` to enable:
|
|
240
|
+
```python
|
|
241
|
+
s = Scweet(auth_token="...", manifest_scrape_on_init=True)
|
|
242
|
+
```
|
|
243
|
+
- Cookies can expire and may need periodic refreshing
|
|
244
|
+
- A single account typically handles hundreds to a few thousand tweets per day before hitting rate limits; multi-account pooling scales proportionally
|
|
245
|
+
- Proxies and dedicated accounts are strongly recommended for anything beyond light testing
|
|
246
|
+
- Username/password login is not supported. X's anti-automation defenses make programmatic login unreliable and likely to trigger account locks. Scweet authenticates with browser cookies (`auth_token`) extracted from an active session instead
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Documentation
|
|
251
|
+
|
|
252
|
+
Full API reference, config options, structured search filters, async patterns, resume, proxies, and troubleshooting:
|
|
253
|
+
|
|
254
|
+
- [Account setup](DOCUMENTATION.md#account-setup)
|
|
255
|
+
- [Search API](DOCUMENTATION.md#search-api)
|
|
256
|
+
- [Profile tweets](DOCUMENTATION.md#profile-tweets)
|
|
257
|
+
- [Followers / Following](DOCUMENTATION.md#followers--following)
|
|
258
|
+
- [User info](DOCUMENTATION.md#user-info)
|
|
259
|
+
- [Saving results](DOCUMENTATION.md#saving-results)
|
|
260
|
+
- [Resume interrupted searches](DOCUMENTATION.md#resume-interrupted-searches)
|
|
261
|
+
- [Controlling limits](DOCUMENTATION.md#controlling-limits)
|
|
262
|
+
- [Configuration reference](DOCUMENTATION.md#configuration-reference)
|
|
263
|
+
- [Account management (ScweetDB)](DOCUMENTATION.md#account-management-scweetdb)
|
|
264
|
+
- [Async usage](DOCUMENTATION.md#async-usage)
|
|
265
|
+
- [Error handling](DOCUMENTATION.md#error-handling)
|
|
266
|
+
- [CLI reference](DOCUMENTATION.md#cli)
|
|
267
|
+
|
|
268
|
+
For advanced Twitter search operators, see [twitter-advanced-search](https://github.com/igorbrigadir/twitter-advanced-search).
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
<details>
|
|
273
|
+
<summary><strong>FAQ</strong></summary>
|
|
274
|
+
|
|
275
|
+
<br>
|
|
276
|
+
|
|
277
|
+
**Does it work without an official Twitter API key?**
|
|
278
|
+
Yes. Scweet calls X's internal GraphQL API — the same one the web app uses. No developer account or API key required.
|
|
279
|
+
|
|
280
|
+
**Is it a replacement for twint or snscrape?**
|
|
281
|
+
Yes. Both are broken as of 2024–2025. Scweet uses a different, currently-working approach: cookies + GraphQL instead of legacy unauthenticated endpoints.
|
|
282
|
+
|
|
283
|
+
**How many tweets can I scrape?**
|
|
284
|
+
A single account typically handles hundreds to a few thousand tweets per day before hitting rate limits. Multi-account pooling scales this proportionally. The hosted Apify actor manages accounts and rate limits automatically.
|
|
285
|
+
|
|
286
|
+
**Will my account get banned?**
|
|
287
|
+
Never use your personal account — use dedicated accounts only. To reduce risk further: use **multiple accounts** (distributes load) and pair each with a **proxy** (prevents all requests from one IP).
|
|
288
|
+
|
|
289
|
+
**Does it work for private accounts?**
|
|
290
|
+
No. Only publicly visible content is accessible.
|
|
291
|
+
|
|
292
|
+
**Does it still work in 2025 / 2026?**
|
|
293
|
+
Yes — last verified working in March 2026 against X's current GraphQL API.
|
|
294
|
+
|
|
295
|
+
</details>
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Community
|
|
300
|
+
|
|
301
|
+
Have a question or want to share what you built with Scweet?
|
|
302
|
+
Open a thread in [**GitHub Discussions**](https://github.com/Altimis/Scweet/discussions).
|
|
303
|
+
|
|
304
|
+
**Found it useful? [Star the repo](https://github.com/Altimis/Scweet/stargazers)**
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Contributing
|
|
309
|
+
|
|
310
|
+
Bug reports, feature suggestions, and PRs are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
*MIT License*
|