Sitemap自動更新ツール『追放された俺でも、サイトマップ更新で無双する件。』 ソースコード

『追放された俺でも、サイトマップ更新で無双する件。』のソースコード全文です:

 
        import tkinter as tk
        from tkinter import filedialog, messagebox, scrolledtext
        import os
        import xml.etree.ElementTree as ET
        from datetime import datetime
        
        
        class SitemapUpdater:
            def __init__(self, master):
                self.master = master
                self.master.title("Sitemap自動更新ツール - 追放された俺でも、サイトマップ更新で無双する件。")
                self.sitemap_path = ""
                self.folder_path = ""
        
                # パス表示ラベル
                self.label_sitemap = tk.Label(master, text="sitemap.xml: 未選択", anchor="w", wraplength=600)
                self.label_sitemap.pack(fill="x", padx=10, pady=2)
        
                self.label_folder = tk.Label(master, text="対象フォルダ: 未選択", anchor="w", wraplength=600)
                self.label_folder.pack(fill="x", padx=10, pady=2)
        
                # 操作ボタン
                tk.Button(master, text="XMLファイルを選択", command=self.load_sitemap).pack(pady=4)
                tk.Button(master, text="フォルダを選択", command=self.select_folder).pack(pady=4)
                tk.Button(master, text="更新・保存", command=self.update_sitemap).pack(pady=10)
        
                # ステータス表示欄
                self.status_text = scrolledtext.ScrolledText(master, height=12, wrap=tk.WORD)
                self.status_text.pack(fill="both", expand=True, padx=10, pady=5)
        
            def log(self, message):
                """ステータスログに出力"""
                timestamp = datetime.now().strftime("[%H:%M:%S] ")
                self.status_text.insert(tk.END, timestamp + message + "\n")
                self.status_text.see(tk.END)
        
            def load_sitemap(self):
                path = filedialog.askopenfilename(filetypes=[("XML files", "*.xml")])
                if path:
                    self.sitemap_path = path
                    self.label_sitemap.config(text=f"XMLファイル: {path}")
                    self.log("XMLファイルを選択しました。")
        
            def select_folder(self):
                folder = filedialog.askdirectory()
                if folder:
                    self.folder_path = folder
                    self.label_folder.config(text=f"対象フォルダ: {folder}")
                    self.log("対象フォルダを選択しました。")
        
            def update_sitemap(self):
                if not self.sitemap_path or not self.folder_path:
                    messagebox.showwarning("エラー", "XMLファイルとフォルダの両方を選択してください。")
                    return
        
                self.log("XMLファイルを読み込み中...")
                tree = ET.parse(self.sitemap_path)
                root = tree.getroot()
                ns = {'ns': 'http://www.sitemaps.org/schemas/sitemap/0.9'}
        
                ET.register_namespace('', ns['ns'])
        
                updated = False
                updated_count = 0
        
                for url in root.findall("ns:url", ns):
                    loc = url.find("ns:loc", ns)
                    lastmod = url.find("ns:lastmod", ns)
        
                    if loc is not None and lastmod is not None:
                        url_path = self.url_to_path(loc.text)
                        full_path = os.path.join(self.folder_path, url_path)
        
                        if os.path.isfile(full_path):
                            file_time = os.path.getmtime(full_path)
                            file_dt = datetime.fromtimestamp(file_time)
                            try:
                                lastmod_dt = datetime.fromisoformat(lastmod.text.replace("Z", "+00:00")).replace(tzinfo=None)
                            except ValueError:
                                self.log(f"⚠ 日付形式不正: {lastmod.text}")
                                continue
        
                            if file_dt > lastmod_dt:
                                lastmod.text = file_dt.strftime("%Y-%m-%dT%H:%M:%S+00:00")
                                self.log(f"✅ 更新: {url_path}")
                                updated = True
                                updated_count += 1
                            else:
                                self.log(f"🟢 最新です: {url_path}")
                        else:
                            self.log(f"⚠ ファイルが見つかりません: {url_path}")
        
                if updated:
                    now = datetime.now().strftime("%Y%m%d-%H%M%S")
                    save_path = os.path.join(os.path.dirname(self.sitemap_path), f"sitemap-{now}.xml")
                    tree.write(save_path, encoding="utf-8", xml_declaration=True)
                    self.log(f"💾 {updated_count} 件更新し、保存しました: {save_path}")
                    messagebox.showinfo("保存完了", f"{updated_count} 件の<lastmod>を更新し、保存しました。")
                else:
                    self.log("🔍 すべてのファイルが最新の状態です。")
                    messagebox.showinfo("更新不要", "すべてのファイルが最新の状態です。")
        
            def url_to_path(self, url):
                """URLからファイルパスを抽出(例: https://example.com/a/b.html → a/b.html)"""
                parts = url.split("://")[-1].split("/", 1)
                return parts[1] if len(parts) > 1 else ""
        
        
        if __name__ == "__main__":
            root = tk.Tk()
        
            ##タイトルバーアイコン表示用
            data = '''R0lGODdhEAAQAIcAAOStRN6lPdyiOtmeONidN9ebNtaZNdSYNNCTMdCQLsiLLceJLMaHKsSFKsCCKcCBKb1+KLx+KL1+Jbx8I7Z6J7d4JLZ3I7R3JLN3JrV2IrF1JLR0ILJ0JbJ0JLJ0IqxvI6tvIapvIqpvIadrHqBmIJ9mHp9lHZxlH6BkG5tjH5tjHJphHJRhIZRhIJlgGphfGZVfG5RgHpNfHZNfHJZeGpNdHZVcG5FeHpFdH5BbGo9aG45aHIlaIJBZF4lWG4pTFohVGIRTG4ZSF4ZSFYJRF4JPFIFPF3xNGIBJD3xKFHpLFXlIE3xHEHhHE3dDDnZEEG5BEWlEGW1BEWxBEmw/EGk9DWg9EGg9D2w8DWc8EGU7DFw2DWE1C1w1DVU1EFo0DlYyDVUyDFcxDFUxC1ExDU8wD08uC0wtDEosDEktD0csDlQqBVQqBE4nBU4nBEsnBkoqC0cqDEcoCkUqDEIoDEEpD0EoDEApDz8oDkAnDj4qEzopFDooEzkoEz4nDj0nDkcjA0ElCUEiBkMhAz8mDDwlDDomDzkmEDklDTkkDjcmEzYmEjgkDjYjDTQjDzMjDzMiDjMhDTIkEzIiEDAhDzAhDi8kEyshEjEgDDAgDS4gDy4gDiwgDy4fDi4fDS0fDiofETceBzUdBjEdBy8cByweDiweDSweDCseDSscCioeDikeDyodDikdDykdDSocDCkcDSkcDDEbBjAaBisZBi0YBSsXBSgaCigXBigWBSgWBCcfEiceEScdECYdECYdDyccDiccDSccDCUcDyMcECIcEScbDCcbCyUbDCQbDiMbDyIbDyEbECQaDSQaDCMaDiIaDyEaDyYZCSMZDSIZDSIYCiEYDCEYCycWBSYVBCIXCSIWByAZDh8ZDx8XDB8XCh0ZEB0ZDx4YDR0YDxwYDhsYDx4XDB0XDRwXDRsXDh0VChwVChoWDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAEAAQAEAI/wDLhSu2y5IiPnr29JF0iZcybul8OVJTRYQDBAEADGBQoceYO5WgBZOmS9CbNmvYuAE0KBCkTcCiwfI0So6PHDReuFBxooaXV826/fpUiMcNGTNgxGjBIgqrYNyIqcKExkgKDBEeQPhg48qcSa2UbcJDRsgKEBUmbEDxQ8oZRK7Qmbu2DZesWbVs5dKVDdstY9bGLQO16FCdNGXKqMmTSNOqZ+TADUslCgcHDRYyeAhB4kgmU8mYwdJGCs4XKE2SLLEiJg4jTsN8UfqzpQQFBQUEHGjQoYgZQ516PVKjxcSFBQYIJJAwYkgYP56ilWpEJwuVJ0yQOMHCBYydSFCdHSOjFSrIDh1AiCiZ0oVQrGnsznlbp+5bNWOoTJ0SdgwZNXEBAQA7''' 
            root.tk.call('wm', 'iconphoto', root._w, tk.PhotoImage(data=data))
            ####
        
            app = SitemapUpdater(root)
            root.mainloop()
       
    

📦 ダウンロード 🏠 ホームへ