tweepy-self 1.0.0b1__py3-none-any.whl → 1.0.0b2__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- tweepy_self-1.0.0b2.dist-info/METADATA +218 -0
- tweepy_self-1.0.0b2.dist-info/RECORD +16 -0
- twitter/__init__.py +3 -3
- twitter/{_account.py → account.py} +6 -31
- twitter/base/__init__.py +7 -0
- twitter/{_client.py → base/client.py} +1 -1
- twitter/{_twitter_client.py → client.py} +4 -4
- twitter/errors.py +1 -1
- twitter/utils/__init__.py +42 -0
- twitter/utils/accounts.py +43 -0
- twitter/utils/file.py +41 -0
- twitter/{utils.py → utils/html.py} +0 -25
- twitter/utils/other.py +24 -0
- tweepy_self-1.0.0b1.dist-info/METADATA +0 -63
- tweepy_self-1.0.0b1.dist-info/RECORD +0 -12
- twitter/_file_utils.py +0 -17
- {tweepy_self-1.0.0b1.dist-info → tweepy_self-1.0.0b2.dist-info}/WHEEL +0 -0
- /twitter/{_session.py → base/session.py} +0 -0
- /twitter/{_models.py → models.py} +0 -0
@@ -0,0 +1,218 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: tweepy-self
|
3
|
+
Version: 1.0.0b2
|
4
|
+
Summary: Twitter (selfbot) for Python!
|
5
|
+
Author: Alen
|
6
|
+
Author-email: alen.kimov@gmail.com
|
7
|
+
Requires-Python: >=3.9,<4.0
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
13
|
+
Requires-Dist: beautifulsoup4 (>=4,<5)
|
14
|
+
Requires-Dist: better-proxy (==0.5.0)
|
15
|
+
Requires-Dist: curl_cffi (==0.6.0b9)
|
16
|
+
Requires-Dist: lxml (>=5,<6)
|
17
|
+
Requires-Dist: pydantic (>=2,<3)
|
18
|
+
Requires-Dist: pyotp (>=2,<3)
|
19
|
+
Requires-Dist: python3-capsolver (>=0.9,<0.10)
|
20
|
+
Requires-Dist: yarl (>=1,<2)
|
21
|
+
Description-Content-Type: text/markdown
|
22
|
+
|
23
|
+
# Tweepy-self
|
24
|
+
[](https://t.me/cum_insider)
|
25
|
+
[](https://pypi.python.org/pypi/tweepy-self)
|
26
|
+
[](https://pypi.python.org/pypi/tweepy-self)
|
27
|
+
|
28
|
+
A modern, easy to use, feature-rich, and async ready API wrapper for Twitter's user API written in Python.
|
29
|
+
|
30
|
+
- Docs (soon)
|
31
|
+
|
32
|
+
More libraries of the family:
|
33
|
+
- [better-web3](https://github.com/alenkimov/better_web3)
|
34
|
+
- [better-proxy](https://github.com/alenkimov/better_proxy)
|
35
|
+
- [better-automation](https://github.com/alenkimov/better_automation)
|
36
|
+
|
37
|
+
Отдельное спасибо [Кузнице Ботов](https://t.me/bots_forge) за код для авторизации и разморозки! Подписывайтесь на их Telegram :)
|
38
|
+
|
39
|
+
## Key Features
|
40
|
+
- Modern Pythonic API using async and await.
|
41
|
+
- Prevents user account automation detection.
|
42
|
+
|
43
|
+
## Installing
|
44
|
+
```bash
|
45
|
+
pip install tweepy-self
|
46
|
+
```
|
47
|
+
|
48
|
+
## Example
|
49
|
+
```python
|
50
|
+
import asyncio
|
51
|
+
import twitter
|
52
|
+
|
53
|
+
account = twitter.Account("auth_token")
|
54
|
+
|
55
|
+
async def main():
|
56
|
+
async with twitter.Client(account) as twitter_client:
|
57
|
+
await twitter_client.tweet("Hello, tweepy-self! <3")
|
58
|
+
|
59
|
+
asyncio.run(main())
|
60
|
+
```
|
61
|
+
|
62
|
+
## More
|
63
|
+
Automating user accounts is against the Twitter ToS. This library is a proof of concept and I cannot recommend using it. Do so at your own risk
|
64
|
+
|
65
|
+
## Документация (устаревшая)
|
66
|
+
`Код ушел немного дальше, чем эта документация.`
|
67
|
+
|
68
|
+
Библиотека позволяет работать с неофициальным API Twitter, а именно:
|
69
|
+
- Логин
|
70
|
+
- Анлок
|
71
|
+
- Привязывать сервисы (приложения).
|
72
|
+
- Устанавливать статус аккаунта (бан, лок).
|
73
|
+
- Загружать изображения на сервер и изменять баннер и аватарку.
|
74
|
+
- Изменять данные о пользователе: имя, описание профиля и другое.
|
75
|
+
- Изменять имя пользователя и пароль.
|
76
|
+
- Запрашивать информацию о подписчиках.
|
77
|
+
- Запрашивать некоторую информацию о пользователе (количество подписчиков и другое).
|
78
|
+
- Голосовать.
|
79
|
+
- Подписываться и отписываться.
|
80
|
+
- Лайкать и дизлайкать.
|
81
|
+
- Твиттить, ретвиттить с изображением и без.
|
82
|
+
- Закреплять твиты.
|
83
|
+
- Запрашивать твиты пользователей.
|
84
|
+
- Удалять твиты.
|
85
|
+
- И другое.
|
86
|
+
|
87
|
+
#### Статус аккаунта
|
88
|
+
После любого взаимодействия с Twitter устанавливается статус аккаунта:
|
89
|
+
- `BAD_TOKEN` - Неверный токен.
|
90
|
+
- `UNKNOWN` - Статус аккаунта не установлен.
|
91
|
+
- `SUSPENDED` - Действие учетной записи приостановлено (бан).
|
92
|
+
- `LOCKED` - Учетная запись заморожена (лок) (требуется прохождение капчи).
|
93
|
+
- `GOOD` - Аккаунт в порядке.
|
94
|
+
|
95
|
+
Не каждое взаимодействие с Twitter достоверно определяет статус аккаунта.
|
96
|
+
Например, простой запрос данных об аккаунте честно вернет данные, даже если ваш аккаунт заморожен.
|
97
|
+
|
98
|
+
Для достоверной установки статуса аккаунта используйте метод `establish_status()`
|
99
|
+
|
100
|
+
### Примеры работы
|
101
|
+
Запрос информации о пользователе:
|
102
|
+
```python
|
103
|
+
# Запрос информации о текущем пользователе:
|
104
|
+
me = await twitter_client.request_user_data()
|
105
|
+
print(f"[{account.short_auth_token}] {me}")
|
106
|
+
print(f"Аккаунт создан: {me.created_at}")
|
107
|
+
print(f"Following (подписан ты): {me.followings_count}")
|
108
|
+
print(f"Followers (подписаны на тебя): {me.followers_count}")
|
109
|
+
print(f"Прочая информация: {me.raw_data}")
|
110
|
+
|
111
|
+
# Запрос информации об ином пользователе:
|
112
|
+
elonmusk = await twitter.request_user_data("@elonmusk")
|
113
|
+
print(elonmusk)
|
114
|
+
```
|
115
|
+
|
116
|
+
Смена имени пользователя и пароля:
|
117
|
+
```python
|
118
|
+
account = twitter.Account("auth_token", password="password")
|
119
|
+
...
|
120
|
+
await twitter_client.change_username("new_username")
|
121
|
+
await twitter_client.request_user_data()
|
122
|
+
print(f"New username: {account.data.username}")
|
123
|
+
|
124
|
+
await twitter_client.change_password("new_password")
|
125
|
+
print(f"New password: {account.password}")
|
126
|
+
print(f"New auth_token: {account.auth_token}")
|
127
|
+
```
|
128
|
+
|
129
|
+
Смена данных профиля:
|
130
|
+
```python
|
131
|
+
await twitter_client.update_birthdate(day=1, month=12, year=2000)
|
132
|
+
await twitter_client.update_profile( # Locks account!
|
133
|
+
name="New Name",
|
134
|
+
description="New description",
|
135
|
+
location="New York",
|
136
|
+
website="https://github.com/alenkimov/better_automation",
|
137
|
+
)
|
138
|
+
```
|
139
|
+
|
140
|
+
Загрузка изображений и смена аватара и баннера:
|
141
|
+
```python
|
142
|
+
image = open(f"image.png", "rb").read()
|
143
|
+
media_id = await twitter_client.upload_image(image)
|
144
|
+
avatar_image_url = await twitter_client.update_profile_avatar(media_id)
|
145
|
+
banner_image_url = await twitter_client.update_profile_banner(media_id)
|
146
|
+
```
|
147
|
+
|
148
|
+
Привязка сервиса (приложения):
|
149
|
+
|
150
|
+
```python
|
151
|
+
# Изучите запросы сервиса и найдите подобные данные для авторизации (привязки):
|
152
|
+
bind_data = {
|
153
|
+
'response_type': 'code',
|
154
|
+
'client_id': 'TjFVQm52ZDFGWEtNT0tKaktaSWU6MTpjaQ',
|
155
|
+
'redirect_uri': 'https://waitlist.lens.xyz/tw/',
|
156
|
+
'scope': 'users.read tweet.read offline.access',
|
157
|
+
'state': 'state', # Может быть как статичным, так и динамическим.
|
158
|
+
'code_challenge': 'challenge',
|
159
|
+
'code_challenge_method': 'plain'
|
160
|
+
}
|
161
|
+
|
162
|
+
bind_code = await twitter_client.oauth_2(**bind_data)
|
163
|
+
# Передайте код авторизации (привязки) сервису.
|
164
|
+
# Сервис также может потребовать state, если он динамический.
|
165
|
+
```
|
166
|
+
|
167
|
+
Отправка сообщения:
|
168
|
+
```python
|
169
|
+
bro = await twitter_client.request_user_data("@username")
|
170
|
+
await twitter_client.send_message(bro.id, "I love you!")
|
171
|
+
```
|
172
|
+
|
173
|
+
Запрос входящих сообщений:
|
174
|
+
```python
|
175
|
+
messages = await twitter_client.request_messages()
|
176
|
+
for message in messages:
|
177
|
+
message_data = message["message_data"]
|
178
|
+
recipient_id = message_data["recipient_id"]
|
179
|
+
sender_id = message_data["sender_id"]
|
180
|
+
text = message_data["text"]
|
181
|
+
print(f"[id {sender_id}] -> [id {recipient_id}]: {text}")
|
182
|
+
```
|
183
|
+
|
184
|
+
Другие методы:
|
185
|
+
```python
|
186
|
+
# Выражение любви через твит
|
187
|
+
tweet_id = await twitter_client.tweet("I love YOU! !!!!1!1")
|
188
|
+
print(f"Любовь выражена! Tweet id: {tweet_id}")
|
189
|
+
|
190
|
+
print(f"Tweet is pined: {await twitter_client.pin_tweet(tweet_id)}")
|
191
|
+
|
192
|
+
# Лайк
|
193
|
+
print(f"Tweet {tweet_id} is liked: {await twitter_client.like(tweet_id)}")
|
194
|
+
|
195
|
+
# Репост (ретвит)
|
196
|
+
print(f"Tweet {tweet_id} is retweeted. Tweet id: {await twitter_client.repost(tweet_id)}")
|
197
|
+
|
198
|
+
# Коммент (реплай)
|
199
|
+
print(f"Tweet {tweet_id} is replied. Reply id: {await twitter_client.reply(tweet_id, 'tem razão')}")
|
200
|
+
|
201
|
+
# Подписываемся на Илона Маска
|
202
|
+
print(f"@{elonmusk.username} is followed: {await twitter_client.follow(elonmusk.id)}")
|
203
|
+
|
204
|
+
# Отписываемся от Илона Маска
|
205
|
+
print(f"@{elonmusk.username} is unfollowed: {await twitter_client.unfollow(elonmusk.id)}")
|
206
|
+
|
207
|
+
tweet_url = 'https://twitter.com/CreamIce_Cone/status/1691735090529976489'
|
208
|
+
# Цитата (Quote tweet)
|
209
|
+
quote_tweet_id = await twitter_client.quote(tweet_url, 'oh....')
|
210
|
+
print(f"Quoted! Tweet id: {quote_tweet_id}")
|
211
|
+
|
212
|
+
# Запрашиваем первых трех подписчиков
|
213
|
+
# (Параметр count по каким-то причинам работает некорректно)
|
214
|
+
followers = await twitter_client.request_followers(count=20)
|
215
|
+
print("Твои подписчики:")
|
216
|
+
for follower in followers:
|
217
|
+
print(follower)
|
218
|
+
```
|
@@ -0,0 +1,16 @@
|
|
1
|
+
twitter/__init__.py,sha256=ydA6wuWhW7-0sYmaJyl5_7wIaekKdaBaN7aO6elywLk,465
|
2
|
+
twitter/account.py,sha256=vXPd3ag3lmYbSblAnHJLm6t42SyFNbULpjWkRPiDhT0,1787
|
3
|
+
twitter/base/__init__.py,sha256=x0EHKv4q_FI6xEq2nL4V9s8P6VWr6IaHTqdH9sXB5d8,133
|
4
|
+
twitter/base/client.py,sha256=7byb0Psai-dvg_ww6Y7uyE2hV1pfTU653hFgVdRiqXo,478
|
5
|
+
twitter/base/session.py,sha256=6-gLhdSCaTCd_zv3YgUtVRGbfiAawXuDRBoo7s5bGSs,2234
|
6
|
+
twitter/client.py,sha256=v2ebGB3NxmEmStePAddNR5XX7oqBCn0Fm86wf0l7MVI,53004
|
7
|
+
twitter/errors.py,sha256=U6kGyNp_5tEq-RwxLjm61muJLEp5BYBq9vrPBkCxr_g,4088
|
8
|
+
twitter/models.py,sha256=3-Lft160msCqOjRPubOmxMqWUkmjlTSzHSGsvZK91nU,1817
|
9
|
+
twitter/utils/__init__.py,sha256=2sjQEu5jJgUEpGYT_arwNVhaboywCbYLB00eiD0mZCk,743
|
10
|
+
twitter/utils/accounts.py,sha256=lp7c4GyScAsY65V52V5Buquj8OZgWFyi-54YloRpOfE,1556
|
11
|
+
twitter/utils/file.py,sha256=-6n8I8KWDlntfciJJsfIeOi0gmqoHRIe1ldIx1ynGUE,1118
|
12
|
+
twitter/utils/html.py,sha256=Cs55MxVyZLSKiCEj11ALUrnCW9ADZ4CEDCE0gKESzO0,1627
|
13
|
+
twitter/utils/other.py,sha256=4NaGd2CIJVrDiW17shcrDlJRqFkQNbBSTiiH7kNWcww,559
|
14
|
+
tweepy_self-1.0.0b2.dist-info/METADATA,sha256=0rOKLx8U1hRVeRKk9T6qnRHu_RAP3sqbOFV5qSajmKA,9230
|
15
|
+
tweepy_self-1.0.0b2.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
16
|
+
tweepy_self-1.0.0b2.dist-info/RECORD,,
|
twitter/__init__.py
CHANGED
@@ -5,9 +5,9 @@ Twitter API Wrapper
|
|
5
5
|
A basic wrapper for the Twitter user API.
|
6
6
|
"""
|
7
7
|
|
8
|
-
from .
|
9
|
-
from .
|
10
|
-
from .
|
8
|
+
from .client import Client
|
9
|
+
from .account import Account, AccountStatus
|
10
|
+
from .models import Tweet, UserData
|
11
11
|
from . import errors, utils
|
12
12
|
|
13
13
|
__all__ = [
|
@@ -1,14 +1,10 @@
|
|
1
1
|
import enum
|
2
2
|
|
3
|
+
from pydantic import BaseModel, Field
|
3
4
|
import pyotp
|
4
5
|
|
5
6
|
from .utils import hidden_value
|
6
7
|
|
7
|
-
# TODO Валидация
|
8
|
-
# AUTH_TOKEN_PATTERN = r"^[a-f0-9]{40}$"
|
9
|
-
# BACKUP_CODE_PATTERN = r"^[a-z0-9]{12}$"
|
10
|
-
# KEY_2FA_PATTERN = r"^[A-Z0-9]{16}$"
|
11
|
-
|
12
8
|
|
13
9
|
class AccountStatus(enum.StrEnum):
|
14
10
|
BAD_TOKEN = "BAD_TOKEN" # (401) 32
|
@@ -21,38 +17,17 @@ class AccountStatus(enum.StrEnum):
|
|
21
17
|
return self.value
|
22
18
|
|
23
19
|
|
24
|
-
class Account:
|
25
|
-
auth_token: str | None
|
20
|
+
class Account(BaseModel):
|
21
|
+
auth_token: str | None = Field(default=None, pattern=r"^[a-f0-9]{40}$")
|
26
22
|
ct0: str | None
|
27
23
|
id: int | None
|
28
24
|
name: str | None
|
29
25
|
username: str | None
|
30
26
|
password: str | None
|
31
27
|
email: str | None
|
32
|
-
key2fa: str | None
|
33
|
-
backup_code: str | None
|
34
|
-
status: AccountStatus
|
35
|
-
|
36
|
-
def __init__(
|
37
|
-
self,
|
38
|
-
auth_token: str = None,
|
39
|
-
*,
|
40
|
-
username: str = None,
|
41
|
-
password: str = None,
|
42
|
-
email: str = None,
|
43
|
-
key2fa: str = None,
|
44
|
-
backup_code: str = None,
|
45
|
-
):
|
46
|
-
self.auth_token = auth_token
|
47
|
-
self.ct0 = None
|
48
|
-
self.id = None
|
49
|
-
self.name = None
|
50
|
-
self.username = username
|
51
|
-
self.password = password
|
52
|
-
self.email = email
|
53
|
-
self.key2fa = key2fa
|
54
|
-
self.backup_code = backup_code
|
55
|
-
self.status = AccountStatus.UNKNOWN
|
28
|
+
key2fa: str | None = Field(default=None, pattern=r"^[a-f0-9]{12}$")
|
29
|
+
backup_code: str | None = Field(default=None, pattern=r"^[A-Z0-9]{16}$")
|
30
|
+
status: AccountStatus = AccountStatus.UNKNOWN
|
56
31
|
|
57
32
|
@property
|
58
33
|
def hidden_auth_token(self) -> str | None:
|
twitter/base/__init__.py
ADDED
@@ -23,10 +23,10 @@ from .errors import (
|
|
23
23
|
Locked,
|
24
24
|
Suspended,
|
25
25
|
)
|
26
|
-
from .
|
27
|
-
from .
|
28
|
-
from .
|
29
|
-
from .
|
26
|
+
from .utils import to_json
|
27
|
+
from .base import BaseClient
|
28
|
+
from .account import Account, AccountStatus
|
29
|
+
from .models import UserData, Tweet
|
30
30
|
from .utils import remove_at_sign, parse_oauth_html, parse_unlock_html
|
31
31
|
|
32
32
|
|
twitter/errors.py
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
from .file import (
|
2
|
+
copy_file,
|
3
|
+
load_lines,
|
4
|
+
load_json,
|
5
|
+
load_toml,
|
6
|
+
write_lines,
|
7
|
+
write_json,
|
8
|
+
to_json,
|
9
|
+
)
|
10
|
+
from .accounts import (
|
11
|
+
load_accounts_from_file,
|
12
|
+
extract_accounts_to_file,
|
13
|
+
)
|
14
|
+
from .html import (
|
15
|
+
parse_unlock_html,
|
16
|
+
parse_oauth_html,
|
17
|
+
)
|
18
|
+
from .other import (
|
19
|
+
remove_at_sign,
|
20
|
+
tweet_url,
|
21
|
+
to_datetime,
|
22
|
+
hidden_value,
|
23
|
+
)
|
24
|
+
|
25
|
+
|
26
|
+
__all__ = [
|
27
|
+
"copy_file",
|
28
|
+
"load_lines",
|
29
|
+
"load_json",
|
30
|
+
"load_toml",
|
31
|
+
"write_lines",
|
32
|
+
"write_json",
|
33
|
+
"to_json",
|
34
|
+
"load_accounts_from_file",
|
35
|
+
"extract_accounts_to_file",
|
36
|
+
"parse_unlock_html",
|
37
|
+
"parse_oauth_html",
|
38
|
+
"remove_at_sign",
|
39
|
+
"tweet_url",
|
40
|
+
"to_datetime",
|
41
|
+
"hidden_value",
|
42
|
+
]
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
from typing import Sequence, Iterable
|
3
|
+
|
4
|
+
from .file import load_lines, write_lines
|
5
|
+
from ..account import Account
|
6
|
+
|
7
|
+
|
8
|
+
def load_accounts_from_file(
|
9
|
+
filepath: Path | str,
|
10
|
+
*,
|
11
|
+
separator: str = ":",
|
12
|
+
fields: Sequence[str] = ("auth_token", "password", "email", "username"),
|
13
|
+
) -> list[Account]:
|
14
|
+
"""
|
15
|
+
:param filepath: Путь до файла с данными об аккаунтах.
|
16
|
+
:param separator: Разделитель между данными в строке.
|
17
|
+
:param fields: Кортеж, содержащий имена полей в порядке их появления в строке.
|
18
|
+
:return: Список Twitter аккаунтов.
|
19
|
+
"""
|
20
|
+
accounts = []
|
21
|
+
for line in load_lines(filepath):
|
22
|
+
data = dict(zip(fields, line.split(separator)))
|
23
|
+
data.update({key: None for key in data if not data[key]})
|
24
|
+
accounts.append(Account(**data))
|
25
|
+
return accounts
|
26
|
+
|
27
|
+
|
28
|
+
def extract_accounts_to_file(
|
29
|
+
filepath: Path | str,
|
30
|
+
accounts: Iterable[Account],
|
31
|
+
*,
|
32
|
+
separator: str = ":",
|
33
|
+
fields: Sequence[str] = ("auth_token", "password", "email", "username"),
|
34
|
+
):
|
35
|
+
lines = []
|
36
|
+
for account in accounts:
|
37
|
+
account_data = []
|
38
|
+
for field_name in fields:
|
39
|
+
field = getattr(account, field_name)
|
40
|
+
field = field if field is not None else ""
|
41
|
+
account_data.append(field)
|
42
|
+
lines.append(separator.join(account_data))
|
43
|
+
write_lines(filepath, lines)
|
twitter/utils/file.py
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
import json
|
2
|
+
import shutil
|
3
|
+
import tomllib
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Iterable
|
6
|
+
|
7
|
+
|
8
|
+
def copy_file(source_path: Path | str, destination_path: Path | str):
|
9
|
+
destination_path = Path(destination_path)
|
10
|
+
if destination_path.exists():
|
11
|
+
return
|
12
|
+
shutil.copy2(str(source_path), str(destination_path))
|
13
|
+
|
14
|
+
|
15
|
+
def load_toml(filepath: Path | str) -> dict:
|
16
|
+
with open(filepath, "rb") as file:
|
17
|
+
return tomllib.load(file)
|
18
|
+
|
19
|
+
|
20
|
+
def load_lines(filepath: Path | str) -> list[str]:
|
21
|
+
with open(filepath, "r") as file:
|
22
|
+
return [line.strip() for line in file.readlines() if line != "\n"]
|
23
|
+
|
24
|
+
|
25
|
+
def write_lines(filepath: Path | str, lines: Iterable[str]):
|
26
|
+
with open(filepath, "w") as file:
|
27
|
+
file.write("\n".join(lines))
|
28
|
+
|
29
|
+
|
30
|
+
def load_json(filepath: Path | str) -> dict:
|
31
|
+
with open(filepath, "r") as file:
|
32
|
+
return json.load(file)
|
33
|
+
|
34
|
+
|
35
|
+
def write_json(filepath: Path | str, data):
|
36
|
+
with open(filepath, "w") as file:
|
37
|
+
json.dump(data, file, indent=4)
|
38
|
+
|
39
|
+
|
40
|
+
def to_json(obj) -> str:
|
41
|
+
return json.dumps(obj, separators=(',', ':'), ensure_ascii=True)
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from datetime import datetime
|
2
|
-
|
3
1
|
from bs4 import BeautifulSoup
|
4
2
|
|
5
3
|
|
@@ -29,26 +27,3 @@ def parse_unlock_html(html: str) -> tuple[str | None, str | None, bool]:
|
|
29
27
|
verification_string = soup.find('input', id='verification_string')
|
30
28
|
needs_unlock = bool(verification_string)
|
31
29
|
return authenticity_token, assignment_token, needs_unlock
|
32
|
-
|
33
|
-
|
34
|
-
def remove_at_sign(username: str) -> str:
|
35
|
-
if username.startswith("@"):
|
36
|
-
return username[1:]
|
37
|
-
return username
|
38
|
-
|
39
|
-
|
40
|
-
def tweet_url(username: str, tweet_id: int) -> str:
|
41
|
-
"""
|
42
|
-
:return: Tweet URL
|
43
|
-
"""
|
44
|
-
return f"https://x.com/{username}/status/{tweet_id}"
|
45
|
-
|
46
|
-
|
47
|
-
def to_datetime(twitter_datetime: str):
|
48
|
-
return datetime.strptime(twitter_datetime, '%a %b %d %H:%M:%S +0000 %Y')
|
49
|
-
|
50
|
-
|
51
|
-
def hidden_value(value: str) -> str:
|
52
|
-
start = value[:3]
|
53
|
-
end = value[-3:]
|
54
|
-
return f"{start}**{end}"
|
twitter/utils/other.py
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
|
3
|
+
|
4
|
+
def remove_at_sign(username: str) -> str:
|
5
|
+
if username.startswith("@"):
|
6
|
+
return username[1:]
|
7
|
+
return username
|
8
|
+
|
9
|
+
|
10
|
+
def tweet_url(username: str, tweet_id: int) -> str:
|
11
|
+
"""
|
12
|
+
:return: Tweet URL
|
13
|
+
"""
|
14
|
+
return f"https://x.com/{username}/status/{tweet_id}"
|
15
|
+
|
16
|
+
|
17
|
+
def to_datetime(twitter_datetime: str):
|
18
|
+
return datetime.strptime(twitter_datetime, '%a %b %d %H:%M:%S +0000 %Y')
|
19
|
+
|
20
|
+
|
21
|
+
def hidden_value(value: str) -> str:
|
22
|
+
start = value[:3]
|
23
|
+
end = value[-3:]
|
24
|
+
return f"{start}**{end}"
|
@@ -1,63 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: tweepy-self
|
3
|
-
Version: 1.0.0b1
|
4
|
-
Summary: Twitter (selfbot) for Python!
|
5
|
-
Author: Alen
|
6
|
-
Author-email: alen.kimov@gmail.com
|
7
|
-
Requires-Python: >=3.9,<4.0
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
9
|
-
Classifier: Programming Language :: Python :: 3.9
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
12
|
-
Classifier: Programming Language :: Python :: 3.12
|
13
|
-
Requires-Dist: beautifulsoup4 (>=4,<5)
|
14
|
-
Requires-Dist: better-proxy (==0.5.0)
|
15
|
-
Requires-Dist: curl_cffi (==0.6.0b9)
|
16
|
-
Requires-Dist: lxml (>=5,<6)
|
17
|
-
Requires-Dist: pydantic (>=2,<3)
|
18
|
-
Requires-Dist: pyotp (>=2,<3)
|
19
|
-
Requires-Dist: python3-capsolver (>=0.9,<0.10)
|
20
|
-
Requires-Dist: yarl (>=1,<2)
|
21
|
-
Description-Content-Type: text/markdown
|
22
|
-
|
23
|
-
# Tweepy-self
|
24
|
-
[](https://t.me/cum_insider)
|
25
|
-
[](https://pypi.python.org/pypi/tweepy-self)
|
26
|
-
[](https://pypi.python.org/pypi/tweepy-self)
|
27
|
-
|
28
|
-
A modern, easy to use, feature-rich, and async ready API wrapper for Twitter's user API written in Python.
|
29
|
-
|
30
|
-
- Docs (soon)
|
31
|
-
|
32
|
-
More libraries of the family:
|
33
|
-
- [better-web3](https://github.com/alenkimov/better_web3)
|
34
|
-
- [better-proxy](https://github.com/alenkimov/better_proxy)
|
35
|
-
|
36
|
-
Отдельное спасибо [Кузнице Ботов](https://t.me/bots_forge), как соавторам! Подписывайтесь на их Telegram :)
|
37
|
-
|
38
|
-
## Key Features
|
39
|
-
- Modern Pythonic API using async and await.
|
40
|
-
- Prevents user account automation detection.
|
41
|
-
|
42
|
-
## Installing
|
43
|
-
```bash
|
44
|
-
pip install tweepy-self
|
45
|
-
```
|
46
|
-
|
47
|
-
## Example
|
48
|
-
```python
|
49
|
-
import asyncio
|
50
|
-
import twitter
|
51
|
-
|
52
|
-
account = twitter.Account("auth_token")
|
53
|
-
|
54
|
-
async def main():
|
55
|
-
async with twitter.Client(account) as twitter_client:
|
56
|
-
await twitter_client.tweet("Hello, tweepy-self! <3")
|
57
|
-
|
58
|
-
asyncio.run(main())
|
59
|
-
```
|
60
|
-
|
61
|
-
## More
|
62
|
-
Automating user accounts is against the Twitter ToS. This library is a proof of concept and I cannot recommend using it. Do so at your own risk
|
63
|
-
|
@@ -1,12 +0,0 @@
|
|
1
|
-
twitter/__init__.py,sha256=nC-rEZfRkk8Bp26yWtlzciR7mdOrfcI_KXHcnkW4hyk,476
|
2
|
-
twitter/_account.py,sha256=dTNHdYhAJgznrXp6nRRtswuWMR5LjohrtwmPf53SSDU,2382
|
3
|
-
twitter/_client.py,sha256=3QUfb5uH-erDt2STx9BELSB6u_5U1p_oyPs6As0tIOo,479
|
4
|
-
twitter/_file_utils.py,sha256=ePgsHMlGmegBBMK5ZhCZVeJp58WRQ7kaArPDAgjSu-c,495
|
5
|
-
twitter/_models.py,sha256=3-Lft160msCqOjRPubOmxMqWUkmjlTSzHSGsvZK91nU,1817
|
6
|
-
twitter/_session.py,sha256=6-gLhdSCaTCd_zv3YgUtVRGbfiAawXuDRBoo7s5bGSs,2234
|
7
|
-
twitter/_twitter_client.py,sha256=l0fztx0sk03ojWStDe0oovQpKWqCj-vNZzLK05b_E-Y,53015
|
8
|
-
twitter/errors.py,sha256=7BzHnm3iinbkQrW38PqEqpZNwJCk41l57qQ2hhOV59I,4089
|
9
|
-
twitter/utils.py,sha256=AlE1Z7Vxgm9i6vWi8rUso9gPobKnZh-ZFiDBT90YNA8,2188
|
10
|
-
tweepy_self-1.0.0b1.dist-info/METADATA,sha256=jb6otKQVeG13qg53hbt4iUdVr1VtPi44gpn1p1qQFaI,2192
|
11
|
-
tweepy_self-1.0.0b1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
12
|
-
tweepy_self-1.0.0b1.dist-info/RECORD,,
|
twitter/_file_utils.py
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
from pathlib import Path
|
3
|
-
from typing import Iterable
|
4
|
-
|
5
|
-
|
6
|
-
def load_lines(filepath: Path | str) -> list[str]:
|
7
|
-
with open(filepath, "r") as file:
|
8
|
-
return [line.strip() for line in file.readlines() if line != "\n"]
|
9
|
-
|
10
|
-
|
11
|
-
def write_lines(filepath: Path | str, lines: Iterable[str]):
|
12
|
-
with open(filepath, "w") as file:
|
13
|
-
file.write("\n".join(lines))
|
14
|
-
|
15
|
-
|
16
|
-
def to_json(obj) -> str:
|
17
|
-
return json.dumps(obj, separators=(',', ':'), ensure_ascii=True, default=str)
|
File without changes
|
File without changes
|
File without changes
|