File size: 4,887 Bytes
a08962e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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