зеркало из
https://github.com/viginum-datalab/twscrape.git
synced 2025-10-29 21:16:25 +02:00
родитель
9f34f03700
Коммит
728ff6ab69
@ -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():
|
||||||
|
|||||||
Загрузка…
x
Ссылка в новой задаче
Block a user