tweepy-self 1.2.1__py3-none-any.whl → 1.3.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.
@@ -1,15 +1,15 @@
|
|
1
1
|
twitter/__init__.py,sha256=hdrsdbH_qFhx6ro1ct79qF9SpkgFhxgbYUw9A4RVuec,684
|
2
|
-
twitter/account.py,sha256=
|
2
|
+
twitter/account.py,sha256=jneBaUSQ8dfHjOZFvs0qhVNg6EM6ChFIg6-Ee7DWXXM,3278
|
3
3
|
twitter/base/__init__.py,sha256=x0EHKv4q_FI6xEq2nL4V9s8P6VWr6IaHTqdH9sXB5d8,133
|
4
4
|
twitter/base/client.py,sha256=7byb0Psai-dvg_ww6Y7uyE2hV1pfTU653hFgVdRiqXo,478
|
5
5
|
twitter/base/session.py,sha256=5aMjCytV_cu-uouccJzjMUPIgXZwMElPkqb7FCawmfg,2055
|
6
|
-
twitter/client.py,sha256=
|
7
|
-
twitter/errors.py,sha256=
|
6
|
+
twitter/client.py,sha256=WvwxVd273LjPtuyMPX69j42fJNxsK5nVFI4W4YACE1s,53674
|
7
|
+
twitter/errors.py,sha256=2Co_XtXk9KwKVL89MyMIzRUT9Jaoy6hwzHxrokEOuAs,4122
|
8
8
|
twitter/models.py,sha256=3-Lft160msCqOjRPubOmxMqWUkmjlTSzHSGsvZK91nU,1817
|
9
9
|
twitter/utils/__init__.py,sha256=pyhQXwTdp0HFwV_UNF4dTyklLD9RtaefA16SrQXeNlg,589
|
10
10
|
twitter/utils/file.py,sha256=-6n8I8KWDlntfciJJsfIeOi0gmqoHRIe1ldIx1ynGUE,1118
|
11
11
|
twitter/utils/html.py,sha256=Cs55MxVyZLSKiCEj11ALUrnCW9ADZ4CEDCE0gKESzO0,1627
|
12
12
|
twitter/utils/other.py,sha256=4NaGd2CIJVrDiW17shcrDlJRqFkQNbBSTiiH7kNWcww,559
|
13
|
-
tweepy_self-1.
|
14
|
-
tweepy_self-1.
|
15
|
-
tweepy_self-1.
|
13
|
+
tweepy_self-1.3.0.dist-info/METADATA,sha256=a4Iwl5zvqRiA3lFSvY_3eLnoVPLVDNccmk9R3wNIuNM,9139
|
14
|
+
tweepy_self-1.3.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
15
|
+
tweepy_self-1.3.0.dist-info/RECORD,,
|
twitter/account.py
CHANGED
@@ -21,14 +21,14 @@ class AccountStatus(enum.StrEnum):
|
|
21
21
|
|
22
22
|
class Account(BaseModel):
|
23
23
|
auth_token: str | None = Field(default=None, pattern=r"^[a-f0-9]{40}$")
|
24
|
-
ct0: str | None
|
25
|
-
id: int | None
|
26
|
-
name: str | None
|
27
|
-
username: str | None
|
28
|
-
password: str | None
|
29
|
-
email: str | None
|
30
|
-
totp_secret: str | None =
|
31
|
-
backup_code: str | None =
|
24
|
+
ct0: str | None = None
|
25
|
+
id: int | None = None
|
26
|
+
name: str | None = None
|
27
|
+
username: str | None = None
|
28
|
+
password: str | None = None
|
29
|
+
email: str | None = None
|
30
|
+
totp_secret: str | None = None
|
31
|
+
backup_code: str | None = None
|
32
32
|
status: AccountStatus = AccountStatus.UNKNOWN
|
33
33
|
|
34
34
|
@property
|
twitter/client.py
CHANGED
@@ -36,7 +36,7 @@ class Client(BaseClient):
|
|
36
36
|
'authority': 'twitter.com',
|
37
37
|
'origin': 'https://twitter.com',
|
38
38
|
'x-twitter-active-user': 'yes',
|
39
|
-
|
39
|
+
'x-twitter-auth-type': 'OAuth2Session',
|
40
40
|
'x-twitter-client-language': 'en',
|
41
41
|
}
|
42
42
|
_GRAPHQL_URL = 'https://twitter.com/i/api/graphql'
|
@@ -73,11 +73,15 @@ class Client(BaseClient):
|
|
73
73
|
account: Account,
|
74
74
|
*,
|
75
75
|
wait_on_rate_limit: bool = True,
|
76
|
+
capsolver_api_key: str = None,
|
77
|
+
max_unlock_attempts: int = 4,
|
76
78
|
**session_kwargs,
|
77
79
|
):
|
78
80
|
super().__init__(**session_kwargs)
|
79
81
|
self.account = account
|
80
82
|
self.wait_on_rate_limit = wait_on_rate_limit
|
83
|
+
self.capsolver_api_key = capsolver_api_key
|
84
|
+
self.max_unlock_attempts = max_unlock_attempts
|
81
85
|
|
82
86
|
async def request(
|
83
87
|
self,
|
@@ -148,7 +152,11 @@ class Client(BaseClient):
|
|
148
152
|
|
149
153
|
if 326 in exc.api_codes:
|
150
154
|
self.account.status = AccountStatus.LOCKED
|
151
|
-
|
155
|
+
if not self.capsolver_api_key:
|
156
|
+
raise Locked(self.account)
|
157
|
+
|
158
|
+
await self.unlock()
|
159
|
+
return await self.request(method, url, auth, bearer, **kwargs)
|
152
160
|
|
153
161
|
raise exc
|
154
162
|
|
@@ -170,7 +178,11 @@ class Client(BaseClient):
|
|
170
178
|
|
171
179
|
if 326 in exc.api_codes:
|
172
180
|
self.account.status = AccountStatus.LOCKED
|
173
|
-
|
181
|
+
if not self.capsolver_api_key:
|
182
|
+
raise Locked(self.account)
|
183
|
+
|
184
|
+
await self.unlock()
|
185
|
+
return await self.request(method, url, auth, bearer, **kwargs)
|
174
186
|
|
175
187
|
raise exc
|
176
188
|
|
@@ -722,6 +734,8 @@ class Client(BaseClient):
|
|
722
734
|
is_updated = all(response_json.get(key) == value for key, value in data.items() if key != "url")
|
723
735
|
if website: is_updated &= URL(website) == URL(response_json["entities"]["url"]["urls"][0]["expanded_url"])
|
724
736
|
await self.establish_status() # Изменение данных профиля часто замораживает аккаунт
|
737
|
+
await self.unlock()
|
738
|
+
await self.request_user_data()
|
725
739
|
return is_updated
|
726
740
|
|
727
741
|
async def establish_status(self):
|
@@ -888,11 +902,7 @@ class Client(BaseClient):
|
|
888
902
|
|
889
903
|
return await self.request("POST", self._CAPTCHA_URL, data=payload, bearer=False)
|
890
904
|
|
891
|
-
async def unlock(
|
892
|
-
self,
|
893
|
-
capsolver_api_key: str,
|
894
|
-
attempts: int = 4):
|
895
|
-
await self.establish_status()
|
905
|
+
async def unlock(self):
|
896
906
|
if not self.account.status == "LOCKED":
|
897
907
|
return
|
898
908
|
|
@@ -901,7 +911,7 @@ class Client(BaseClient):
|
|
901
911
|
attempt = 1
|
902
912
|
|
903
913
|
funcaptcha = {
|
904
|
-
"api_key": capsolver_api_key,
|
914
|
+
"api_key": self.capsolver_api_key,
|
905
915
|
"websiteURL": self._CAPTCHA_URL,
|
906
916
|
"websitePublicKey": self._CAPTCHA_SITE_KEY,
|
907
917
|
}
|
@@ -921,7 +931,7 @@ class Client(BaseClient):
|
|
921
931
|
response, html = await self._confirm_unlock(authenticity_token, assignment_token,
|
922
932
|
verification_string=token)
|
923
933
|
|
924
|
-
if attempt >
|
934
|
+
if attempt > self.max_unlock_attempts or response.url == "https://twitter.com/?lang=en":
|
925
935
|
await self.establish_status()
|
926
936
|
return
|
927
937
|
|
@@ -1034,10 +1044,6 @@ class Client(BaseClient):
|
|
1034
1044
|
return await self._send_task(flow_token, subtask_inputs, auth=False)
|
1035
1045
|
|
1036
1046
|
async def _viewer(self):
|
1037
|
-
"""
|
1038
|
-
Здесь нужно забрать ct0
|
1039
|
-
:return:
|
1040
|
-
"""
|
1041
1047
|
url, query_id = self._action_to_url("Viewer")
|
1042
1048
|
features = {
|
1043
1049
|
'responsive_web_graphql_exclude_directive_enabled': True,
|
@@ -1066,6 +1072,8 @@ class Client(BaseClient):
|
|
1066
1072
|
"""
|
1067
1073
|
url = 'https://twitter.com'
|
1068
1074
|
response = await self._session.request("GET", url)
|
1075
|
+
# TODO Если в сессии есть рабочий auth_token, то не вернет нужную страницу.
|
1076
|
+
# Поэтому нужно очищать сессию перед вызовом этого метода.
|
1069
1077
|
guest_token = re.search(r'gt\s?=\s?\d+', response.text)[0].split('=')[1]
|
1070
1078
|
return guest_token
|
1071
1079
|
|
twitter/errors.py
CHANGED
@@ -41,7 +41,7 @@ class BadToken(BadAccount):
|
|
41
41
|
|
42
42
|
class Locked(BadAccount):
|
43
43
|
def __init__(self, account: Account):
|
44
|
-
exception_message = f"Twitter account is locked.
|
44
|
+
exception_message = (f"Twitter account is locked. Paste CapSolver API key into Client instance to autounlock.")
|
45
45
|
super().__init__(account, custom_exception_message=exception_message)
|
46
46
|
|
47
47
|
|
File without changes
|