0
0

More than 1 year has passed since last update.

Pythonを使ってBIZTEL 2系のユーザー一覧をエクスポートする

Posted at

はじめに

弊社で使っているIP電話サービスBIZTEL。バージョン2系と呼ばれる古いバージョンを使っているため、管理画面がかなり使いづらい。特に、ユーザーの一覧をエクスポートする機能がないので、欠番を簡単に確認できない。
そこで、Pythonを使ってユーザー一覧をCSVで吐き出してみようと思った。

ちなみに、これからBIZTELを導入する場合は、BIZTEL 3系になると思うから、管理画面も改善しているはず。

前提条件

  • BIZTELのシステム管理権限
  • Windows 11
  • Python 3.10.3
    • requests 2.27.1
    • beautifulsoup4 4.10.0

コード

import re
import csv
import time
import urllib3

import requests
from bs4 import BeautifulSoup

# SSL証明書のエラー警告を無視
urllib3.disable_warnings()

class Login:
    def __init__(self, url, id, pw):
        self.session = requests.session()
        # URL末尾にスラッシュがない場合はつける
        self.base_url = url if url[-1] == '/' else url + '/'
        # ログイン情報をセット
        payload = {
            'inpAccount': id,
            'inpPassword': pw
        }
        # verify=FalseとしないとSSL証明書エラーとなる
        self.session.post(self.base_url + 'adminlogin.php', data=payload, verify=False)


class AccountManagement(Login):
    def __init__(self, url, id, pw):
        super().__init__(url, id, pw)
        self.account_management_url = self.base_url + 'account_management.php'
        account_management_response = self.session.get(self.account_management_url, allow_redirects=False)
        self.soup = BeautifulSoup(account_management_response.text, 'html.parser')

    def get_accounts(self):
        # 正規表現でユーザーの合計数を取得
        pattern = r'(?<=合計 )[0-9]+(?= 件)'
        total_text = self.soup.select('td:contains("合計")')
        total = re.search(pattern, total_text[-1].get_text(strip=True)).group(0)
        # ページ数を計算
        pages = int(total) // 10 + 1
        # ユーザー情報を格納するリスト
        accounts = []
        # 1~pagesまでページを取得する
        for i in range(pages):
            page = {
                'Ppage': i
            }

            response = self.session.post(self.account_management_url, data=page, allow_redirects=False)
            soup = BeautifulSoup(response.text, 'html.parser')
            # 名前と内線番号を取得
            names = [e.get_text() for e in soup.select('body > table > tr > td > table > tr > td > table > tr > td > table > TR > td > a[href="#"]')]
            phone_nums = [e.get_text(strip=True) for e in soup.select('body > table > tr > td > table > tr > td > table > tr > td > table > TR > td[width="90"]')]
            # 名前と内線番号をリストに格納
            for name, phone in zip(names, phone_nums):
                accounts.append([name, phone])
            # インターバル
            time.sleep(1)
        
        # ソート
        accounts.sort(key=lambda x: x[1])
        # ヘッダーをセット
        accounts.insert(0, ['ユーザ名', '内線番号'])

        # CSV ファイルへ出力する
        with open('output.csv', mode='w') as f:
            writer = csv.writer(f, lineterminator='\n')
            writer.writerows(accounts)

使用例

Biztel = AccountManagement('https://biztel:1234', 'ID', 'Password')
Biztel.get_accounts()

SSLエラー回避

BIZTELはSSLサーバ証明書に自己証明書を利用しているため警告画面が表示されるとのこと。
セキュリティ上は問題ないらしいが、スクレイピングをする上で、エラーが出て止まってしまうので、回避策が必要。
そこで、urllib3.disable_warnings()を追記。

BIZTELではサーバとの通信を暗号化しており、その際に使用しているSSLサーバ証明書に自己証明書を利用しているため警告画面が表示されますが 、セキュリティ上問題になるものではございません。

BIZTEL FAQサイト

ログイン

inpAccountinpPasswordにIDとパスワードを渡してPOST。

アカウント管理ページ

class AccountManagement(Login):
    def __init__(self, url, id, pw):
        super().__init__(url, id, pw)
        self.account_management_url = self.base_url + 'account_management.php'
        account_management_response = self.session.get(self.account_management_url, allow_redirects=False)
        self.soup = BeautifulSoup(account_management_response.text, 'html.parser')
  • クラスLoginを継承する。
  • アカウント管理用のURLはhttps://biztel:1234/account_management.phpとなる。
  • allow_redirects=Falseこれがないとログイン画面に飛ばされる。
  • BS4の標準パーサーであるhtml.parserを使う。

アカウント管理ページをループ

    def get_accounts(self):
        # 合計を取得
        pattern = r'(?<=合計 )[0-9]+(?= 件)'
        total_text = self.soup.select('td:contains("合計")')
        total = re.search(pattern, total_text[-1].get_text(strip=True)).group(0)
        # ページ数を計算
        pages = int(total) // 10 + 1

        accounts = []

        for i in range(pages):
            page = {
                'Ppage': i
            }

            response = self.session.post(self.account_management_url, data=page, allow_redirects=False)
            soup = BeautifulSoup(response.text, 'html.parser')
            # 名前と内線番号を取得
            names = [e.get_text() for e in soup.select('body > table > tr > td > table > tr > td > table > tr > td > table > TR > td > a[href="#"]')]
            phone_nums = [e.get_text(strip=True) for e in soup.select('body > table > tr > td > table > tr > td > table > tr > td > table > TR > td[width="90"]')]
            # 名前と内線番号をリストに格納
            for name, phone in zip(names, phone_nums):
                accounts.append([name, phone])
            # インターバル
            time.sleep(1)
        
        # ソート
        accounts.sort(key=lambda x: x[1])
        accounts.insert(0, ['ユーザ名', '内線番号'])

        # CSV ファイルへ出力する
        with open('output.csv', mode='w') as f:
            writer = csv.writer(f, lineterminator='\n')
            writer.writerows(accounts)
  • 正規表現を使ってユーザー数の合計をtotalへ格納。
  • 1ページあたり10人なので、求めたユーザー数を10で割った整数商に1を足すと総ページ数となる。
  • accountsにユーザー情報の一覧を格納。
  • アカウント管理ページのページ数はパラメーターPpageで管理。
  • 1ページごとにユーザー名と内線番号を取得してaccountsに追加。
  • サーバーへ負荷をかけないようにtime.sleep(1)で1秒間のインターバル。
  • accounts.sort(key=lambda x: x[1])で内線番号を基準にソートして、accounts.insert(0, ['ユーザ名', '内線番号'])でヘッダーを追加。
  • CSV出力。

おわりに

バージョン3系へ早く移行したい。。。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0