→コード: 詳細なログをファイルにも出力するように変更
>Fet-Fe (→コード: v4.1.13 異常終了時にそれまで収集したツイートを残すように修正) |
>Fet-Fe (→コード: 詳細なログをファイルにも出力するように変更) |
||
11行目: | 11行目: | ||
"""Twitter自動収集スクリプト | """Twitter自動収集スクリプト | ||
ver4.1. | 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, | ||
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 | ||
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] = | 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') # | 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({ # | 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'): # | 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( # | 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): | ||
logger.critical('貴職のPythonのバージョン: ' + str(sys.version_info)) | logger.critical('貴職のPythonのバージョン: ' + str(sys.version_info)) | ||
sys.exit( | sys.exit('Pythonのバージョンを3.12以上に上げて下さい') | ||
parser: Final[ArgumentParser] = ArgumentParser() | parser: Final[ArgumentParser] = ArgumentParser() | ||
parser.add_argument( | parser.add_argument( |