tweepy-self 1.9.0__py3-none-any.whl → 1.10.0__py3-none-any.whl

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.
@@ -0,0 +1,306 @@
1
+ Metadata-Version: 2.1
2
+ Name: tweepy-self
3
+ Version: 1.10.0
4
+ Summary: Twitter (selfbot) for Python!
5
+ Home-page: https://github.com/alenkimov/tweepy-self
6
+ Author: Alen
7
+ Author-email: alen.kimov@gmail.com
8
+ Requires-Python: >=3.11,<4.0
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Requires-Dist: aiohttp (>=3.9,<4.0)
13
+ Requires-Dist: beautifulsoup4 (>=4,<5)
14
+ Requires-Dist: better-proxy (>=1.1,<2.0)
15
+ Requires-Dist: curl_cffi (==0.6.2)
16
+ Requires-Dist: loguru (>=0.7,<0.8)
17
+ Requires-Dist: lxml (>=5,<6)
18
+ Requires-Dist: pydantic (>=2,<3)
19
+ Requires-Dist: pyotp (>=2,<3)
20
+ Requires-Dist: requests (>=2,<3)
21
+ Requires-Dist: tenacity (>=8,<9)
22
+ Requires-Dist: yarl (>=1,<2)
23
+ Project-URL: Repository, https://github.com/alenkimov/tweepy-self
24
+ Project-URL: Source, https://github.com/alenkimov/tweepy-self
25
+ Description-Content-Type: text/markdown
26
+
27
+ # Tweepy-self
28
+ [![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)
29
+ [![PyPI version info](https://img.shields.io/pypi/v/tweepy-self.svg)](https://pypi.python.org/pypi/tweepy-self)
30
+ [![PyPI supported Python versions](https://img.shields.io/pypi/pyversions/tweepy-self.svg)](https://pypi.python.org/pypi/tweepy-self)
31
+ [![PyPI downloads per month](https://img.shields.io/pypi/dm/tweepy-self.svg)](https://pypi.python.org/pypi/tweepy-self)
32
+
33
+ A modern, easy to use, feature-rich, and async ready API wrapper for Twitter's user API written in Python.
34
+
35
+ _NEW!_ Менеджер аккаунтов с базой данных:
36
+ - [tweepy-manager](https://github.com/alenkimov/tweepy-manager)
37
+
38
+ More libraries of the family:
39
+ - [better-proxy](https://github.com/alenkimov/better_proxy)
40
+ - [better-web3](https://github.com/alenkimov/better_web3)
41
+
42
+ Отдельное спасибо [Кузнице Ботов](https://t.me/bots_forge) за код для авторизации и разморозки! Подписывайтесь на их Telegram :)
43
+
44
+ ## Key Features
45
+ - Modern Pythonic API using async and await.
46
+ - Prevents user account automation detection.
47
+
48
+ ## Installing
49
+ ```bash
50
+ pip install tweepy-self
51
+ ```
52
+
53
+ ## Example
54
+ ```python
55
+ import asyncio
56
+ import twitter
57
+
58
+ twitter_account = twitter.Account(auth_token="auth_token")
59
+
60
+ async def main():
61
+ async with twitter.Client(twitter_account) as twitter_client:
62
+ print(f"Logged in as @{twitter_account.username} (id={twitter_account.id})")
63
+ tweet = await twitter_client.tweet("Hello tweepy-self! <3")
64
+ print(tweet)
65
+
66
+ if __name__ == "__main__":
67
+ asyncio.run(main())
68
+ ```
69
+
70
+ ## Документация
71
+ ### Некоторые истины
72
+ Имена пользователей нужно передавать БЕЗ знака `@`.
73
+ Чтобы наверняка убрать этот знак можно передать имя пользователя в функцию `twitter.utils.remove_at_sign()`
74
+
75
+ 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
76
+
77
+ ### Как включить логирование
78
+ ```python
79
+ import sys
80
+ from loguru import logger
81
+
82
+ logger.remove()
83
+ logger.add(sys.stdout, level="INFO")
84
+ logger.enable("twitter")
85
+ ```
86
+
87
+ `level="DEBUG"` позволяет увидеть информацию обо всех запросах.
88
+
89
+ ### Аккаунт
90
+ После любого взаимодействия с Twitter устанавливается статус аккаунта:
91
+ - `UNKNOWN` - Статус аккаунта не установлен. Это статус по умолчанию.
92
+ - `BAD_TOKEN` - Неверный или мертвый токен.
93
+ - `SUSPENDED` - Действие учетной записи приостановлено. Тем не менее возможен запрос данных, а также авторизация через OAuth и OAuth2.
94
+ - `LOCKED` - Учетная запись заморожена (лок). Для разморозки (анлок) требуется прохождение капчи (funcaptcha).
95
+ - `CONSENT_LOCKED` - Учетная запись заморожена (лок). Условия для разморозки неизвестны.
96
+ - `GOOD` - Аккаунт в порядке.
97
+
98
+ Не каждое взаимодействие с Twitter достоверно определяет статус аккаунта.
99
+ Например, простой запрос данных об аккаунте честно вернет данные, даже если действие вашей учетной записи приостановлено.
100
+
101
+ Для достоверной установки статуса аккаунта используйте метод `Client.establish_status()`
102
+
103
+ ### Настройка клиента
104
+ Класс `twitter.Client` может быть сконфигурирован перед работой. Он принимает в себя следующие параметры:
105
+ - `wait_on_rate_limit` Если включено, то при достижении Rate Limit будет ждать, вместо того, чтобы выбрасывать исключение. Включено по умолчанию.
106
+ - `capsolver_api_key` API ключ сервиса [CapSolver](https://dashboard.capsolver.com/passport/register?inviteCode=m-aE3NeBGZLU). Нужен для автоматической разморозки аккаунта.
107
+ - `max_unlock_attempts` Максимальное количество попыток разморозки аккаунта. По умолчанию: 5.
108
+ - `auto_relogin` Если включено, то при невалидном токене (`BAD_TOKEN`) и предоставленных данных для авторизации (имя пользователя, пароль и totp_secret) будет произведен автоматический релогин (замена токена). Включено по умолчанию.
109
+ - `update_account_info_on_startup` Если включено, то на старте будет автоматически запрошена информация об аккаунте. Включено по умолчанию.
110
+ - `**session_kwargs` Любые параметры, которые может принимать сессия `curl_cffi.requests.AsyncSession`. Например, можно передать параметр `proxy`.
111
+
112
+ Пример настройки клиента:
113
+ ```python
114
+ async with twitter.Client(
115
+ twitter_account,
116
+ capsolver_api_key="CAP-00000000000000000000000000000000",
117
+ proxy="http://login:password@ip:port", # Можно передавать в любом формате, так как используется библиотека better_proxy
118
+ ) as twitter_client:
119
+ ...
120
+ ```
121
+
122
+ ### Доступные методы
123
+ Список всех методов.
124
+
125
+ #### Запрос информации о собственном аккаунте
126
+ ```python
127
+ twitter_client.update_account_info()
128
+ print(twitter_client.account)
129
+ ```
130
+
131
+ #### Запрос пользователя по username или по ID
132
+
133
+ ```python
134
+ bro = twitter_client.request_user_by_username(bro_username)
135
+ bro = twitter_client.request_user_by_id(bro_id)
136
+ bros = twitter_client.request_users_by_ids([bro1_id, bro2_id, ...])
137
+ ```
138
+
139
+ #### Загрузка изображения на сервер, смена аватарки и баннера
140
+ ```python
141
+ image = open("image.png", "rb").read()
142
+ media = await twitter_client.upload_image(image)
143
+ avatar_image_url = await twitter_client.update_profile_avatar(media.id)
144
+ banner_image_url = await twitter_client.update_profile_banner(media.id)
145
+ ```
146
+
147
+ #### Изменения данных профиля
148
+ ```python
149
+ await twitter_client.update_birthdate(day=1, month=12, year=2000)
150
+ await twitter_client.update_profile( # Locks account!
151
+ name="New Name",
152
+ description="New description",
153
+ location="New York",
154
+ website="https://github.com/alenkimov/tweepy-self",
155
+ )
156
+ ```
157
+
158
+ #### Включение TOTP (2FA)
159
+ ```python
160
+ if await twitter_client.totp_is_enabled():
161
+ print(f"TOTP уже включен.")
162
+ return
163
+
164
+ await twitter_client.enable_totp()
165
+ ```
166
+
167
+ #### Логин, если включен TOTP (2FA)
168
+ ```python
169
+ import twitter
170
+
171
+ twitter_account = twitter.Account(auth_token="...", username="...", password="...", totp_secret="...")
172
+ await twitter_client.login()
173
+ print(f"Logged in! New auth_token: {twitter_account.auth_token}")
174
+ ```
175
+
176
+ #### Смена имени пользователя и пароля
177
+ ```python
178
+ twitter_account = twitter.Account("auth_token", password="password")
179
+ ...
180
+ await twitter_client.change_username("new_username")
181
+ await twitter_client.request_user()
182
+ print(f"New username: {twitter_account.username}")
183
+
184
+ await twitter_client.change_password("new_password")
185
+ print(f"New password: {twitter_account.password}")
186
+ print(f"New auth_token: {twitter_account.auth_token}")
187
+ ```
188
+
189
+ #### Авторизация с OAuth
190
+ ```python
191
+ auth_code = await twitter_client.oauth(oauth_token, **oauth_params)
192
+ ```
193
+
194
+ #### Авторизация с OAuth2
195
+ ```python
196
+ # Изучите запросы сервиса и найдите подобные данные для авторизации (привязки):
197
+ oauth2_data = {
198
+ 'response_type': 'code',
199
+ 'client_id': 'TjFVQm52ZDFGWEtNT0tKaktaSWU6MTpjaQ',
200
+ 'redirect_uri': 'https://waitlist.lens.xyz/tw/',
201
+ 'scope': 'users.read tweet.read offline.access',
202
+ 'state': 'state', # Может быть как статичным, так и динамическим.
203
+ 'code_challenge': 'challenge',
204
+ 'code_challenge_method': 'plain'
205
+ }
206
+
207
+ auth_code = await twitter_client.oauth2(**oauth2_data)
208
+ # Передайте код авторизации (привязки) сервису.
209
+ # Сервис также может потребовать state, если он динамический.
210
+ ```
211
+
212
+ #### Отправка сообщения:
213
+ ```python
214
+ bro = await twitter_client.request_user("bro_username")
215
+ await twitter_client.send_message(bro.id, "I love you!")
216
+ ```
217
+
218
+ #### Запрос входящих сообщений:
219
+ ```python
220
+ messages = await twitter_client.request_messages()
221
+ for message in messages:
222
+ message_data = message["message_data"]
223
+ recipient_id = message_data["recipient_id"]
224
+ sender_id = message_data["sender_id"]
225
+ text = message_data["text"]
226
+ print(f"[id {sender_id}] -> [id {recipient_id}]: {text}")
227
+ ```
228
+
229
+ Так как мне почти не приходилось работать с сообщениями, я еще не сделал для этого удобных моделей.
230
+ Поэтому приходится работать со словарем.
231
+
232
+ #### Пост (твит)
233
+ ```python
234
+ tweet = await twitter_client.tweet("I love you tweepy-self! <3")
235
+ print(f"Любовь выражена! Tweet id: {tweet.id}")
236
+ ```
237
+
238
+ #### Лайк, репост (ретвит), коммент (реплай)
239
+ ```python
240
+ # Лайк
241
+ print(f"Tweet {tweet_id} is liked: {await twitter_client.like(tweet_id)}")
242
+
243
+ # Репост (ретвит)
244
+ print(f"Tweet {tweet_id} is retweeted. Tweet id: {await twitter_client.repost(tweet_id)}")
245
+
246
+ # Коммент (реплай)
247
+ print(f"Tweet {tweet_id} is replied. Reply id: {await twitter_client.reply(tweet_id, 'tem razão')}")
248
+ ```
249
+
250
+ #### Цитата
251
+ ```python
252
+ tweet_url = 'https://twitter.com/CreamIce_Cone/status/1691735090529976489'
253
+ # Цитата (Quote tweet)
254
+ quote_tweet_id = await twitter_client.quote(tweet_url, 'oh....')
255
+ print(f"Quoted! Tweet id: {quote_tweet_id}")
256
+ ```
257
+
258
+ #### Подписка и отписка
259
+ ```python
260
+ # Подписываемся на Илона Маска
261
+ print(f"@{elonmusk.username} is followed: {await twitter_client.follow(elonmusk.id)}")
262
+
263
+ # Отписываемся от Илона Маска
264
+ print(f"@{elonmusk.username} is unfollowed: {await twitter_client.unfollow(elonmusk.id)}")
265
+ ```
266
+
267
+ #### Закрепление твита
268
+ ```python
269
+ pinned = await twitter_client.pin_tweet(tweet_id)
270
+ print(f"Tweet is pined: {pinned}")
271
+ ```
272
+
273
+ #### Запрос своих и чужих подписчиков
274
+ ```python
275
+
276
+ followers = await twitter_client.request_followers()
277
+ print("Твои подписчики:")
278
+ for user in followers:
279
+ print(user)
280
+
281
+ followings = await twitter_client.request_followings()
282
+ print(f"Ты подписан на:")
283
+ for user in followings:
284
+ print(user)
285
+
286
+ bro_followers = await twitter_client.request_followers(bro_id)
287
+ print(f"Подписчики твоего бро (id={bro_id}):")
288
+ for user in bro_followers:
289
+ print(user)
290
+
291
+ bro_followings = await twitter_client.request_followings(bro_id)
292
+ print(f"На твоего бро (id={bro_id}) подписаны:")
293
+ for user in bro_followings:
294
+ print(user)
295
+ ```
296
+
297
+ #### Голосование
298
+ ```python
299
+ vote_data = await twitter_client.vote(tweet_id, card_id, choice_number)
300
+ votes_count = vote_data["card"]["binding_values"]["choice1_count"]["string_value"]
301
+ print(f"Votes: {votes_count}")
302
+ ```
303
+
304
+ Так как мне почти не приходилось работать с голосованиями, я еще не сделал для этого удобных моделей.
305
+ Поэтому приходится работать со словарем.
306
+
@@ -4,20 +4,20 @@ twitter/_capsolver/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
4
4
  twitter/_capsolver/core/base.py,sha256=In3qDLgRh1z1UZLaLFgYcDEdnqW3d62PVzgEjU2S4BU,8883
5
5
  twitter/_capsolver/core/config.py,sha256=8_eXT6N2hBheN2uCMNhqk8tLZRJjLDTYLK208fqIkhM,1054
6
6
  twitter/_capsolver/core/enum.py,sha256=ivfAEN6jrg3iaq5C3H7CuRqsvOloX1b8lF8cLa3zaiY,1741
7
- twitter/_capsolver/core/serializer.py,sha256=2KuZ84VRUQp86iE386qUxReJryFIHnqueRGQUJDQadk,2616
7
+ twitter/_capsolver/core/serializer.py,sha256=xPEUIPgytuw2wM1ubTY3RMhJGVyp_d3bokPTx0BjF0c,2602
8
8
  twitter/_capsolver/fun_captcha.py,sha256=VVbTmn08cGnvPMGdJmPxaLfAIPxyA68oTSAyEL8RWnU,10974
9
- twitter/account.py,sha256=kczlNN3YQcfec7eB1DKDbjn4zmZfJPl3e5o-70IFPFA,3142
9
+ twitter/account.py,sha256=joAB5Zw-Le5E3kOZ-1nb4DPGlTqWYv2Vs6gJ3cwu7is,3175
10
10
  twitter/base/__init__.py,sha256=Q2ko0HeOS5tiBnDVKxxaZYetwRR3YXJ67ujL3oThGd4,141
11
- twitter/base/client.py,sha256=4z_keQnr8YxqRCsWfilQViGDKHulCZ_YBU1fEOr0AnE,482
11
+ twitter/base/client.py,sha256=J_iL4ZGfwTbZ2gpjtFCbBxNgt7weJ55EeMGzYsLtjf4,500
12
12
  twitter/base/session.py,sha256=JFPS-9Qae1iY3NfNcywxvWWmRDijaU_Rjs3WaQ00iFA,2071
13
- twitter/client.py,sha256=hLMW20v3hSPwOPwoXNUbNFFOWmlqG77jt02VGUKoQDU,64199
13
+ twitter/client.py,sha256=VZ9cymxz1KMSaqVTTFfCfuC1c5xZHdRUOD0XENSf53w,75555
14
14
  twitter/enums.py,sha256=-OH6Ibxarq5qt4E2AhkProVawcEyIf5YG_h_G5xiV9Y,270
15
- twitter/errors.py,sha256=NuoHmYz97VwXU1RWAaNELXR69snpwnCtFH0bII1hHyo,5088
16
- twitter/models.py,sha256=3KtyNHm6GGMiapk8I4jUmbnfrRTMBCFvN4g4dEW99tI,4985
15
+ twitter/errors.py,sha256=oNa0Neos80ZK4-0FBzqgxXonH564qFnoN-kavHalfR4,5274
16
+ twitter/models.py,sha256=CrGb3dvA0U4PfPTkUtuprPKXpqkLpM8AR_-De4D3efM,5677
17
17
  twitter/utils/__init__.py,sha256=usxpfcRQ7zxTTgZ-i425tT7hIz73Pwh9FDj4t6O3dYg,663
18
18
  twitter/utils/file.py,sha256=Sz2KEF9DnL04aOP1XabuMYMMF4VR8dJ_KWMEVvQ666Y,1120
19
- twitter/utils/html.py,sha256=hVtIRFI2yRAdWEaShFNBG-_ZWxd16og8i8OVDnFy5Hc,1971
19
+ twitter/utils/html.py,sha256=nrOJw0vUKfBaHgFaQSQIdXfvfZ8mdu84MU_s46kJTJ4,2087
20
20
  twitter/utils/other.py,sha256=9RIYF2AMdmNKIwClG3jBP7zlvxZPEgYfuHaIiOhURzM,1061
21
- tweepy_self-1.9.0.dist-info/METADATA,sha256=LgnHHwoM-zyQF9l-XTR58GuHMXiVR_QHEOWGnUm-jDg,9437
22
- tweepy_self-1.9.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
23
- tweepy_self-1.9.0.dist-info/RECORD,,
21
+ tweepy_self-1.10.0.dist-info/METADATA,sha256=VxhYCaJLHUnrJTKxD8tnFVPtm8lTFCi0qQTG2wDXewo,13287
22
+ tweepy_self-1.10.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
23
+ tweepy_self-1.10.0.dist-info/RECORD,,
@@ -45,7 +45,7 @@ class CaptchaResponseSer(ResponseSer):
45
45
  solution: Dict[str, Any] = Field(None, description="Task result data. Different for each type of task.")
46
46
 
47
47
  class Config:
48
- allow_population_by_field_name = True
48
+ populate_by_name = True
49
49
 
50
50
 
51
51
  class ControlResponseSer(ResponseSer):
twitter/account.py CHANGED
@@ -12,11 +12,11 @@ from .models import User
12
12
  class Account(User):
13
13
  # fmt: off
14
14
  auth_token: str | None = Field(default=None, pattern=r"^[a-f0-9]{40}$")
15
- ct0: str | None = None
16
- password: str | None = None
17
- email: str | None = None
18
- totp_secret: str | None = None
19
- backup_code: str | None = None
15
+ ct0: str | None = None # 160
16
+ password: str | None = None # 128
17
+ email: str | None = None # 254
18
+ totp_secret: str | None = None # 16
19
+ backup_code: str | None = None # 12
20
20
  status: AccountStatus = AccountStatus.UNKNOWN
21
21
  # fmt: on
22
22
 
twitter/base/client.py CHANGED
@@ -14,7 +14,7 @@ class BaseHTTPClient:
14
14
  return self
15
15
 
16
16
  async def __aexit__(self, *args):
17
- self.close()
17
+ await self.close()
18
18
 
19
- def close(self):
20
- self._session.close()
19
+ async def close(self):
20
+ await self._session.close()