Seleniumを使ってCiscoのバグ検索ツールから情報を取得するPythonスクリプト

# はじめに
2024年CiscoSystems合同会社社員有志によるAdventCalendarの記事の一つです。

https://qiita.com/advent-calendar/2024/cisco

# 目的
Seleniumを使ってCiscoのバグ検索ツールから情報を取得するPythonスクリプト
この記事では、PythonとSeleniumを使用してCiscoのバグ検索ツールから指定したバグIDに関連する情報（Overview, Product, Affected Version, Fixed Version）を自動取得する方法を解説します。

# 必要な環境
## 前提条件
Python 3.7以上がインストールされていること
Google Chromeがインストールされていること
Chromeのバージョンと一致するChromeDriverが利用可能であること

## 必要なPythonモジュール
Selenium
Webdriver-Manager

## セットアップ手順
### 1. Python環境のセットアップ
まず、Pythonがインストールされていることを確認します。
以下のコマンドでPythonのバージョンを確認してください。
```bash
python3 --version
```
Pythonがインストールされていない場合は、Python公式サイトからダウンロードしてインストールしてください。

### 2. 仮想環境を作成（推奨）
プロジェクト専用の仮想環境を作成して依存関係を隔離します。

```bash
python3 -m venv venv
source venv/bin/activate  # Windowsの場合は `venv\Scripts\activate`
```

### 3. 必要なモジュールをインストール
次に、必要なPythonモジュールをインストールします。

以下のコマンドを実行してください。

```bash
pip install selenium webdriver-manager
```
これで、SeleniumとWebdriver-Managerがインストールされます。

### 4. スクリプトの準備
以下のPythonスクリプトを作成します（例: new-scraping.py）。

```python
import sys
import csv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time

# Base URL
base_url = "https://bst.cloudapps.cisco.com/bugsearch/bug/"

# XPaths for required data
xpaths = {
    "Overview": "/html/body/app-root/div/main/section/app-bugsummary/section/div[2]/span[1]",
    "Product": "/html/body/app-root/div/main/section/app-bugsummary/section/div[4]/div/div[2]/div[2]/div[2]/div/div/div/div[1]/ul/div[2]/div/div/div/div/span",
    "Affected Version": "/html/body/app-root/div/main/section/app-bugsummary/section/div[4]/div/div[2]/div[2]/div[2]/div/div/div/div[2]/ul/div[2]/div/div/div/div/span",
    "Fixed Version": "/html/body/app-root/div/main/section/app-bugsummary/section/div[4]/div/div[2]/div[2]/div[2]/div/div/div/div[3]/ul/div[2]/div/div/div/div/span"
}

# Check if bug IDs are provided
if len(sys.argv) <= 1:
    print("Usage: python3 new-scraping.py <BugID1> <BugID2> ...")
    print("Example: python3 new-scraping.py CSCwi69572 CSCwi81026 CSCwj40589")
    sys.exit(1)

# Get bug IDs from arguments
bug_ids = sys.argv[1:]

# Initialize WebDriver using webdriver-manager
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))

try:
    # Open the first URL for manual login
    first_url = f"{base_url}{bug_ids[0]}"
    driver.get(first_url)
    print("Please log in manually using the opened browser. Once logged in, press Enter to continue...")
    input()  # Wait for the user to log in manually

    # Store results
    results = []

    # Navigate through all provided bug IDs and extract data
    for bug_id in bug_ids:
        url = f"{base_url}{bug_id}"
        print(f"Processing Bug ID: {bug_id}")
        driver.get(url)
        time.sleep(3)  # Wait for the page to load completely

        bug_data = {"Bug ID": bug_id}
        for key, xpath in xpaths.items():
            try:
                element = driver.find_element(By.XPATH, xpath)
                value = element.text.strip()
                # If the value is empty, we explicitly mark it as "No Value Found"
                bug_data[key] = value if value else "No Value Found"
            except Exception:
                # If XPath is not found, mark it as "Error: No XPath Found"
                bug_data[key] = "Error: No XPath Found"

        results.append(bug_data)

    # Print results to the terminal
    for result in results:
        print(f"Bug ID: {result['Bug ID']}")
        for key in xpaths.keys():
            print(f"{key}: {result[key]}")
        print("-" * 40)

    # Save results to a CSV file
    csv_file = "bug_report.csv"
    with open(csv_file, mode="w", newline="", encoding="utf-8") as file:
        writer = csv.DictWriter(file, fieldnames=["Bug ID"] + list(xpaths.keys()))
        writer.writeheader()
        writer.writerows(results)

    print(f"Results saved to {csv_file}")

finally:
    # Close the browser
    driver.quit()
```

## 実行方法
引数を指定して実行
スクリプトを実行する際、引数として取得したいバグIDを指定します。

以下のコマンドを実行してください。

```bash
python3 new-scraping.py CSCwi69572 CSCwi81026 CSCwj40589
```

### 出力例
以下のように、各バグIDの情報が表示されます。

```plaintext
Bug ID: CSCwi69572
Overview: High CPU alarms/ alerts are seen every 30 mins to one hour in 20.6.5.1.13 code
Product: Cisco 1000 Series Integrated Services Routers
Affected Version: Error: No XPath Found
Fixed Version: No Records Found
----------------------------------------
Bug ID: CSCwi81026
Overview: SDWAN BFD Sessions Flapping During IPSec Rekey in Scaled Environment
Product: Cisco 1000 Series Integrated Services Routers
Affected Version: Error: No XPath Found
Fixed Version: Error: No XPath Found
----------------------------------------
Bug ID: CSCwj40589
Overview: Endpoint tracker using DNS does not log "DOWN" message when DNS server reachability is lost
Product: Cisco SD-WAN
Affected Version: 17.9.3a
Fixed Version: Error: No XPath Found
----------------------------------------
```

## 注意事項
### 手動ログイン
最初のバグIDのURLを開く際にまずは手動でログインする必要があります。
ログイン完了後、ターミナルに戻って Enter を押してください。

### Seleniumのバージョン管理:
webdriver-manager が自動的にChromeDriverを管理します。Chromeのバージョンに合わせて最新のドライバがダウンロードされます。

### エラー処理
データが見つからない場合、Error: No XPath Found または No Value Found と表示されます。

# まとめ
このスクリプトは、Ciscoのバグ検索ツールを使用して指定したバグIDの情報を効率よく取得するのに役立ちます。PythonとSeleniumの強力な組み合わせにより、ブラウザ操作を自動化しつつ、ユーザーが手動でログインする柔軟性を確保しています。

何か質問や改善案があればコメント欄で教えてください！ 😊

# 余談
勢い余っていくつか記事を書いたのでお時間があれば下のやつも見ていってください。

https://qiita.com/KoheiYamashita1/items/067fd318195575295da0

https://qiita.com/KoheiYamashita1/items/e9b4761e79a15eeb50c8

https://qiita.com/KoheiYamashita1/items/aff7da82b45b8fb1abe4

https://qiita.com/KoheiYamashita1/items/6579659b7a3b7f7db516