tweepy-self 0.1.0__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.
@@ -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
+ [![Telegram channel](https://img.shields.io/endpoint?url=https://runkit.io/damiankrawczyk/telegram-badge/branches/master?url=https://t.me/cum_insider)](https://t.me/cum_insider)
25
+ [![PyPI version info](https://img.shields.io/pypi/v/tweepy-self.svg)](https://pypi.python.org/pypi/tweepy-self)
26
+ [![PyPI supported Python versions](https://img.shields.io/pypi/pyversions/tweepy-self.svg)](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 ADDED
@@ -0,0 +1,24 @@
1
+ """
2
+ Twitter API Wrapper
3
+ ~~~~~~~~~~~~~~~~~~~
4
+
5
+ A basic wrapper for the Twitter user API.
6
+ """
7
+
8
+ from .client import Client
9
+ from .account import Account, AccountStatus
10
+ from .models import Tweet, UserData
11
+ from . import errors, utils
12
+
13
+ __all__ = [
14
+ "Client",
15
+ "Account",
16
+ "AccountStatus",
17
+ "utils",
18
+ "errors",
19
+ ]
20
+
21
+
22
+ import warnings
23
+ # HACK: Ignore event loop warnings from curl_cffi
24
+ warnings.filterwarnings('ignore', module='curl_cffi')
twitter/account.py ADDED
@@ -0,0 +1,58 @@
1
+ import enum
2
+
3
+ from pydantic import BaseModel, Field
4
+ import pyotp
5
+
6
+ from .utils import hidden_value
7
+
8
+
9
+ class AccountStatus(enum.StrEnum):
10
+ BAD_TOKEN = "BAD_TOKEN" # (401) 32
11
+ UNKNOWN = "UNKNOWN"
12
+ SUSPENDED = "SUSPENDED" # (403) 64, (200) 141
13
+ LOCKED = "LOCKED" # (403) 326
14
+ GOOD = "GOOD"
15
+
16
+ def __str__(self):
17
+ return self.value
18
+
19
+
20
+ class Account(BaseModel):
21
+ auth_token: str | None = Field(default=None, pattern=r"^[a-f0-9]{40}$")
22
+ ct0: str | None
23
+ id: int | None
24
+ name: str | None
25
+ username: str | None
26
+ password: str | None
27
+ email: str | None
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
31
+
32
+ @property
33
+ def hidden_auth_token(self) -> str | None:
34
+ return hidden_value(self.auth_token) if self.auth_token else None
35
+
36
+ @property
37
+ def hidden_password(self) -> str | None:
38
+ return hidden_value(self.password) if self.password else None
39
+
40
+ @property
41
+ def hidden_key2fa(self) -> str | None:
42
+ return hidden_value(self.key2fa) if self.key2fa else None
43
+
44
+ @property
45
+ def hidden_backup_code(self) -> str | None:
46
+ return hidden_value(self.backup_code) if self.backup_code else None
47
+
48
+ def __repr__(self):
49
+ return f"{self.__class__.__name__}(auth_token={self.hidden_auth_token}, username={self.username})"
50
+
51
+ def __str__(self):
52
+ return self.hidden_auth_token
53
+
54
+ def get_2fa_code(self) -> str | None:
55
+ if not self.key2fa:
56
+ raise ValueError("No key2fa")
57
+
58
+ return str(pyotp.TOTP(self.key2fa).now())
@@ -0,0 +1,7 @@
1
+ from .client import BaseClient
2
+ from .session import BaseAsyncSession
3
+
4
+ __all__ = [
5
+ "BaseClient",
6
+ "BaseAsyncSession",
7
+ ]
twitter/base/client.py ADDED
@@ -0,0 +1,20 @@
1
+ from .session import BaseAsyncSession
2
+
3
+
4
+ class BaseClient:
5
+ _DEFAULT_HEADERS = None
6
+
7
+ def __init__(self, **session_kwargs):
8
+ self._session = BaseAsyncSession(
9
+ headers=session_kwargs.pop("headers", None) or self._DEFAULT_HEADERS,
10
+ **session_kwargs,
11
+ )
12
+
13
+ async def __aenter__(self):
14
+ return self
15
+
16
+ async def __aexit__(self, *args):
17
+ self.close()
18
+
19
+ def close(self):
20
+ self._session.close()
@@ -0,0 +1,56 @@
1
+ from curl_cffi import requests
2
+ from better_proxy import Proxy
3
+
4
+
5
+ class BaseAsyncSession(requests.AsyncSession):
6
+ """
7
+ Базовая асинхронная сессия:
8
+ - Принимает прокси в формате URL и better-proxy.
9
+ - Отключает верификацию SSL сертификатов по умолчанию.
10
+ - По умолчанию устанавливает версию браузера chrome120.
11
+ - По умолчанию устанавливает user-agent под версию браузера chrome120.
12
+ """
13
+ proxy: Proxy | None
14
+ DEFAULT_HEADERS = {
15
+ "accept": "*/*",
16
+ "accept-language": "en-US,en",
17
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
18
+ "sec-ch-ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
19
+ "sec-ch-ua-platform": '"Windows"',
20
+ "sec-ch-ua-mobile": "?0",
21
+ "sec-fetch-dest": "empty",
22
+ "sec-fetch-mode": "cors",
23
+ "sec-fetch-site": "same-origin",
24
+ "connection": "keep-alive",
25
+ }
26
+ DEFAULT_IMPERSONATE = requests.BrowserType.chrome120
27
+
28
+ def __init__(
29
+ self,
30
+ proxy: str | Proxy = None,
31
+ **session_kwargs,
32
+ ):
33
+ self._proxy = None
34
+ headers = session_kwargs["headers"] = session_kwargs.get("headers") or {}
35
+ headers.update(self.DEFAULT_HEADERS)
36
+ session_kwargs["impersonate"] = session_kwargs.get("impersonate") or self.DEFAULT_IMPERSONATE
37
+ session_kwargs["verify"] = session_kwargs.get("verify", False)
38
+ super().__init__(**session_kwargs)
39
+ self.proxy = proxy
40
+
41
+ @property
42
+ def user_agent(self) -> str:
43
+ return self.headers["user-agent"]
44
+
45
+ @property
46
+ def proxy(self) -> Proxy | None:
47
+ return self._proxy
48
+
49
+ @proxy.setter
50
+ def proxy(self, proxy: str | Proxy | None):
51
+ if not proxy:
52
+ self.proxies = {}
53
+ return
54
+
55
+ self._proxy = Proxy.from_str(proxy) if proxy else None
56
+ self.proxies = {"http": self._proxy.as_url, "https": self._proxy.as_url}