зеркало из
https://github.com/viginum-datalab/twscrape.git
synced 2025-10-29 21:16:25 +02:00
add login method to account_pool; update readme
Этот коммит содержится в:
родитель
410a1fb9a4
Коммит
01d59b50d6
46
readme.md
46
readme.md
@ -4,21 +4,51 @@ Twitter GraphQL and Search API implementation with [SNScrape](https://github.com
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from twapi.client import UserClient
|
||||
from twapi.pool import AccountsPool
|
||||
from twapi.search import Search
|
||||
from twapi.account import Account
|
||||
from twapi.accounts_pool import AccountsPool
|
||||
from twapi.api import API
|
||||
from twapi.utils import gather
|
||||
|
||||
async def main():
|
||||
acc1 = UserClient("user1", "pass1", "user1@example.com", "email_pass1")
|
||||
acc2 = UserClient("user2", "pass2", "user2@example.com", "email_pass2")
|
||||
acc1 = Account("user1", "pass1", "user1@example.com", "email_pass1")
|
||||
acc2 = Account("user2", "pass2", "user2@example.com", "email_pass2")
|
||||
|
||||
pool = AccountsPool()
|
||||
pool.add_account(acc1)
|
||||
pool.add_account(acc2)
|
||||
|
||||
search = Search(pool)
|
||||
async for rep in search.query("elon musk"):
|
||||
print(rep.status_code, rep.json())
|
||||
# login all accounts if required (not account file found)
|
||||
# session file will be saved to `accounts/{username}.json`
|
||||
await pool.login()
|
||||
|
||||
api = API(pool)
|
||||
|
||||
# search api
|
||||
await gather(api.search("elon musk", limit=20)) # list[Tweet]
|
||||
|
||||
# graphql api
|
||||
tweet_id = 20
|
||||
user_id, user_login = 2244994945, "twitterdev"
|
||||
|
||||
await api.tweet_details(tweet_id) # Tweet
|
||||
await gather(api.retweeters(tweet_id, limit=20)) # list[User]
|
||||
await gather(api.favoriters(tweet_id, limit=20)) # list[User]
|
||||
|
||||
await api.user_by_id(user_id) # User
|
||||
await api.user_by_login(user_login) # User
|
||||
await gather(api.followers(user_id, limit=20)) # list[User]
|
||||
await gather(api.following(user_id, limit=20)) # list[User]
|
||||
await gather(api.user_tweets(user_id, limit=20)) # list[Tweet]
|
||||
await gather(api.user_tweets_and_replies(user_id, limit=20)) # list[Tweet]
|
||||
|
||||
# note 1: limit is optional, default is -1 (no limit)
|
||||
# note 2: all methods have `raw` version e.g.:
|
||||
|
||||
async for tweet in api.search("elon musk"):
|
||||
print(tweet.id, tweet.user.username, tweet.rawContent) # tweet is `Tweet` object
|
||||
|
||||
async for rep in api.search_raw("elon musk"):
|
||||
print(rep.status_code, rep.json()) # rep is `httpx.Response` object
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
|
||||
@ -2,7 +2,7 @@ import asyncio
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from .account import Account
|
||||
from .account import Account, Status
|
||||
|
||||
|
||||
class AccountsPool:
|
||||
@ -12,7 +12,16 @@ class AccountsPool:
|
||||
def add_account(self, account: Account):
|
||||
self.accounts.append(account)
|
||||
|
||||
def get_login_by_token(self, auth_token: str) -> str:
|
||||
async def login(self):
|
||||
for x in self.accounts:
|
||||
try:
|
||||
if x.status == Status.NEW:
|
||||
await x.login()
|
||||
except Exception as e:
|
||||
logger.error(f"Error logging in to {x.username}: {e}")
|
||||
pass
|
||||
|
||||
def get_username_by_token(self, auth_token: str) -> str:
|
||||
for x in self.accounts:
|
||||
if x.client.cookies.get("auth_token") == auth_token:
|
||||
return x.username
|
||||
|
||||
@ -10,7 +10,7 @@ from .models import Tweet, User
|
||||
from .utils import encode_params, find_item, to_old_obj, to_search_like
|
||||
|
||||
|
||||
class Search:
|
||||
class API:
|
||||
def __init__(self, pool: AccountsPool):
|
||||
self.pool = pool
|
||||
|
||||
@ -21,7 +21,7 @@ class Search:
|
||||
ll = rep.headers.get("x-rate-limit-limit", -1)
|
||||
|
||||
auth_token = rep.request.headers["cookie"].split("auth_token=")[1].split(";")[0]
|
||||
username = self.pool.get_login_by_token(auth_token)
|
||||
username = self.pool.get_username_by_token(auth_token)
|
||||
|
||||
return f"{username} {lr}/{ll}"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import json
|
||||
from collections import defaultdict
|
||||
from typing import Any, TypeVar
|
||||
from typing import Any, AsyncGenerator, TypeVar
|
||||
|
||||
from httpx import HTTPStatusError, Response
|
||||
from loguru import logger
|
||||
@ -8,6 +8,13 @@ from loguru import logger
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
async def gather(gen: AsyncGenerator[T, None]) -> list[T]:
|
||||
items = []
|
||||
async for x in gen:
|
||||
items.append(x)
|
||||
return items
|
||||
|
||||
|
||||
def raise_for_status(rep: Response, label: str):
|
||||
try:
|
||||
rep.raise_for_status()
|
||||
|
||||
Загрузка…
x
Ссылка в новой задаче
Block a user