LoginSignup
3
4

More than 5 years have passed since last update.

connpassのイベント参加者リストをcsv形式で取得し、重複する参加者を調べる

Last updated at Posted at 2018-08-18

はじめに

connpassの複数のイベントに参加していると、同一の内容を異なるグループのイベントでLTする機会も増えてきます。

エンジニアをつなぐIT勉強会支援プラットフォーム
https://connpass.com/

別のイベントではあるものの、同じ参加者がたくさん来られている場合は、同じ内容でLTするのは気が引けますよね。

connpassのイベント主催者は、参加者リストとcsv形式を取得することができます。しかし、一般の参加者は参加者一覧ページを閲覧することはできますが、csv形式では入手することができません。

そこで、指定したイベントの参加者リストをpython3でスクレイピングし、csv形式で出力する処理を作ってみました。

csvファイルの出力後は、イベント(2つのcsvファイル)間で、重複する参加者を出力する処理も用意しました。

GitHubにてソースコードを公開しています。
https://github.com/NobuyukiInoue/get_connpass_participants

参考1:スクレイピング処理に関しての留意事項
Webスクレイピングの注意事項一覧
connpass利用規約

参考2:動作確認環境
* Windows10 & Python 3.6.0
* Windows7 & Python 3.6.1
* macOS 10.13.6 & Python 3.6.5
* Ubuntu 16.04.5 LTS & Python 3.7.0

追記

2つのイベントを(CSVファイルに出力せずに)比較し、重複ユーザーを表示する処理も追加で作成しました。列挙したいだけなら、こちらの方が使い勝手が良いかもしれません。

connpassの2つイベント間で重複する参加者を調べる

ソースコード)get_participant_duplicates.py

1. 必要モジュールのインストール

HTMLのparse処理にbeautifulsoup4を使用しています。
管理者権限でpip install beautifulsoup4コマンドを実行し、事前にインストールしておいてください。

2. 参加者一覧の取得とcsvファイル出力

コンパスの各イベントのURLは下記のような書式になっています。

https://グループ名.connpass.com/event/イベントID/

「イベント参加者・申込者一覧」ページのURLには、participationというサブディレクトリ名が付加されています。

https://グループ名.connpass.com/event/イベントID/participation/

2-1. 処理内容

参加者一覧を取得するスクレイピング処理では、この「イベント参加者・申込者一覧」ページにアクセスしてHTMLの応答を取得したあと、
<A HREF=...>タグを抽出することにより、ユーザー名およびプロフィールへのリンクを取得しています。

get_participant.py
import sys
from datetime import datetime

import urllib.request, urllib.error
from bs4 import BeautifulSoup

def print_arg_error(commandName):
    """引数エラー時のメッセージ出力"""
    print("Usage: python {cmd} connpassURL\n"
          "\n"
          "example)\n"
          "python {cmd} https://GROUP_NAME.connpass.com/event/xxxxx/"
          .format(cmd=commandName))
    exit(0)


def is_url(url):
    """URL書式チェック"""
    return url.startswith("https://") or url.startswith("http://")


def participation_url(url):
    """参加者URLに変換"""
    if url.endswith("/participation/"):
        return url
    if url.endswith("/participation"):
        return url + "/"
    if url.endswith("/"):
        return url + "participation/"
    else:
        return url + "/participation/"


def getgrpName(url, extention):
    """グループ名とイベント番号を取り出してファイル名とする"""

    # url format
    # "https://<groupName>.connpass.com/event/<eventId>/participation/"

    # <groupName>を取り出す
    pos_l1 = url.find("/")
    pos_l2 = url.find("/", pos_l1 + 1)
    pos_l3 = url.find(".")

    if ((pos_l1 < 0) or (pos_l2 < 0) or (pos_l3 < 0)):
        print("groupName error...")
        return ""

    groupName = url[pos_l2 + 1:pos_l3]

    # <eventId>を取り出す
    pos_r1 = url.rfind("/")
    pos_r2 = url.rfind("/", 0, pos_r1 - 1)
    pos_r3 = url.rfind("/", 0, pos_r2 - 1)

    if ((pos_r1 < 0) or (pos_r2 < 0) or (pos_r3 < 0)):
        print("eventId error...")
        return ""

    eventId = url[pos_r3 + 1:pos_r2]

    # 現在の時刻を年、月、日、時、分、秒で取得
    dateStr = datetime.now().strftime("%Y%m%d_%H%M%S")

    return(groupName + "_" + eventId + "_" + dateStr + extention)


def users(tags):
    """ユーザー情報の取得(ユーザ名とユーザURLのCSV形式)"""
    for tag in tags:
        try:
            if tag.text and tag.text != "\n\n":
                href = tag['href']
                if "/open/" in href or "/user/" in href:
                    yield '"{name}","{url}"\n'.format(name=tag.text, url=href)
        except:
            pass


def main():
    args = sys.argv

    if len(args) <= 1:
        print_arg_error(args[0])

    # URL Format
    # "https://xxxxxx.connpass.com/event/xxxxx/"

    # URL書式チェック
    if not is_url(args[1]):
        print("URL Error...%s\n" %args[1])
        print_arg_error(args[0])

    # 参加者URLに変換
    url = participation_url(args[1])

    save_fname = getgrpName(url, ".csv")
    if (save_fname == ""):
        print_arg_error(args[0])

    # 指定したURLの出力htmlを取得する 
    html = urllib.request.urlopen(url)

    # htmlをBeautifulSoupに取り込む
    soup = BeautifulSoup(html, "html.parser")

    # すべての<A>タグを抽出する
    tags = soup.find_all("a")

    # ユーザー情報保存用リストに格納
    ulist = list(users(tags))

    # 抽出したリストを標準出力に表示する
    for user in ulist:
        print(user, end="")

    # ファイルに出力する
    with open(save_fname, mode='w') as f:
        f.writelines(ulist)

    print("\nsave as ... [%s]" %(save_fname))

if __name__ == "__main__":
    main()

2-2. 取得処理の実行

実行時には、get_participant.pyへの引数として、参加者リストを取得したいイベントのURLを指定します。

参加者リストは、実行結果として標準出力に表示されたあと、
グループ名_イベントID_YYYYmmdd_HHMMSS.csvというファイル名で自動保存されます。

PS D:\> python .\get_participant.py https://グループ名.connpass.com/event/イベントID/

"(主催者01)","https://connpass.com/user/(主催者01)/open/"
"(発表者01)","https://connpass.com/user/(発表者01)/presentation/"
"(発表者02)","https://connpass.com/user/(発表者02)/presentation/"
"(参加者01)","https://connpass.com/user/(参加者01)/"
"(参加者02)","https://connpass.com/user/(参加者02)/"
"(参加者03)","https://connpass.com/user/(参加者03)/"
...
...
...
"(参加者29)","https://connpass.com/user/(参加者29)/"
"(参加者30)","https://connpass.com/user/(参加者30)/"

save as ... [グループ名_イベントID_YYYYmmdd_HHMMSS.csv]
PS D:\> 

3. csvファイルの比較

次に、2つのイベント間で重複する参加者を抽出する処理です。

get_duplicate_user.pyで2つのイベントの参加者リストを読み込ませます。処理の中では、(ユーザー名ではなく)各ユーザーのプロフィールのURLが一致していないかを調べています。一致していた場合、そのレコードが表示されます。
(10行目のencoding="sjis"は、必要に応じて書き換えてください。macOSLinuxでは不要かも。)

3.1. 重複する参加者を抽出する

get_duplicate_user.py
# coding: cp932

import sys
import os

def getDuplicateUsers(users1, users2):
    """2つのcsv配列を比較し、profile URLが一致するレコードを出力する"""
    urls2 = {user2.split('","')[1] for user2 in users2}
    for user1 in users1:
        name1, url1 = user1.split('","')
        if url1 in urls2:
            yield user1

def main():
    args = sys.argv

    if len(args) <= 2:
        print("Usage: python %s file1 file2" %(args[0]))
        exit()

    if ( os.path.isfile(args[1]) != True ):
        print("%s not found." %(args[1]))
        exit(0)

    if ( os.path.isfile(args[2]) != True ):
        print("%s not found." %(args[2]))
        exit(0)

    with open(args[1]) as f:
        users1 = f.readlines()

    with open(args[2]) as f:
        users2 = f.readlines()

    # 2つのcsv配列を比較し、profile URLが一致するレコードを出力する
    print("\n=== Dupulicate users [%s] in [%s] ===" %(args[1], args[2]))
    for user in getDuplicateUsers(users1, users2):
        print(user, end="")

if __name__ == "__main__":
    main()

3.2. 実行例

PS D:> python .\get_duplicate_user.py .\groupA_xxxxx_20180818_154841.csv .\groupB_yyyyy_20180819_185951.csv

=== Dupulicate users [.\data\groupA_xxxxxx_20180818_154841.csv] in [.\groupB_yyyyy_20180819_185951.csv]
===
"user01","https://connpass.com/user/user01/"
"user02","https://connpass.com/user/user02/"
"user03","https://connpass.com/user/user03/"
"user04","https://connpass.com/user/user04/"

PS D:\>
3
4
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
3
4