請啟用JavaScript來查看內容

[Python爬蟲實例] Anue 鉅亨網:爬取最新財經新聞

前言

好久沒有更新 Python網路爬蟲實例系列 文章了,今天換來看財經與投資的相關新聞。

「Anue 鉅亨網」提供國內外財經相關資訊,我們來透過 Python 網路爬蟲抓取即時頭條新聞,掌握最新消息。

圖片來源:Anue鉅亨網 - 即時頭條新聞
圖片來源:Anue鉅亨網 - 即時頭條新聞

備註:此文僅教育學習,切勿用作商業用途,個人實作皆屬個人行為,本作者不負任何法律責任


套件

此次 Python 爬蟲主要使用到的套件:

安裝

1
pip install requests

流程說明

找找新聞如何被載入

首先進入 Anue 鉅亨網 的 即時新聞列表 網頁,來觀察看看其新聞列表載入方式。

可以試著將滾輪往下滾,網頁會一直往下,它新聞也會被一直載入進來,推測應該是採用動態載入的方式。

打開瀏覽器的 開發人員工具 (F12 或 Ctrl + Shift + i),切換到 "Network" > "Fetch/XHR",往下滾動新聞頁面,會尋找到有個 headline?page=2&limit=30... 的請求,並且點開後在 "Preview" 分頁查看,就會發現裡面包含新聞的相關資料。

那就沒錯了,這就是我們想要抓取的部分!💪

請求 "Preview" 分頁,找到我們想要的資料
請求 "Preview" 分頁,找到我們想要的資料

請求方式與參數

切換回 "Headers" 分頁,看一下此資料請求的方式與網址。
使用 GET 請求方式,網址類似 https://api.cnyes.com/media/api/v1/newslist/category/headline?page=2&limit=30&isCategoryHeadline=1&startAt=1710295609&endAt=1711159609

請求 "Headers" 分頁
請求 "Headers" 分頁

我們先來觀察網址後方的參數代表甚麼意思。

page=2&limit=30&isCategoryHeadline=1&startAt=1710295609&endAt=1711159609

pagelimit 很明顯就是代表「頁數」跟「一頁幾則新聞」。
(如果不太懂這兩個參數,可以回去看看我之前寫的文章:(圖解) 網路爬蟲 API 常見的 3 種「翻頁」方式)

isCategoryHeadline 可以代入 0 或 1,差別是回傳資料的 coverSrc 欄位裡面有沒有包含新聞封面圖片。

startAtendAt 是新聞範圍的時間 (以時間戳格式),並且有限定指定的時間只能兩年內。

新聞時間範圍有限定兩年內
新聞時間範圍有限定兩年內

這些參數就算不代入,也會有預設值,所以以下程式範例只使用到 pagelimit 參數來示範教學。

回傳內容

可以將網址貼到瀏覽器的網址欄位中,查看回傳的資料。

請求回傳資料
請求回傳資料

items 裡欄位代表意思如下表:

欄位代表意思
total全部新聞總數
per_page一頁新聞數
current_page當前頁數
last_page最後頁數
prev_page_url前一頁網址
next_page_url下一頁網址
from此頁新聞第一筆
to此頁新聞最後一筆
data各新聞資訊

而 items 裡的 data 新聞資訊,有包含新聞標題、內文、關鍵字、發布時間、分類……等等。

  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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
{
    "items": {
        "total": 1007,
        "per_page": 30,
        "current_page": 1,
        "last_page": 34,
        "next_page_url": "/media/api/v1/newslist/category/headline?limit=30&page=2",
        "prev_page_url": null,
        "from": 1,
        "to": 30,
        "data": [
            {
                "newsId": 5501189,
                "title": "OpenAI旗下Sora進軍好萊塢電影產業",
                "content": "<p>市場週五 (22 日) 傳出,OpenAI 計劃進軍電影業,已安排下週與好萊塢工作室和人才機構舉行會議,鼓勵電影製作人和工作室在工作中使用人工智慧。他們已經向一些大牌演員和導演推廣了人工智慧影片製作軟體 Sora。</p>\n\n<p>OpenAI 試圖電影業人員構建娛樂產業的合作夥伴關係、並鼓勵眾多製片公司將 OpenAI 的新款 AI 影音生成器融入它們的工作中。</p>\n\n<p>OpenAI 向好萊塢推廣其文字生成影音 AI 服務 Sora,OpenAI CEO Altman 已經在奧斯卡電影節週末出席洛杉磯的多場派對。</p>\n\n<figure><img alt="(圖片:翻攝smartprix)" data-height="416" data-mime="image/jpeg" data-ratio="1.8269230769230769" data-src-m="https://cimg.cnyes.cool/prod/news/5501189/m/961b1580a9294bfceeccfc6b86fec545.jpg" data-width="760" src="https://cimg.cnyes.cool/prod/news/5501189/l/961b1580a9294bfceeccfc6b86fec545.jpg">\n<figcaption>OpenAI 旗下 Sora 進軍好萊塢,下周將開會 (圖:OpenAI)</figcaption>\n</figure>\n\n<p>Sora 是 Open AI 公司繼文本模型 ChatGPT、圖像模型 Dall-E 撼動了全世界之後,於今年 2 月 15 日發布的文生影像模型,可根據文字描述產生 60 秒的影像,這引發好萊塢巨大震撼。</p>\n\n<p>電影攝影師、動畫師和電影製片對其生成的影音品質大感震驚。Sora 目前只能生成約一分鐘的影片,且缺乏對物理作用的了解,但還在持續學習,而其學習方式正是好萊塢和其他產業的最擔心之處</p>\n\n<p>好萊塢導演暨製片人派瑞已率先發出警告。他在看過 Sora 影音後已「無限期」暫緩 8 億美元的工作室擴展計畫。</p>\n\n<p>大華國際投顧阮蕙慈表示,對於投資人來說,Sora 的橫空出世絕對是要留意的重要產業趨勢之一,其影響性又遠大於其他現有的生成式 AI 相關應用。Sora 的誕生,意味著影像生成門檻大幅降低,不僅對廣告、影視、短視頻等相關行業引發巨大變革,而且對於算力、傳輸速度、儲存空間的需求更是現有好幾倍的成長。</p>\n",
                "hasCoverPhoto": 1,
                "isIndex": 1,
                "summary": "市場週五 (22 日) 傳出,OpenAI 計劃進軍電影業,已安排下週與好萊塢工作室和人才機構舉行會議,鼓勵電影製作人和工作室在工作中使用人工智慧。他們已經向一些大牌演員和導演推廣了人工智慧影片製作軟體 Sora。",
                "isCategoryHeadline": 1,
                "stock": [],
                "video": "",
                "payment": 0,
                "feature": 0,
                "otherProduct": [],
                "source": null,
                "isOutsource": 0,
                "keyword": [
                    "Sora",
                    "OpenAI",
                    "ChatGPT",
                    "好萊塢"
                ],
                "is24h": 1,
                "publishAt": 1711137477,
                "coverSrc": {
                    "xs": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501189/xs/50120aeff052a284a8c5136c4cb945a5.jpg",
                        "width": 100,
                        "height": 56
                    },
                    "s": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501189/s/50120aeff052a284a8c5136c4cb945a5.jpg",
                        "width": 180,
                        "height": 101
                    },
                    "m": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501189/m/50120aeff052a284a8c5136c4cb945a5.jpg",
                        "width": 380,
                        "height": 214
                    },
                    "l": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501189/l/50120aeff052a284a8c5136c4cb945a5.jpg",
                        "width": 640,
                        "height": 360
                    },
                    "xl": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501189/xl/50120aeff052a284a8c5136c4cb945a5.jpg",
                        "width": 960,
                        "height": 540
                    },
                    "xxl": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501189/xl/50120aeff052a284a8c5136c4cb945a5.jpg",
                        "width": 960,
                        "height": 540
                    }
                },
                "abTesting": null,
                "categoryId": 831,
                "categoryName": "美股雷達",
                "columnists": null,
                "fundCategoryAbbr": [],
                "etf": [],
                "fbShare": 0,
                "fbComment": 0,
                "fbCommentPluginCount": 0
            },
            {
                "newsId": 5501177,
                "title": "傳蘋果放棄自研手錶Micro LED計畫 裁員數十位工程師",
                "content": "<p>根據彭博周五 (22 日) 援引知情人士消息報導,蘋果正逐步結束自研智慧手錶 Micro LED 螢幕計畫,而且已經在重組該團隊並在亞洲和美國裁撤數十位工程師。報導指出,原因是該工作的成本太高、過程也太複雜,因此決定結束這項耗資龐大的研發計畫。</p>\n\n<p>報導指出,結束手錶螢幕自研計畫的同時,蘋果先前也取消研發自駕汽車的工作。在這兩種情況下,蘋果至少給一些受影響的員工在公司找到其他職缺的機會,倘若內部轉職未果便會遭到資遣命運。</p>\n\n<p>蘋果目前認為 OLED 是其智慧手錶的最佳解決方案,但知情人士說,該公司仍在考慮在未來的其他專案中使用 microLED。蘋果正在尋找潛在的新供應商和流程,讓該技術能應用在其設備中,儘管這不太可能很快實現。</p>\n\n<p>對於上述報導,蘋果發言人拒絕置評請求。截稿前,蘋果 (AAPL-US) 周五盤中股價上漲 0.69%,每股暫報 172.56 美元。</p>\n\n<p>自研計畫是蘋果推動更多內部技術設計的更廣泛努力的一部分。雖然該公司已經在其產品中客製化螢幕,但在很大程度上是基於樂金顯示公司 (LG Display, LGD) 和三星 SDI 等合作夥伴的設計。透過在蘋果內部引入更多這項流程,該公司希望獲得相對於競爭對手的優勢。</p>\n\n<p>蘋果硬體工程部門大約 7 年前開始了這項工作,後來這個代號為 T159 的計畫幾年前被轉移到了蘋果的硬體技術部門。</p>\n\n<p>蘋果甚至在總部附近建立了自己的螢幕製造工廠,數百名員工可以在該廠測試 microLED 螢幕的生產。許多裁員都涉及該工廠的人員,以及蘋果在亞洲靠近其供應鏈中心的顯示工程中心。本周對蘋果位於聖克拉拉工廠的訪問顯示,該大樓仍在運行,停車場裡有汽車,少數員工進出大樓。</p>\n\n<p>最近幾周,有關該計畫轉變的消息首次出現,當時供應商宣布他們正在失去與 microLED 相關的合約,其中包括 AMS-Osram AG。該公司表示,取消收購將迫使其裁員,可能會出售一家製造工廠,並記錄一筆可能接近 10 億美元的減記。</p>\n\n<p class="warning">本篇文章不提供合作夥伴轉載</p>\n",
                "hasCoverPhoto": 1,
                "isIndex": 1,
                "summary": "根據彭博周五 (22 日) 援引知情人士消息報導,蘋果正逐步結束自研智慧手錶顯示螢幕 Micro LED 計畫,而且已經在重組該團隊並在亞洲和美國裁撤數十位工程師。報導指出,原因是該工作的成本太高、過程也太複雜,因此決定結束這項耗",
                "isCategoryHeadline": 1,
                "stock": [
                    "US-AAPL"
                ],
                "video": "",
                "payment": 0,
                "feature": 0,
                "otherProduct": [
                    "USS:AAPL:STOCK:COMMON"
                ],
                "source": null,
                "isOutsource": 0,
                "keyword": [
                    "蘋果",
                    "Micro LED",
                    "裁員",
                    "產業",
                    "開發",
                    "Apple Watch"
                ],
                "is24h": 1,
                "publishAt": 1711132206,
                "coverSrc": {
                    "xs": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501177/xs/f888c80709d77e7ad0f2dfb96bbf8b1d.jpg",
                        "width": 100,
                        "height": 56
                    },
                    "s": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501177/s/f888c80709d77e7ad0f2dfb96bbf8b1d.jpg",
                        "width": 180,
                        "height": 101
                    },
                    "m": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501177/m/f888c80709d77e7ad0f2dfb96bbf8b1d.jpg",
                        "width": 380,
                        "height": 214
                    },
                    "l": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501177/l/f888c80709d77e7ad0f2dfb96bbf8b1d.jpg",
                        "width": 640,
                        "height": 360
                    },
                    "xl": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501177/xl/f888c80709d77e7ad0f2dfb96bbf8b1d.jpg",
                        "width": 960,
                        "height": 539
                    },
                    "xxl": {
                        "src": "https://cimg.cnyes.cool/prod/news/5501177/xxl/f888c80709d77e7ad0f2dfb96bbf8b1d.jpg",
                        "width": 1080,
                        "height": 607
                    }
                },
                "abTesting": null,
                "categoryId": 831,
                "categoryName": "美股雷達",
                "columnists": null,
                "fundCategoryAbbr": [],
                "etf": [],
                "fbShare": 0,
                "fbComment": 0,
                "fbCommentPluginCount": 0,
                "market": [
                    {
                        "code": "AAPL",
                        "name": "蘋果",
                        "symbol": "USS:AAPL:STOCK"
                    }
                ]
            }
            ...
        ]
    },
    "message": "成功",
    "statusCode": 200
}

* 為了方便觀察,也可以使用 JSON Editor Online 線上工具來輔助。

可以使用 JSON Editor Online 線上工具來輔助觀察
可以使用 JSON Editor Online 線上工具來輔助觀察

完整程式碼

 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
import time
import random
import requests


class CnyesNewsSpider():
    
    def get_newslist_info(self, page=1, limit=30):
        """ 房屋詳情

        :param page: 頁數
        :param limit: 一頁新聞數量
        :return newslist_info: 新聞資料
        """
        headers = {
            'Origin': 'https://news.cnyes.com/',
            'Referer': 'https://news.cnyes.com/',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
        }
        r = requests.get(f"https://api.cnyes.com/media/api/v1/newslist/category/headline?page={page}&limit={limit}", headers=headers)
        if r.status_code != requests.codes.ok:
            print('請求失敗', r.status_code)
            return None
        newslist_info = r.json()['items']
        return newslist_info


if __name__ == "__main__":
    cnyes_news_spider = CnyesNewsSpider()
    newslist_info = cnyes_news_spider.get_newslist_info()
    
    print(f'搜尋結果 > 全部新聞總數:{newslist_info["total"]}')
    print(f'搜尋結果 > 一頁新聞數:{newslist_info["per_page"]}')
    print(f'搜尋結果 > 當前頁數:{newslist_info["current_page"]}')
    print(f'搜尋結果 > 最後頁數:{newslist_info["last_page"]}')
    print(f'搜尋結果 > 前一頁網址:{newslist_info["prev_page_url"]}')
    print(f'搜尋結果 > 下一頁網址:{newslist_info["next_page_url"]}')
    print(f'搜尋結果 > 此頁新聞第一筆:{newslist_info["from"]}')
    print(f'搜尋結果 > 此頁新聞最後一筆:{newslist_info["to"]}')
    
    for news in newslist_info["data"]:
        print(f'    ------------ {news["newsId"]} ------------')
        print(f'    新聞 > URL:https://news.cnyes.com/news/id/{news["newsId"]}')
        print(f'    新聞 > 標題:{news["title"]}')
        print(f'    新聞 > 概要:{news["summary"]}')
        # print(f'    新聞 > 內文:{news["content"]}')
        print(f'    新聞 > 關鍵字:{news["keyword"]}')
        print(f'    新聞 > 發布時間:{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(news["publishAt"]))}')
        print(f'    新聞 > 分類:{news["categoryName"]} (id:{news["categoryId"]})')
        print()
        

    # 如果要爬取多頁新聞,建議加入隨機 delay 一段時間,避免被反爬蟲偵測
    # time.sleep(random.uniform(2, 5))


延伸練習

  1. 除了我上面示範的 pagelimit 參數,我們可以發現還有 isCategoryHeadlinestartAtendAt,你能試著將其加入到程式碼內嗎?
  2. 我們上面是抓取「即時頭條」,你有辦法改成只抓「台股新聞」這個分類嗎?

結語

學習了基本的網路爬蟲,後續還可以把新聞抓下來後,再透過關鍵字,將新聞做個人化的篩選、分類,甚至串接 LINE Notify 推播訊息📣給自己。


我陸續有在寫一些網站的 Python網路爬蟲實例,如果你正好是剛開始想學爬蟲的新手、想知道某個網站如何爬取資料,又或遇到其他問題,歡迎參考和在底下留言支持我~💬




未來從現在開始!


🔻 如果覺得喜歡,歡迎在下方獎勵我 5 個讚~
分享

Jia
作者
Jia
軟體工程師