「利用者:夜泣き/スクリプト」の版間の差分
ナビゲーションに移動
検索に移動
編集の要約なし
>夜泣き 編集の要約なし |
>夜泣き 編集の要約なし |
||
144行目: | 144行目: | ||
print(str(Limit) + "件も記録している。もうやめにしませんか。") | print(str(Limit) + "件も記録している。もうやめにしませんか。") | ||
make_txt(output_txt) | make_txt(output_txt) | ||
--> | |||
<!-- | |||
#!/usr/bin/env python3 | |||
#当コードは恒心停止してしまったhttps://rentry.co/7298gの降臨ショーツイート自動収集スクリプトの復刻改善版です | |||
#前開発者との出会いに感謝 | |||
# | |||
#ーーーーーーーー【注意点】ーーーーーーーーーー | |||
#・玉葱を使用すること。 | |||
#・バグ報告はhttps://krsw-wiki.org/wiki/?curid=15799。 | |||
#インポート類 | |||
import subprocess | |||
import codecs | |||
import re | |||
from time import sleep | |||
import requests | |||
from bs4 import BeautifulSoup as bs4 | |||
from typing import Final | |||
from urllib.parse import quote | |||
#定数類 | |||
##nitterのインスタンス | |||
##生きているのはhttps://github.com/zedeus/nitter/wiki/Instancesで確認 | |||
Nitterinstance = 'http://nitterqdyumlovt7tjqpdjrluitgmtpa53qq3idlpgoe4kxo7gs3xvad.onion/' | |||
##archive.todayの魚拓 | |||
##実際にアクセスして魚拓があるか調べるのにはonionを使用 | |||
Archivetoday = 'http://archiveiya74codqgiixo33q62qlrqtkgmcitqx5u2oeqnmn5bpcbiyd.onion/' | |||
##archive.todayの魚拓 | |||
##記事の文章に使うのはクリアネット | |||
Archivetodaystandard = 'https://archive.ph/' | |||
##降臨ショーのユーザーネーム | |||
Callinshow: Final[str] = 'CallinShow' | |||
##HTTPリクエストのタイムアウト秒数 | |||
Request_timeout: Final[int] = 30 | |||
##取得するツイート数の上限 | |||
Limit_tweet: Final[int] = 400 | |||
##HTTPリクエスト失敗時の再試行回数 | |||
Limit_request: Final[int] = 5 | |||
##HTTPリクエスト失敗時の待機時間 | |||
Waittime: Final[int] = 5 | |||
##nitterのURLのドメインとユーザーネーム部分の接続部品 | |||
Searchquery = "search?q=from%3A" | |||
##HTTPリクエスト時のユーザーエージェントとヘッダ | |||
user_agent = 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0' | |||
header = { | |||
'User-Agent': user_agent | |||
} | |||
##nitterでユーザーがいなかったとき返ってくるページのタイトル | |||
##万が一仕様変更で変わったとき用 | |||
Nitter_error_title = "Error|nitter" | |||
Curlhead = 'torsocks curl -sS -A "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0" ' | |||
Redirectcurl = ' -w "%{redirect_url}" -o /dev/null 2> /dev/null' | |||
Searchquery = "search?q=from%3A" | |||
Andamp = '&' + 'amp;' | |||
HTMLtext = '<div class="tweet-content media-body" dir="auto">' | |||
##坂根輝美に場所を知らせます | |||
def pickupcounter(): | |||
print('ピックアップカウンター付近でふ') | |||
##引数のURLにHTTP接続します | |||
##失敗かどうかは呼出側で要判定 | |||
def request_onetime(url: Final[str]) -> Response: | |||
return requests.get(url, timeout=Request_timeout, headers=header) | |||
##HTTP接続を再試行回数まで試します | |||
##成功すると結果を返します | |||
##接続失敗が何度も起きるとエラーと今までにとれたツイートを吐き出して終了 | |||
def request(url: Final[str]) -> Response: | |||
counter = 1 | |||
while True: | |||
try: | |||
res = request_onetime(url) | |||
res.raise_for_status() | |||
except requests.exceptions.RequestException as e: | |||
if counter <= Limit_request: | |||
print(url + 'への通信失敗ナリ' + str(counter) + '/' + str(Limit_request) + '回') | |||
counter += 1 | |||
sleep(Waittime) | |||
else: | |||
print('通信失敗しすぎで強制終了ナリ') | |||
make_txt(txt_data) | |||
exit() | |||
else: | |||
return res | |||
##URLの最後にスラッシュ付いていなければ付ける | |||
def slash_check(): | |||
if Nitterinstance[-1] != '/': | |||
Nitterinstance = Nitterinstance + '/' | |||
if Archivetoday[-1] != '/': | |||
Archivetoday = Archivetoday + '/' | |||
if Archivetodaystandard[-1] != '/': | |||
Archivetodaystandard = Archivetodaystandard + '/' | |||
##nitterのインスタンスが生きているかチェック | |||
##死んでいたらそこで終了 | |||
##接続を一回しか試さないrequest_onetimeを使っているのは | |||
##激重インスタンスが指定されたとき試行回数増やして偶然成功してそのまま実行されるのを躱すため | |||
def instance_check(): | |||
try: | |||
res = request_onetime(Nitterinstance) ##リクエスト | |||
res.raise_for_status() ##HTTPステータスコードが200番台以外でエラー発生 | |||
except requests.exceptions.RequestException as e: ##エラー発生時は終了 | |||
print('インスタンスが死んでますを') | |||
exit() | |||
##ツイート収集するユーザー名を取得 | |||
##何も入力しないと尊師を指定するよう改良 | |||
def get_name() -> str: | |||
while True: | |||
print('アカウント名を入れなければない。空白だと自動的に' + Callinshow + 'になりますを') | |||
account_str = input() ##ユーザー入力受付 | |||
##空欄で降臨ショー | |||
if account_str == '': | |||
return Callinshow | |||
else: | |||
res = request(Nitterinstance + account_str) ##リクエストして結果取得 | |||
soup = bs4(res.text, 'html.parser') ##レスポンス解析 | |||
title_text = soup.find('title').get_text() | |||
##1件もないときはtitleにエラー | |||
if title_text == Nitter_error_title: | |||
print(account_str + "は実在の人物ではありませんでした") | |||
else: | |||
print("最終的に出会ったのが@" + account_str + "だった。") | |||
return account_str | |||
##検索クエリを取得 | |||
def get_query(name: Final[str]) -> Response: | |||
while True: | |||
print("検索クエリを入れるナリ。複数ある時は一つの塊ごとに入力するナリ。空欄を入れると検索開始ナリ。") | |||
print("例:「無能」→改行→「脱糞」→改行→「弟殺し」→改行→空欄で改行") | |||
query_str = [name] ##検索クエリ文字列をquery_strに収納。ユーザー名を先に含めておく | |||
query_input = input() ##ユーザー入力受付 | |||
##空欄が押されるまでユーザー入力受付 | |||
while query_input != '': | |||
query_str.append(quote(query_input)) | |||
query_input = input() | |||
res = request(Nitterinstance + Searchquery + '+'.join(query_str)) ##リクエストして結果取得 | |||
soup = bs4(res.text, 'html.parser') ##レスポンス解析 | |||
##1件もないときはHTMLにtimeline-noneがあるから判定 | |||
if soup.find(class_='timeline-none') is None: | |||
print("適切なクエリを入力することを切に望む。") | |||
else: | |||
print("クエリのピースが埋まっていく。") | |||
return res | |||
##テキスト発行 | |||
def make_txt(txt_data): | |||
txt_data = '{|class="wikitable" style="text-align: left;"\n' + txt_data ##wikiの表の最初 | |||
txt_data = txt_data + '|}' ##wikiの表の最後 | |||
##ファイル出力 | |||
with codecs.open('tweet.txt', 'w', 'utf-8') as f: | |||
f.write(txt_data) | |||
print("テキストファイル手に入ったやで〜") | |||
exit() ##終了 | |||
##記録を中断するツイート | |||
def stop_txt() -> str: | |||
print("ここにツイートの本文を入れる!すると・・・・なんと一致するツイートで記録を中断する!(これは本当の仕様です。)ちなみに、空欄だと" + str(Limit_tweet) + "件まで終了しない。") | |||
end_str = input() ##ユーザー入力受付 | |||
return end_str | |||
slash_check() | |||
instance_check() | |||
name = get_name() | |||
page = get_query(name) | |||
stop = stop_txt() | |||
while True: | |||
--> | --> |