import requests from bs4 import BeautifulSoup import re from time import sleep class Scraper: def __init__(self): """ Scraperクラスを初期化し、requestsセッションを作成 """ self.session = requests.Session() def _fetch_content(self, url): """ 指定されたURLのコンテンツを取得する Parameters: - url (str): 取得するウェブページのURL Returns: - content (bytes): 取得したコンテンツのデータ """ response = self.session.get(url) response.raise_for_status() # HTTPエラーが発生した場合は例外を投げる return response.content def _parse_html(self, html): """ HTMLコンテンツをBeautifulSoupでパース Parameters: - html (bytes): パースするHTMLコンテンツ Returns: - soup (BeautifulSoup): パースされたBeautifulSoupオブジェクト """ soup = BeautifulSoup(html, 'html.parser') return soup class YahooNewsScraper(Scraper): base_url = "https://news.yahoo.co.jp/" def get_news_urls(self): """ Yahooニュースのトップページから最新ニュース記事のURLを取得 Parameters: - なし Returns: - article_url_list (list): ニュース記事のURLリスト(最大5件) """ content = self._fetch_content(self.base_url) soup = self._parse_html(content) news_list = soup.select('section.topics a') # 'topics'セクション内のすべてのタグを選択 article_url_list = [tag.get('href') for tag in news_list if tag.get('href')] # href属性を抽出 return article_url_list[:5] # 最初の5つのURLを返す def get_article_url(self, index=0): """ 指定したインデックスのニュース記事のURLを取得する Parameters: - index (int): 取得したい記事のインデックス (デフォルトは0) Returns: - article_url (str): 指定されたインデックスの記事のURL Raises: - IndexError: インデックスが範囲外の場合に発生 """ article_urls = self.get_news_urls() if index >= len(article_urls): raise IndexError("URLが取得できませんでした") # インデックスが範囲外の場合は例外を投げる return article_urls[index] def get_article_detail_url(self, article_url): """ 記事ページから詳細記事のURLを取得する Parameters: - article_url (str): ニュース記事のURL Returns: - detail_url (str): 記事の詳細ページのURL Raises: - ValueError: 詳細ページのURLが見つからない場合に発生 """ content = self._fetch_content(article_url) soup = self._parse_html(content) detail_url_tag = soup.select_one('a:-soup-contains("記事全文を読む")') # "記事全文を読む"を含むリンクを選択 if detail_url_tag: return detail_url_tag.get('href') # タグのhref属性を返す else: raise ValueError("ニュース記事が見つかりませんでした") # タグが見つからない場合はエラーを出力 def get_full_article_text(self, detail_url): """ 詳細記事の全文を取得し、不要な文字を削除する Parameters: - detail_url (str): 記事の詳細ページのURL Returns: - full_text (str): 記事の全文テキスト """ content = self._fetch_content(detail_url) soup = BeautifulSoup(content, 'html.parser') paragraphs = soup.select('article div.article_body p') # 記事本文内のすべての

タグを選択 full_text = ''.join([p.text for p in paragraphs]) # すべての段落のテキストを結合 return re.sub(r"[\u3000\n\r]", "", full_text) # 不要な文字を削除 def scrape_article(self, index=0): """ 指定されたインデックスの記事をスクレイプし、全文を取得する Parameters: - index (int): スクレイプする記事のインデックス (デフォルトは0) Returns: - full_text (str): スクレイプされた記事の全文テキスト """ article_url = self.get_article_url(index) sleep(1) # サーバー負荷を避けるために1秒待機 detail_url = self.get_article_detail_url(article_url) sleep(1) # サーバー負荷を避けるためにさらに1秒待機 article_text = self.get_full_article_text(detail_url) return article_text, detail_url