fix infinite loop on login for non exists account (#132, #165)

Этот коммит содержится в:
Vlad Pronsky 2024-04-17 00:32:42 +03:00
родитель 9f34f03700
Коммит 728ff6ab69
6 изменённых файлов: 21 добавлений и 32 удалений

Просмотреть файл

@ -1 +0,0 @@
python 3.12.0

Просмотреть файл

@ -2,6 +2,7 @@
This example shows how to use twscrape to complete some queries in parallel. This example shows how to use twscrape to complete some queries in parallel.
To limit the number of concurrent requests, see examples/parallel_search_with_limit.py To limit the number of concurrent requests, see examples/parallel_search_with_limit.py
""" """
import asyncio import asyncio
import twscrape import twscrape

Просмотреть файл

@ -1,6 +1,7 @@
""" """
This example shows how to use twscrape in parallel with concurrency limit. This example shows how to use twscrape in parallel with concurrency limit.
""" """
import asyncio import asyncio
import time import time

Просмотреть файл

@ -5,6 +5,7 @@ from datetime import datetime, timezone
from typing import TypedDict from typing import TypedDict
from fake_useragent import UserAgent from fake_useragent import UserAgent
from httpx import HTTPStatusError
from .account import Account from .account import Account
from .db import execute, fetchall, fetchone from .db import execute, fetchall, fetchone
@ -144,8 +145,12 @@ class AccountsPool:
await login(account, cfg=self._login_config) await login(account, cfg=self._login_config)
logger.info(f"Logged in to {account.username} successfully") logger.info(f"Logged in to {account.username} successfully")
return True return True
except HTTPStatusError as e:
rep = e.response
logger.error(f"Failed to login '{account.username}': {rep.status_code} - {rep.text}")
return False
except Exception as e: except Exception as e:
logger.error(f"Failed to login to {account.username}: {e}") logger.error(f"Failed to login '{account.username}': {e}")
return False return False
finally: finally:
await self.save(account) await self.save(account)

Просмотреть файл

@ -3,12 +3,12 @@ from dataclasses import dataclass
from datetime import timedelta from datetime import timedelta
from typing import Any from typing import Any
from httpx import AsyncClient, HTTPStatusError, Response from httpx import AsyncClient, Response
from .account import Account from .account import Account
from .imap import imap_get_email_code, imap_login from .imap import imap_get_email_code, imap_login
from .logger import logger from .logger import logger
from .utils import raise_for_status, utc from .utils import utc
LOGIN_URL = "https://api.twitter.com/1.1/onboarding/task.json" LOGIN_URL = "https://api.twitter.com/1.1/onboarding/task.json"
@ -30,7 +30,7 @@ class TaskCtx:
async def get_guest_token(client: AsyncClient): async def get_guest_token(client: AsyncClient):
rep = await client.post("https://api.twitter.com/1.1/guest/activate.json") rep = await client.post("https://api.twitter.com/1.1/guest/activate.json")
raise_for_status(rep, "guest_token (most likely ip ban)") rep.raise_for_status()
return rep.json()["guest_token"] return rep.json()["guest_token"]
@ -43,7 +43,7 @@ async def login_initiate(client: AsyncClient) -> Response:
} }
rep = await client.post(LOGIN_URL, params={"flow_name": "login"}, json=payload) rep = await client.post(LOGIN_URL, params={"flow_name": "login"}, json=payload)
raise_for_status(rep, "login_initiate") rep.raise_for_status()
return rep return rep
@ -59,7 +59,7 @@ async def login_alternate_identifier(ctx: TaskCtx, *, username: str) -> Response
} }
rep = await ctx.client.post(LOGIN_URL, json=payload) rep = await ctx.client.post(LOGIN_URL, json=payload)
raise_for_status(rep, "login_alternate_identifier") rep.raise_for_status()
return rep return rep
@ -75,7 +75,7 @@ async def login_instrumentation(ctx: TaskCtx) -> Response:
} }
rep = await ctx.client.post(LOGIN_URL, json=payload) rep = await ctx.client.post(LOGIN_URL, json=payload)
raise_for_status(rep, "login_instrumentation") rep.raise_for_status()
return rep return rep
@ -99,7 +99,7 @@ async def login_enter_username(ctx: TaskCtx) -> Response:
} }
rep = await ctx.client.post(LOGIN_URL, json=payload) rep = await ctx.client.post(LOGIN_URL, json=payload)
raise_for_status(rep, "login_username") rep.raise_for_status()
return rep return rep
@ -115,7 +115,7 @@ async def login_enter_password(ctx: TaskCtx) -> Response:
} }
rep = await ctx.client.post(LOGIN_URL, json=payload) rep = await ctx.client.post(LOGIN_URL, json=payload)
raise_for_status(rep, "login_password") rep.raise_for_status()
return rep return rep
@ -131,7 +131,7 @@ async def login_duplication_check(ctx: TaskCtx) -> Response:
} }
rep = await ctx.client.post(LOGIN_URL, json=payload) rep = await ctx.client.post(LOGIN_URL, json=payload)
raise_for_status(rep, "login_duplication_check") rep.raise_for_status()
return rep return rep
@ -147,7 +147,7 @@ async def login_confirm_email(ctx: TaskCtx) -> Response:
} }
rep = await ctx.client.post(LOGIN_URL, json=payload) rep = await ctx.client.post(LOGIN_URL, json=payload)
raise_for_status(rep, "login_confirm_email") rep.raise_for_status()
return rep return rep
@ -174,7 +174,7 @@ async def login_confirm_email_code(ctx: TaskCtx):
} }
rep = await ctx.client.post(LOGIN_URL, json=payload) rep = await ctx.client.post(LOGIN_URL, json=payload)
raise_for_status(rep, "login_confirm_email") rep.raise_for_status()
return rep return rep
@ -185,7 +185,7 @@ async def login_success(ctx: TaskCtx) -> Response:
} }
rep = await ctx.client.post(LOGIN_URL, json=payload) rep = await ctx.client.post(LOGIN_URL, json=payload)
raise_for_status(rep, "login_success") rep.raise_for_status()
return rep return rep
@ -245,12 +245,7 @@ async def login(acc: Account, cfg: LoginConfig | None = None) -> Account:
if not rep: if not rep:
break break
try: rep = await next_login_task(ctx, rep)
rep = await next_login_task(ctx, rep)
except HTTPStatusError as e:
if e.response.status_code == 403:
logger.error(f"403 error {log_id}")
return acc
client.headers["x-csrf-token"] = client.cookies["ct0"] client.headers["x-csrf-token"] = client.cookies["ct0"]
client.headers["x-twitter-auth-type"] = "OAuth2Session" client.headers["x-twitter-auth-type"] = "OAuth2Session"

Просмотреть файл

@ -4,10 +4,6 @@ from collections import defaultdict
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Any, AsyncGenerator, Callable, TypeVar from typing import Any, AsyncGenerator, Callable, TypeVar
from httpx import HTTPStatusError, Response
from .logger import logger
T = TypeVar("T") T = TypeVar("T")
@ -32,14 +28,6 @@ async def gather(gen: AsyncGenerator[T, None]) -> list[T]:
return items return items
def raise_for_status(rep: Response, label: str):
try:
rep.raise_for_status()
except HTTPStatusError as e:
logger.warning(f"{label} - {rep.status_code} - {rep.text}")
raise e
def encode_params(obj: dict): def encode_params(obj: dict):
res = {} res = {}
for k, v in obj.items(): for k, v in obj.items():