0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python学習Day50~57で学んだこと

0
Last updated at Posted at 2026-08-06

インターンシップの最新情報をまとめるサイトを作る

学んだこと(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}")
0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?