インターンシップの最新情報をまとめるサイトを作る
学んだこと(6/13,6/14,6/20,6/23~6/26,8/6)
3.「Connpass(コンパス)」のWebサイトからスクレイピングする
🖥 画面づくり・ユーザー操作の命令
-
「
st.set_page_config(layout="wide")」 → アプリの画面を横いっぱいに広げて、大きな表でもスクロールせずに見やすく整える「画面枠拡張スイッチ」 -
「
st.text_input("...")」 → 画面の中に、人間がキーボードで文字を打ち込める「検索ボックス(入力欄)」を作り、そこで入力された言葉を受け取る処理 -
「
st.button("検索開始")」 → 画面に「検索開始ボタン」を作り、クリックされた瞬間だけ後ろのプログラムを発火させるスタートスイッチ -
「
if search_query:」 → もし検索ボックスに文字が「何か1文字でも入力されていたら」処理を進める、条件分岐のスイッチ -
「
st.progress(...)」 → 「今何%まで完了したか」を緑色のメーターで表示して、作業中のユーザーを安心させる進捗バー作成処理 -
「
my_bar.empty()」 → データ収集が終わった瞬間に、用済みになった進捗バーを画面からスッキリ消し去る命令 -
「
st.table(...)」 → 集めてきたデータを、誰が見ても分かりやすい綺麗な「固定一覧表(テーブル)」として画面に描画する処理
🌐 通信・ブラウザ偽装の命令
-
「
headers = {"User-Agent": ...}」 → 「私はプログラムではなく、普通のパソコンのChromeブラウザですよ」とWebサイトを安心させるための「変装用身分証明書」 -
「
requests.get(url, headers=headers)」 → 指定したURLのWebサイトにアクセスして、ページ丸ごとの裏側データ(HTML)をダウンロードして持ってくる通信命令 -
「
response.raise_for_status()」 → もしページが開けなかったりアクセス拒否(403エラーなど)された場合に、無理に続けず「失敗しました!」と安全にストップをかけるガード処理 -
「
try: ... except Exception as e:」 → 万が一通信エラーやバグが起きてもアプリ全体をクラッシュさせず、画面に分かりやすくエラー原因を表示して安全に受け止める「安全ネット」
🔍 HTMLからピンポイントで情報をつかむ命令
-
「
BeautifulSoup(..., 'html.parser')」 → ダウンロードしてきた生HTML(記号だらけの文字の山)を、プログラムが宝探ししやすい「地図付きデータ」に変換する解析メガネ -
「
soup.select('.event_list.vevent')」 → ページ全体の中から「イベント1件分が入っている枠組み(部屋番号)」だけをすべて見つけ出し、リストにまとめる処理 -
「
card.select_one('.event_title a')」 → イベントの部屋の中から、タイトルとリンク先が隠れている「特定の場所」を1つだけピンポイントで探す命令 -
「
get_text(strip=True)」 → HTMLタグ(< p >や< a >など)の余計な記号や無駄な改行を取り除き、人間が読みたい「純粋なテキスト文字」だけを綺麗に抜き出す処理 -
「
d_soup.find('th', string=...)」 → 詳細ページの表の中から「開催日時」や「会場」という文字が書かれた見出し枠(thタグ)をピンポイントで探す命令 -
「
find_next_sibling('td')」 → 見つけた見出し枠の「すぐ右隣にあるセル(tdタグ)」に移動して、そこに書かれている本当のデータ(日時や住所)をつかむ命令
📊 データ整理・保存・検索の命令
-
「
events.append({...})」 → 抜き出した「日時・タイトル・場所・チケット・URL」を1つのセットにして、データ用バケツ(リスト)に順番に放り込んでいく処理 -
「
pd.DataFrame(events)」 → バケツに溜まったバラバラのデータセットを、Excelのような「縦と横の綺麗な表(データフレーム)」に一瞬で組み上げる変換命令 -
「
pd.read_csv("result.csv", encoding="utf-8-sig")」 → さっきスクレイピングで作ったExcel(CSV)ファイルをPandasの力で丸ごと読み込み、Pythonが高速で中身を検索できるデジタルデータ(データフレーム)に変換する命令 -
「
encoding="utf-8-sig"」 → パソコンの数字と人間の文字を変換する「翻訳辞書」。ExcelとPythonの両方で文字化けせずに日本語が完璧に通じるルール
詰まったところ1
プログラムでConnpassのページを読み込んだものの、イベントが1件も表示されず「イベントが見つかりませんでした」というエラーが出続けていました。
原因
「イベント情報はきっとこの場所(クラス名)に書かれているだろう」と推測して指定していた名前(.event_item など)が、実際のConnpassのHTML構造とズレていたためです。
解決したアクション
ブラウザでConnpassのWebサイトを開き、画面を右クリックして「検証(デベロッパーツール)」を開き、イベント枠の実際のHTMLコードをとってきた。
結果
教えてもらった生HTMLから、実際の目印が .event_list.vevent(divタグのクラス名)であることを特定でき、プログラムが正確にイベントを拾い上げられるようになりました。
詰まったところ2
プログラムを実行した際、Connpassのサーバーから「アクセスがブロックされました」と拒否され、検索結果が1件も読み込めなくなりました。
原因
Pythonコードの書き方に文法的な間違いがあるわけではないのに、Webサイト側のセキュリティ(自動ボット対策)によって通信を遮断されてしまったためです。
解決したアクション
プログラムの通信設定に「私は自動プログラムではなく、通常のPCのChromeブラウザですよ」と示す身分証明情報(User-Agent ヘッダー)を追加し、ブラウザのフリをしてアクセスすることでサーバーのガードを突破しました。
実際に書いたコード
import streamlit as st
import requests
from bs4 import BeautifulSoup
import pandas as pd
from datetime import date
st.set_page_config(layout="wide")
st.title("🚀 復活のインターン検索システム")
keyword = st.text_input("キーワードを入力:", "インターン")
if st.button("検索開始"):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
today = date.today().strftime("%Y/%m/%d")
search_url = f"https://connpass.com/search/?q={keyword}&start_from={today}&sort=2"
try:
response = requests.get(search_url, headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
cards = soup.select('.event_list.vevent')
if not cards:
st.warning("イベントが見つかりませんでした。")
else:
events = []
progress_text = "イベント詳細を収集中..."
my_bar = st.progress(0, text=progress_text)
for i, card in enumerate(cards):
title_tag = card.select_one('.event_title a')
if not title_tag:
continue
title = title_tag.get_text(strip=True)
url = title_tag['href']
# --- ここから詳細ページの取得エンジン ---
d_res = requests.get(url, headers=headers)
d_soup = BeautifulSoup(d_res.text, 'html.parser')
# 1. 日時の取得(「開催日時」の隣のセルを探す)
time_th = d_soup.find('th', string=lambda text: text and '開催日時' in text)
if time_th and time_th.find_next_sibling('td'):
raw_time = time_th.find_next_sibling('td').get_text(separator=' ', strip=True)
# 「Googleカレンダー」などの余計なボタン文字をカット
event_time = raw_time.split('Google')[0].strip()
else:
event_time = "不明"
# 2. 場所の取得(「会場」の隣のセルを探す)
venue_th = d_soup.find('th', string=lambda text: text and '会場' in text)
if venue_th and venue_th.find_next_sibling('td'):
raw_location = venue_th.find_next_sibling('td').get_text(separator=' ', strip=True)
event_location = raw_location.split('マップで見る')[0].strip()
else:
event_location = "未定 / オンラインなど"
# 3. チケット内訳の取得
ptypes = d_soup.select('.ptype')
ticket_info = []
for ptype in ptypes:
name = ptype.select_one('.ptype_name')
parts = ptype.select_one('.participants')
if name and parts:
ticket_info.append(f"{name.get_text(strip=True)}: {parts.get_text(strip=True)}")
ticket_str = " / ".join(ticket_info) if ticket_info else "情報なし"
# 表に追加
events.append({
"日時": event_time,
"イベント名": title,
"場所": event_location,
"チケット": ticket_str,
"URL": url
})
# 進捗バーを更新
my_bar.progress((i + 1) / len(cards), text=f"データ収集中... ({i+1}/{len(cards)}件完了)")
# 完了したらバーを消してテーブルを表示
my_bar.empty()
st.table(pd.DataFrame(events))
except Exception as e:
st.error(f"エラーが発生しました: {e}")