Skip to main content
Glama
moma1992

Yaizu Smart City MCP Server

by moma1992
test_catalog_login.py12 kB
#!/usr/bin/env python3 """ APIカタログサイトへのログインとカタログ選択画面の動作確認 """ import asyncio import base64 import json import os from pathlib import Path from typing import Dict, List from urllib.parse import urljoin import aiohttp from bs4 import BeautifulSoup from dotenv import load_dotenv load_dotenv() BASE_URL = "https://city-api-catalog.smartcity-pf.com/yaizu" EMAIL = os.getenv("YAIZU_API_EMAIL") PASSWORD = os.getenv("YAIZU_API_PASSWORD") class CatalogLoginTester: """APIカタログのログインと画面遷移をテスト""" def __init__(self): self.session = None self.auth_headers = {} self.cookies = {} async def __aenter__(self): self.session = aiohttp.ClientSession() return self async def __aexit__(self, exc_type, exc_val, exc_tb): if self.session: await self.session.close() async def test_access(self): """1. サイトへの初期アクセス""" print("\n" + "="*50) print("ステップ1: APIカタログサイトへアクセス") print("="*50) print(f"URL: {BASE_URL}") try: async with self.session.get(BASE_URL) as response: print(f"✅ ステータス: {response.status}") print(f" Content-Type: {response.headers.get('content-type')}") # クッキーを保存 self.cookies = {k: v.value for k, v in response.cookies.items()} if self.cookies: print(f" クッキー取得: {list(self.cookies.keys())}") html = await response.text() soup = BeautifulSoup(html, 'lxml') # ページタイトル確認 title = soup.find('title') if title: print(f" ページタイトル: {title.get_text(strip=True)}") # ログインリンクを探す login_links = soup.find_all('a', href=lambda x: x and 'login' in x.lower()) if login_links: print(f" ログインリンク発見: {len(login_links)} 個") for link in login_links[:3]: print(f" - {link.get('href')}: {link.get_text(strip=True)}") return True except Exception as e: print(f"❌ エラー: {e}") return False async def test_login(self): """2. ログイン処理""" print("\n" + "="*50) print("ステップ2: ログイン認証") print("="*50) print(f"ユーザー: {EMAIL}") # Basic認証ヘッダーを作成 credentials = f"{EMAIL}:{PASSWORD}" encoded = base64.b64encode(credentials.encode()).decode() self.auth_headers = { "Authorization": f"Basic {encoded}", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" } # documentationページに認証付きでアクセス print(f"\n認証付きでアクセス: {BASE_URL}/documentation") try: async with self.session.get( f"{BASE_URL}/documentation", headers=self.auth_headers ) as response: print(f"✅ ステータス: {response.status}") if response.status == 200: print(" ✅ ログイン成功!") html = await response.text() soup = BeautifulSoup(html, 'lxml') # ページタイトル title = soup.find('title') if title: print(f" ページタイトル: {title.get_text(strip=True)}") return True elif response.status == 401: print(" ❌ 認証失敗(401 Unauthorized)") print(" ユーザー名またはパスワードが正しくない可能性があります") return False else: print(f" ⚠️ 予期しないステータス: {response.status}") return False except Exception as e: print(f"❌ エラー: {e}") return False async def explore_catalog(self): """3. カタログ選択画面の探索""" print("\n" + "="*50) print("ステップ3: APIカタログ選択画面の確認") print("="*50) # documentationページを詳しく調べる async with self.session.get( f"{BASE_URL}/documentation", headers=self.auth_headers ) as response: if response.status != 200: print("❌ アクセスできません") return html = await response.text() soup = BeautifulSoup(html, 'lxml') # デバッグ用にHTMLを保存 debug_file = Path("debug_documentation.html") with open(debug_file, 'w', encoding='utf-8') as f: f.write(html) print(f"📄 デバッグ用HTML保存: {debug_file}") # APIカタログ要素を探す print("\n🔍 APIカタログ要素を探索中...") # 1. サービス一覧を探す service_elements = soup.find_all(['div', 'article'], class_=lambda x: x and any(k in str(x).lower() for k in ['service', 'api', 'catalog'])) if service_elements: print(f"📦 サービス要素発見: {len(service_elements)} 個") for i, elem in enumerate(service_elements[:5], 1): # 名前を探す name = elem.find(['h1', 'h2', 'h3', 'h4', 'a']) if name: print(f" {i}. {name.get_text(strip=True)}") # 2. リンクから探す api_links = [] for link in soup.find_all('a', href=True): href = link['href'] text = link.get_text(strip=True) if text and any(keyword in text.lower() or keyword in href.lower() for keyword in ['api', 'service', 'spec', 'document']): api_links.append((text, href)) if api_links: print(f"\n📎 API関連リンク発見: {len(api_links)} 個") for text, href in api_links[:10]: print(f" - {text[:50]}: {href}") # 3. JavaScriptデータを探す print("\n🔍 JavaScriptデータを探索中...") for script in soup.find_all('script'): if script.string: # APIデータが含まれているか確認 if 'services' in script.string or 'apis' in script.string: print("📊 JavaScriptにAPIデータ発見") # window.変数の形でデータが定義されているか確認 import re window_vars = re.findall(r'window\.(\w+)\s*=\s*', script.string) if window_vars: print(f" window変数: {window_vars[:5]}") # JSON形式のデータを探す json_pattern = re.findall(r'\{[^{}]*"(?:service|api|route|spec)[^{}]*\}', script.string) if json_pattern: print(f" JSONデータブロック発見: {len(json_pattern)} 個") # 4. フォームやボタンを探す forms = soup.find_all('form') buttons = soup.find_all(['button', 'input'], type=['submit', 'button']) if forms: print(f"\n📝 フォーム発見: {len(forms)} 個") for form in forms: action = form.get('action', 'なし') method = form.get('method', 'GET') print(f" - Action: {action}, Method: {method}") if buttons: print(f"\n🔘 ボタン発見: {len(buttons)} 個") for btn in buttons[:5]: text = btn.get_text(strip=True) or btn.get('value', '') if text: print(f" - {text}") async def check_api_endpoints(self): """4. APIエンドポイントの確認""" print("\n" + "="*50) print("ステップ4: APIエンドポイントの確認") print("="*50) # APIエンドポイントをテスト api_base = BASE_URL.replace('city-api-catalog', 'city-api-catalog-api') endpoints = [ f"{api_base}/services", f"{api_base}/routes", f"{api_base}/specs", f"{BASE_URL}/api/services", f"{BASE_URL}/api/catalog" ] for endpoint in endpoints: print(f"\n🔍 テスト: {endpoint}") try: headers = { **self.auth_headers, "Accept": "application/json" } async with self.session.get(endpoint, headers=headers) as response: print(f" ステータス: {response.status}") content_type = response.headers.get('content-type', '') print(f" Content-Type: {content_type}") if response.status == 200: if 'application/json' in content_type: data = await response.json() print(f" ✅ JSONデータ取得成功") # データ構造を表示 if isinstance(data, dict): print(f" キー: {list(data.keys())[:5]}") if 'data' in data and isinstance(data['data'], list): print(f" データ件数: {len(data['data'])}") elif isinstance(data, list): print(f" 配列件数: {len(data)}") else: text = await response.text() print(f" レスポンス長: {len(text)} 文字") except Exception as e: print(f" ❌ エラー: {e}") async def main(): """メイン実行""" print("="*60) print("焼津市APIカタログ - ログイン動作確認テスト") print("="*60) async with CatalogLoginTester() as tester: # 1. 初期アクセス if not await tester.test_access(): print("\n❌ 初期アクセスに失敗しました") return # 2. ログイン if not await tester.test_login(): print("\n❌ ログインに失敗しました") return # 3. カタログ画面探索 await tester.explore_catalog() # 4. APIエンドポイント確認 await tester.check_api_endpoints() print("\n" + "="*60) print("✅ テスト完了") print("="*60) if __name__ == "__main__": asyncio.run(main())

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/moma1992/smartcity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server