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 | |