fix: tighten pagination and platform-specific auth

This commit is contained in:
jackwener
2026-03-11 20:32:51 +08:00
parent 74f06638ee
commit 88a9f4ce97
7 changed files with 139 additions and 13 deletions

View File

@@ -189,7 +189,7 @@ def _extract_cookies_from_jar(jar: Any, source: str = "unknown") -> Optional[Dic
_CHROMIUM_BASE_DIRS: Dict[str, str] = {
"chrome": os.path.join("Google", "Chrome"),
"arc": os.path.join("Arc", "User Data"),
"edge": os.path.join("Microsoft Edge"),
"edge": "Microsoft Edge",
"brave": os.path.join("BraveSoftware", "Brave-Browser"),
}
@@ -207,9 +207,15 @@ def _iter_chrome_cookie_files(browser_name: str) -> List[str]:
if sys.platform == "darwin":
root = os.path.join(os.path.expanduser("~"), "Library", "Application Support", base_dir)
elif sys.platform == "win32":
root = os.path.join(os.environ.get("LOCALAPPDATA", ""), base_dir, "User Data")
if browser_name == "edge":
root = os.path.join(os.environ.get("LOCALAPPDATA", ""), "Microsoft", "Edge", "User Data")
else:
root = os.path.join(os.environ.get("LOCALAPPDATA", ""), base_dir)
else:
root = os.path.join(os.path.expanduser("~"), ".config", base_dir)
if browser_name == "edge":
root = os.path.join(os.path.expanduser("~"), ".config", "microsoft-edge")
else:
root = os.path.join(os.path.expanduser("~"), ".config", base_dir)
if not os.path.isdir(root):
return []

View File

@@ -30,6 +30,7 @@ from __future__ import annotations
import logging
import os
import re
import inspect
import sys
import time
import urllib.parse
@@ -148,9 +149,13 @@ def _get_client_for_output(config=None, quiet=False):
# type: (Optional[Dict[str, Any]], bool) -> TwitterClient
"""Call _get_client while staying compatible with monkeypatched legacy signatures."""
try:
signature = inspect.signature(_get_client)
except (TypeError, ValueError):
signature = None
if signature and "quiet" in signature.parameters:
return _get_client(config, quiet=quiet)
except TypeError:
return _get_client(config)
return _get_client(config)
def _exit_with_error(exc):

View File

@@ -18,16 +18,16 @@ from x_client_transaction.utils import generate_headers as _gen_ct_headers, get_
from .constants import (
BEARER_TOKEN,
SEC_CH_UA_ARCH,
SEC_CH_UA_BITNESS,
SEC_CH_UA_MOBILE,
SEC_CH_UA_MODEL,
SEC_CH_UA_PLATFORM_VERSION,
get_accept_language,
get_sec_ch_ua_arch,
get_sec_ch_ua,
get_sec_ch_ua_full_version,
get_sec_ch_ua_full_version_list,
get_sec_ch_ua_platform,
get_sec_ch_ua_platform_version,
get_twitter_client_language,
get_user_agent,
sync_chrome_version,
@@ -645,10 +645,16 @@ class TwitterClient:
seen_ids.add(user.id)
users.append(user)
if not next_cursor or not new_users:
if not next_cursor:
break
if next_cursor == cursor:
logger.debug("User list pagination stopped because cursor did not advance: %s", next_cursor)
break
cursor = next_cursor
if not new_users:
logger.debug("User list page returned no users but exposed next cursor; continuing pagination")
if len(users) < count and self._request_delay > 0:
time.sleep(self._request_delay * random.uniform(0.7, 1.5))
@@ -903,12 +909,12 @@ class TwitterClient:
"sec-ch-ua": get_sec_ch_ua(),
"sec-ch-ua-mobile": SEC_CH_UA_MOBILE,
"sec-ch-ua-platform": get_sec_ch_ua_platform(),
"sec-ch-ua-arch": SEC_CH_UA_ARCH,
"sec-ch-ua-arch": get_sec_ch_ua_arch(),
"sec-ch-ua-bitness": SEC_CH_UA_BITNESS,
"sec-ch-ua-full-version": get_sec_ch_ua_full_version(),
"sec-ch-ua-full-version-list": get_sec_ch_ua_full_version_list(),
"sec-ch-ua-model": SEC_CH_UA_MODEL,
"sec-ch-ua-platform-version": SEC_CH_UA_PLATFORM_VERSION,
"sec-ch-ua-platform-version": get_sec_ch_ua_platform_version(),
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",

View File

@@ -95,13 +95,32 @@ def get_sec_ch_ua_platform():
return '"Linux"'
def get_sec_ch_ua_arch():
# type: () -> str
machine = (os.uname().machine if hasattr(os, "uname") else "").lower()
if "arm" in machine or "aarch" in machine:
return '"arm"'
if "86" in machine or "amd64" in machine or "x64" in machine:
return '"x86"'
return '""'
def get_sec_ch_ua_platform_version():
# type: () -> str
if sys.platform == "darwin":
return '"15.0.0"'
if sys.platform.startswith("win"):
return '"10.0.0"'
return '""'
# Static Client Hints
SEC_CH_UA_MOBILE = "?0"
SEC_CH_UA_PLATFORM = get_sec_ch_ua_platform()
SEC_CH_UA_ARCH = '"arm"' if sys.platform == "darwin" else '"x86"'
SEC_CH_UA_ARCH = get_sec_ch_ua_arch()
SEC_CH_UA_BITNESS = '"64"'
SEC_CH_UA_MODEL = '""'
SEC_CH_UA_PLATFORM_VERSION = '"15.0.0"' if sys.platform == "darwin" else '"10.0.0"'
SEC_CH_UA_PLATFORM_VERSION = get_sec_ch_ua_platform_version()
# Legacy aliases — modules that import these get the default value.
# _build_headers() should use get_user_agent() / get_sec_ch_ua() instead.