Spaces:
Sleeping
Sleeping
| 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'セクション内のすべての<a>タグを選択 | |
| 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') # 記事本文内のすべての<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 | |