→コード: v4.4.0 -u --krswを指定した時にも上限以内で引っかかった書き込みがあると自動停止する機能を追加
>Fet-Fe (→コード: v4.3.8 動画の取得ロジックを修正) |
>Fet-Fe (→コード: v4.4.0 -u --krswを指定した時にも上限以内で引っかかった書き込みがあると自動停止する機能を追加) |
||
11行目: | 11行目: | ||
"""Twitter自動収集スクリプト | """Twitter自動収集スクリプト | ||
ver4. | ver4.4.0 2024/9/4恒心 | ||
当コードは恒心停止してしまった https://rentry.co/7298g の降臨ショーツイート自動収集スクリプトの復刻改善版です。 | 当コードは恒心停止してしまった https://rentry.co/7298g の降臨ショーツイート自動収集スクリプトの復刻改善版です。 | ||
250行目: | 250行目: | ||
def __init__(self) -> None: | def __init__(self) -> None: | ||
# Torに必要なプロキシをセット | # Torに必要なプロキシをセット | ||
self._cookies: dict[str, str] = {} | self._cookies: dict[str, str] = {} | ||
362行目: | 361行目: | ||
@property | @property | ||
def proxies(self) -> dict[str, str] | None: | def proxies(self) -> dict[str, str] | None: | ||
""" | """dict[str, str] | None: プロキシ設定。""" | ||
return self._proxies | return self._proxies | ||
class SeleniumAccessor(AbstractAccessor): | class SeleniumAccessor(AbstractAccessor): | ||
"""SeleniumでWebサイトに接続するためのクラス。""" | """SeleniumでWebサイトに接続するためのクラス。 | ||
Args: | |||
enable_javascript (bool): JavaScriptを有効にするかどうか。reCAPTCHA対策に必要。 | |||
""" | |||
TOR_BROWSER_PATHS: Final[MappingProxyType[str, str]] = MappingProxyType({ | TOR_BROWSER_PATHS: Final[MappingProxyType[str, str]] = MappingProxyType({ | ||
387行目: | 386行目: | ||
def __init__(self, enable_javascript: bool) -> None: | def __init__(self, enable_javascript: bool) -> None: | ||
self._options: Final[FirefoxOptions] = FirefoxOptions() | self._options: Final[FirefoxOptions] = FirefoxOptions() | ||
self._options.binary_location = ( | self._options.binary_location = ( | ||
521行目: | 513行目: | ||
RequestsとSeleniumのどちらかを選択して使用することができ、その違いを隠蔽する。 | RequestsとSeleniumのどちらかを選択して使用することができ、その違いを隠蔽する。 | ||
Args: | |||
use_browser (bool): `True` ならSeleniumを利用する。`False` ならRequestsのみでアクセスする。 | |||
enable_javascript (bool): SeleniumでJavaScriptを利用する場合は `True`。 | |||
""" | """ | ||
530行目: | 526行目: | ||
def __init__(self, use_browser: bool, enable_javascript: bool) -> None: | def __init__(self, use_browser: bool, enable_javascript: bool) -> None: | ||
self._selenium_accessor: Final[SeleniumAccessor | None] = ( | self._selenium_accessor: Final[SeleniumAccessor | None] = ( | ||
SeleniumAccessor(enable_javascript) if use_browser else None | SeleniumAccessor(enable_javascript) if use_browser else None | ||
546行目: | 533行目: | ||
def __enter__(self) -> Self: | def __enter__(self) -> Self: | ||
return self | return self | ||
557行目: | 539行目: | ||
exc_value: BaseException | None, | exc_value: BaseException | None, | ||
traceback: TracebackType | None) -> None: | traceback: TracebackType | None) -> None: | ||
if self._selenium_accessor is not None: | if self._selenium_accessor is not None: | ||
self._selenium_accessor.quit() | self._selenium_accessor.quit() | ||
688行目: | 663行目: | ||
@property | @property | ||
def last_url(self) -> str: | def last_url(self) -> str: | ||
""" | """str: 最後にアクセスしたURL。""" | ||
return self._last_url | return self._last_url | ||
@property | @property | ||
def proxies(self) -> dict[str, str] | None: | def proxies(self) -> dict[str, str] | None: | ||
""" | """dict[str, str] | None: RequestsAccessorオブジェクトのプロキシ設定。""" | ||
return self._requests_accessor.proxies | return self._requests_accessor.proxies | ||
class TableBuilder: | class TableBuilder: | ||
"""Wikiの表を組み立てるためのクラス。 | """Wikiの表を組み立てるためのクラス。 | ||
Args: | |||
date (datetime | None, optional): 記録するツイートの最新日付。デフォルトは今日の日付。 | |||
""" | |||
FILENAME: Final[str] = UserProperties.filename | FILENAME: Final[str] = UserProperties.filename | ||
"""Final[str]: ツイートを保存するファイルの名前。""" | """Final[str]: ツイートを保存するファイルの名前。""" | ||
def __init__(self, date: datetime | None = None) -> None: | def __init__(self, date: datetime | None = None) -> None: | ||
self._tables: Final[list[str]] = [''] | self._tables: Final[list[str]] = [''] | ||
self._count: int = 0 # 記録数 | self._count: int = 0 # 記録数 | ||
723行目: | 688行目: | ||
@property | @property | ||
def count(self) -> int: | def count(self) -> int: | ||
""" | """int: 表に追加したツイートの件数。""" | ||
return self._count | return self._count | ||
1,013行目: | 974行目: | ||
def __init__(self) -> None: | def __init__(self) -> None: | ||
self._check_constants() # スラッシュが抜けてないかチェック | self._check_constants() # スラッシュが抜けてないかチェック | ||
self._has_ffmpeg: Final[bool] = self._check_ffmpeg() # ffmpegがあるかチェック | self._has_ffmpeg: Final[bool] = self._check_ffmpeg() # ffmpegがあるかチェック | ||
1,023行目: | 983行目: | ||
self._url_query_pattern: Final[re.Pattern[str]] = re.compile(r'\?.*$') | self._url_query_pattern: Final[re.Pattern[str]] = re.compile(r'\?.*$') | ||
def _set_queries(self, accessor: AccessorHandler, krsw: | def _set_queries( | ||
self, accessor: AccessorHandler, krsw: str | None) -> bool: | |||
"""検索条件を設定する。 | """検索条件を設定する。 | ||
1,031行目: | 992行目: | ||
Args: | Args: | ||
accessor (AccessorHandler): アクセスハンドラ | accessor (AccessorHandler): アクセスハンドラ | ||
krsw ( | krsw (str | None): `None` でない場合、名前が :const:`~CALLINSHOW` になり、\ | ||
クエリと終わりにするツイートが無しになる。 | クエリと終わりにするツイートが無しになる。\ | ||
更に空文字でもない場合、この引数が終わりにするツイートになる。 | |||
Returns: | Returns: | ||
1,039行目: | 1,001行目: | ||
# ユーザー名取得 | # ユーザー名取得 | ||
if krsw: | if krsw is not None: | ||
logger.info('名前は自動的に' + self.CALLINSHOW + 'にナリます') | logger.info('名前は自動的に' + self.CALLINSHOW + 'にナリます') | ||
self._name: str = self.CALLINSHOW | self._name: str = self.CALLINSHOW | ||
1,051行目: | 1,013行目: | ||
# 検索クエリとページ取得 | # 検索クエリとページ取得 | ||
self._query_strs: list[str] = [] | self._query_strs: list[str] = [] | ||
if krsw: | if krsw is not None: | ||
logger.info('クエリは自動的になしにナリます') | logger.info('クエリは自動的になしにナリます') | ||
else: | else: | ||
1,072行目: | 1,034行目: | ||
# 終わりにするツイート取得 | # 終わりにするツイート取得 | ||
if krsw: | if krsw == '': | ||
logger.info('終わりにするツイートは自動的になしにナリます') | logger.info('終わりにするツイートは自動的になしにナリます') | ||
self._stop: str = '' | |||
elif krsw is not None: | |||
logger.info(f'終わりにするツイートは自動的に"{krsw}"にナリます') | |||
self._stop: str = krsw | |||
else: | |||
self._stop: str = self._input_stop_word() | |||
logger.info( | logger.info( | ||
1,855行目: | 1,822行目: | ||
'See also: https://nitter.cz' | 'See also: https://nitter.cz' | ||
'\033[0m') | '\033[0m') | ||
def execute(self, krsw: | def execute(self, krsw: str | None = None, use_browser: bool = True, | ||
enable_javascript: bool = True) -> None: | enable_javascript: bool = True) -> None: | ||
"""通信が必要な部分のロジック。 | """通信が必要な部分のロジック。 | ||
Args: | Args: | ||
krsw ( | krsw (str | None, optional): `None` でない場合、名前が自動で \ | ||
:const:`~CALLINSHOW` になり、クエリと終わりにするツイートが自動で無しになる。\ | |||
更に空文字でもない場合、この引数が終わりにするツイートになる。 | |||
use_browser (bool, optional): `True` ならSeleniumを利用する。\ | use_browser (bool, optional): `True` ならSeleniumを利用する。\ | ||
`False` ならRequestsのみでアクセスする。 | `False` ならRequestsのみでアクセスする。 | ||
1,932行目: | 1,900行目: | ||
@override | @override | ||
def _set_queries(self, accessor: AccessorHandler, krsw: | def _set_queries( | ||
self, accessor: AccessorHandler, krsw: str | None) -> bool: | |||
"""検索条件を設定する。 | """検索条件を設定する。 | ||
1,940行目: | 1,909行目: | ||
Args: | Args: | ||
accessor (AccessorHandler): アクセスハンドラ | accessor (AccessorHandler): アクセスハンドラ | ||
krsw ( | krsw (str | None): `None` でない場合、名前が :const:`~CALLINSHOW` になる。 | ||
Returns: | Returns: | ||
1,947行目: | 1,916行目: | ||
# ユーザー名取得 | # ユーザー名取得 | ||
if krsw: | if krsw is not None: | ||
logger.info('名前は自動的に' + self.CALLINSHOW + 'にナリます') | logger.info('名前は自動的に' + self.CALLINSHOW + 'にナリます') | ||
self._name: str = self.CALLINSHOW | self._name: str = self.CALLINSHOW | ||
2,473行目: | 2,442行目: | ||
@override | @override | ||
def execute(self, krsw: | def execute(self, krsw: str | None = None, use_browser: bool = True, | ||
enable_javascript: bool = True) -> None: | enable_javascript: bool = True) -> None: | ||
"""通信が必要な部分のロジック。 | """通信が必要な部分のロジック。 | ||
Args: | Args: | ||
krsw ( | krsw (str | None, optional): `None` でない場合、名前が自動で \ | ||
:const:`~CALLINSHOW` になる。 | |||
use_browser (bool, optional): `True` ならSeleniumを利用する。\ | use_browser (bool, optional): `True` ならSeleniumを利用する。\ | ||
`False` ならRequestsのみでアクセスする。 | `False` ならRequestsのみでアクセスする。 | ||
2,531行目: | 2,500行目: | ||
parser.add_argument( | parser.add_argument( | ||
'--krsw', | '--krsw', | ||
type=str, | |||
help='指定すると、パカデブのツイートを取得上限数まで取得する。') | nargs='?', | ||
const='', | |||
default=None, | |||
help=('指定すると、パカデブのツイートを取得上限数まで取得する。' | |||
'更に--search-unarchivedモードでこのオプションに引数を与えると、' | |||
'その文言が終わりにするツイートになる。')) | |||
parser.add_argument( | parser.add_argument( | ||
'-n', | '-n', |