「利用者:夜泣き/スクリプト」の版間の差分

→‎コード: 詳細なログをファイルにも出力するように変更
>Fet-Fe
(→‎コード: v4.1.13 異常終了時にそれまで収集したツイートを残すように修正)
>Fet-Fe
(→‎コード: 詳細なログをファイルにも出力するように変更)
11行目: 11行目:
"""Twitter自動収集スクリプト
"""Twitter自動収集スクリプト


ver4.1.13 2024/1/28恒心
ver4.1.14 2024/2/3恒心


当コードは恒心停止してしまった https://rentry.co/7298g の降臨ショーツイート自動収集スクリプトの復刻改善版です
当コードは恒心停止してしまった https://rentry.co/7298g の降臨ショーツイート自動収集スクリプトの復刻改善版です
78行目: 78行目:
from traceback import TracebackException
from traceback import TracebackException
from types import FrameType, MappingProxyType, TracebackType
from types import FrameType, MappingProxyType, TracebackType
from typing import (Final, NamedTuple, NoReturn, Self, assert_never, final,
from typing import (Final, NamedTuple, NoReturn, Self, TextIO, assert_never,
                    override)
                    final, override)
from urllib.parse import (ParseResult, parse_qs, quote, unquote, urljoin,
from urllib.parse import (ParseResult, parse_qs, quote, unquote, urljoin,
                           urlparse)
                           urlparse)
94行目: 94行目:
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support.wait import WebDriverWait
logging.basicConfig(format='{asctime} [{levelname:.4}] : {message}', style='{')
logger: Final[logging.Logger] = logging.getLogger(__name__)
logger.setLevel(logging.INFO)  # basicConfigで設定するとモジュールのDEBUGログなども出力される




112行目: 108行目:
     filename: Final[str] = 'tweet.txt'
     filename: Final[str] = 'tweet.txt'
     """Final[str]: ツイートを保存するファイルの名前。
     """Final[str]: ツイートを保存するファイルの名前。
    """
    log_file: Final[str] = 'twitter_archiver.log'
    """Final[str]: ログを保存するファイルの名前。
     """
     """


156行目: 156行目:
         """
         """


         incremented_num_default: Final[int] = 5
         incremented_num_default: Final[int] = 6
         """Final[int]: ツイートURLの数字部分うち、インクリメントする桁のデフォルト値。
         """Final[int]: ツイートURLの数字部分うち、インクリメントする桁のデフォルト値。


166行目: 166行目:
         """Final[str]: URLのリストをダンプするファイル名。
         """Final[str]: URLのリストをダンプするファイル名。
         """
         """
# ログ設定
# basicConfigでレベルを設定するとモジュールのDEBUGログなども出力される
formatter: Final[logging.Formatter] = logging.Formatter(
    fmt='{asctime} [{levelname:.4}] : {message}', style='{')
logger: Final[logging.Logger] = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 標準エラー出力へのログ出力
stream_handler: Final[logging.StreamHandler[TextIO]] = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)
# ファイルへのログ出力
file_handler: Final[logging.FileHandler] = (
    logging.FileHandler(UserProperties.log_file))
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)




244行目: 263行目:
     HEADERS: Final[dict[str, str]] = {
     HEADERS: Final[dict[str, str]] = {
         'User-Agent':
         'User-Agent':
             'Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/120.0'
             'Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/120.0' # noqa: E501
     }
     }
     """Final[dict[str, str]]: HTTPリクエスト時のヘッダ。
     """Final[dict[str, str]]: HTTPリクエスト時のヘッダ。
421行目: 440行目:
             self.TOR_BROWSER_PATHS[platform.system()]
             self.TOR_BROWSER_PATHS[platform.system()]
         )
         )
         self._options.add_argument('--user-data-dir=selenium')  # type: ignore
         self._options.add_argument('--user-data-dir=selenium')  # pyright: ignore [reportUnknownMemberType] # noqa: E501


         if enable_javascript:
         if enable_javascript:
             logger.warning('reCAPTCHA対策のためJavaScriptをonにしますを')
             logger.warning('reCAPTCHA対策のためJavaScriptをonにしますを')


         self._options.preferences.update({  # type: ignore
         self._options.preferences.update({  # pyright: ignore [reportUnknownMemberType] # noqa: E501
             'javascript.enabled': enable_javascript,
             'javascript.enabled': enable_javascript,
             'intl.accept_languages': 'en-US, en',
             'intl.accept_languages': 'en-US, en',
478行目: 497行目:


         if len(self._driver.find_elements(By.ID, 'g-recaptcha')) > 0:
         if len(self._driver.find_elements(By.ID, 'g-recaptcha')) > 0:
             if self._options.preferences.get('javascript.enabled'):  # type: ignore
             if self._options.preferences.get('javascript.enabled'):  # pyright: ignore[reportUnknownMemberType] # noqa: E501
                 logger.warning(f'{url} でreCAPTCHAが要求されたナリ')
                 logger.warning(f'{url} でreCAPTCHAが要求されたナリ')
                 print('reCAPTCHAを解いてね(笑)、それはできるよね。')
                 print('reCAPTCHAを解いてね(笑)、それはできるよね。')
532行目: 551行目:
     def set_cookies(self, cookies: dict[str, str]) -> None:
     def set_cookies(self, cookies: dict[str, str]) -> None:
         for name, value in cookies.items():
         for name, value in cookies.items():
             self._driver.add_cookie(  # type: ignore
             self._driver.add_cookie(  # pyright: ignore [reportUnknownMemberType] # noqa: E501
                 {'name': name, 'value': value})
                 {'name': name, 'value': value})
         self._driver.refresh()
         self._driver.refresh()
956行目: 975行目:
     """
     """


     ARCHIVE_TODAY: Final[str] = 'http://archiveiya74codqgiixo33q62qlrqtkgmcitqx5u2oeqnmn5bpcbiyd.onion/'
     ARCHIVE_TODAY: Final[str] = 'http://archiveiya74codqgiixo33q62qlrqtkgmcitqx5u2oeqnmn5bpcbiyd.onion/' # noqa: E501
     """Final[str]: archive.todayの魚拓のonionドメイン。
     """Final[str]: archive.todayの魚拓のonionドメイン。


1,468行目: 1,487行目:
                         logger.error(f'{tweet_url}の動画が取得できませんでしたを 当職無能')
                         logger.error(f'{tweet_url}の動画が取得できませんでしたを 当職無能')
                         media_list.append('[[ファイル:(動画の取得ができませんでした)|240px]]')
                         media_list.append('[[ファイル:(動画の取得ができませんでした)|240px]]')
                     case _ as unreachable:  # pyright: ignore [reportUnnecessaryComparison]
                     case _ as unreachable:  # pyright: ignore[reportUnnecessaryComparison] # noqa: E501
                         assert_never(unreachable)
                         assert_never(unreachable)


2,343行目: 2,362行目:
                         account_name_tag: Final[Tag | None] = (
                         account_name_tag: Final[Tag | None] = (
                             retweet_tag.select_one(
                             retweet_tag.select_one(
                                 'div[data-testid="User-Name"] div[tabindex="-1"]'))
                                 'div[data-testid="User-Name"] div[tabindex="-1"]')) # noqa: E501
                         assert account_name_tag is not None
                         assert account_name_tag is not None
                         text = self._concat_texts(
                         text = self._concat_texts(
2,421行目: 2,440行目:
if __name__ == '__main__':
if __name__ == '__main__':
     if sys.version_info < (3, 12):
     if sys.version_info < (3, 12):
        print('Pythonのバージョンを3.12以上に上げて下さい')
         logger.critical('貴職のPythonのバージョン: ' + str(sys.version_info))
         logger.critical('貴職のPythonのバージョン: ' + str(sys.version_info))
         sys.exit(1)
         sys.exit('Pythonのバージョンを3.12以上に上げて下さい')
     parser: Final[ArgumentParser] = ArgumentParser()
     parser: Final[ArgumentParser] = ArgumentParser()
     parser.add_argument(
     parser.add_argument(
匿名利用者