Fet-Fe

2024年11月8日 (金)に参加
編集の要約なし
>Fet-Fe
編集の要約なし
>Fet-Fe
編集の要約なし
12行目: 12行目:


連絡は[[利用者・トーク:Fet-Fe|トークページ]]までお願いします
連絡は[[利用者・トーク:Fet-Fe|トークページ]]までお願いします
== 恒心教徒の皆様へ:当Wikiのソースの魚拓取得をお手伝い下さい ==
現在Ost師がいらっしゃらない期間が長く続いており、何かあったのではないかと当職は心配しています
Wikiのダンプを取れるのはOst師だけなので、最悪の場合、Wikiのデータが消失してしまうことも考えられます
そこで、履歴が消えても最新のコンテンツだけは保存できるよう、当職はWikiの各ページの「ソースを編集」で開く編集ページの魚拓を取るスクリプトを書きました
使い方は必要なライブラリをインストールし、走らせるだけです
87行目以降の<code>namespace_list</code>を絞れば、その名前空間のページだけ魚拓をとることができます
多くの教徒が別々の名前空間に対して魚拓をとっていただければ、取得が早く終わります
また1つのIPから多くの魚拓を取得すると制限がかかるかもしれないので、なるべく多様なIPから魚拓をとっていただけると助かります
アクセス先は当wikiとarchive.phだけなので、生IPでも多分大丈夫です
魚拓ページに対して、JavaScriptなら<code>document.querySelector('#wpTextbox1').textContent</code>を実行すればwikiのソースが取れます
皆様ご協力をお願いいたします
‎<syntaxhighlight lang="python" line>
import subprocess
from urllib.parse import quote, unquote
from bs4 import BeautifulSoup
import re
from time import sleep
from datetime import datetime
from typing import List
ROOT = "https://krsw-wiki.org"
ARCHIVE = "https://archive.ph"
yobi = re.compile(r'\([日月火水木金土]\)')
archive_wip_url_re = re.compile(r'document\.location\.replace\(\"(https:\/\/archive\.ph\/wip\/\S+)\"\)')
# curlコマンドでリクエストを送る
def curl(arg: str) -> str:
  sleep(1) # DoS予防
  return subprocess.run('curl -sSL ' + arg, stdout=subprocess.PIPE, shell=True).stdout.decode('utf-8')
# ページのBeautifulSoupオブジェクトを取得
def fetch_page(url: str) -> BeautifulSoup:
  url = url.replace('&', '\&')
  response = curl(f"-A 'Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0' {url}")
  soup = BeautifulSoup(response, features='lxml')
  return soup
# ページが最後に編集された時間を取得
def last_edit(page_href: str) -> datetime:
  info_page_url = f"{ROOT}/index.php?title={page_href[6:]}&action=info"
  page_obj = fetch_page(info_page_url)
  time_text = page_obj.select_one('#mw-pageinfo-lasttime > td > a').get_text(strip=True)
  # 2022年3月3日 (木) 15:40 みたいな形式からdatetimeに
  time_text = yobi.sub('', time_text)
  timestamp = datetime.strptime(time_text, '%Y年%m月%d日  %H:%M')
  return timestamp
# ページのソースが最後に魚拓された時間を取得
def last_archive(page_href: str) -> datetime:
  source_page_url = f"{ROOT}/index.php?title={page_href[6:]}&action=edit"
  archive_page_url = f"{ARCHIVE}/{source_page_url}"
  page_obj = fetch_page(archive_page_url)
  time_text_node = page_obj.select_one('#row0 > .THUMBS-BLOCK > div:last-of-type > a > div')
  # 魚拓が無ければ最小のタイムスタンプ
  if not time_text_node:
    return datetime.min
  time_text = time_text_node.get_text(strip=True)
  # 16 Jan 2022 00:37 みたいな形式からdatetimeに
  timestamp = datetime.strptime(time_text, '%d %b %Y %H:%M')
  return timestamp
def fetch_submitid() -> str:
  soup = fetch_page(ARCHIVE)
  return soup.select_one('#submiturl > input').get('value')
# 1つのページの魚拓をとる
def archive_page(page_href: str):
  source_page_url = f"{ROOT}/index.php?title={page_href[6:]}&action=edit"
  print(f"{unquote(source_page_url)} の魚拓を取るナリ")
  response = curl(f"-X POST -A 'Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0' -H 'Host:archive.ph' {ARCHIVE}/submit/ --data-raw 'anyway=1&submitid={quote(fetch_submitid())}&url={quote(source_page_url)}'")
  print(f"{archive_wip_url_re.search(response)[1]} で魚拓を取っているナリ\n")
# ページ一覧の各ページで最新の魚拓をとる
def archive_each_page(page_list_url: str):
  page_obj = fetch_page(page_list_url)
  page_list = page_obj.select('.mw-allpages-chunk > li > a')
  for page_url in page_list:
    # 各ページの最終更新日時とそれらのソースの最終魚拓日時を比較
    last_edit_time = last_edit(page_url.get('href'))
    last_archive_time = last_archive(page_url.get('href'))
    if last_archive_time <= last_edit_time:
      # 魚拓が古ければ新しくアーカイブ
      archive_page(page_url.get('href'))
  # ページ一覧のpagination
  pagination_url = page_obj.select_one('.mw-allpages-nav > a:last-of-type')
  if pagination_url and '次のページ' in pagination_url.get_text(strip=True):
    archive_each_page(f"{ROOT}{pagination_url.get('href')}")
def main(namespace_list: List[int]):
  for i in namespace_list:
    # 名前空間のページ一覧のURL
    page_list_url = f"{ROOT}/wiki/{quote('特別:ページ一覧')}?from=&to=&namespace={i}"
    print(f"  {unquote(page_list_url)} の名前空間を探索するナリ\n")
    archive_each_page(page_list_url)
if __name__ == '__main__':
  namespace_list = [
    0,  # (標準)
    4,  # Wiki
    3004, # 恒辞苑
    3006, # 恒心文庫
    8,  # MediaWiki
    10, # テンプレート
    14, # カテゴリ
    828, # モジュール
    3008, # 恒心AA保管庫
    12, # ヘルプ
    6,  # ファイル
    2,  # 利用者
    3000, # Forum
    3002, # Books
    1,  # トーク
    5,  # Wiki・トーク
    3005, # 恒辞苑・トーク
    3007, # 恒心文庫
    9,  # MediaWiki・トーク
    11, # テンプレート・トーク
    15, # カテゴリ・トーク
    829, # モジュール・トーク
    3009, # 恒心AA保管庫・トーク
    13, # ヘルプ・トーク
    7,  # ファイル・トーク
    3,  # 利用者・トーク
    3001, # Forum talk
    3003, # Books talk
  ]
  main(namespace_list)
‎</syntaxhighlight>


== Unicodeのノウハウ ==
== Unicodeのノウハウ ==
匿名利用者