iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0
自我挑戰組

BeautifulSoup網頁爬蟲佐Django伺服器框架附AWS雲端運算服務系列 第 19

[Day 19] 第一主餐 pt.11-財報資料,我全都要

  • 分享至 

  • xImage
  •  

上一篇我們修改了資料庫
並且成功地把BeautifulSoup的資料送到Database內了
今天我們就要來把所有的資料都撈進Database啦
廢話不多說,咱們累狗

能自動就不要手動 - 一鍵撈取所有財報

上一篇我們把單一的公司季財報撈出來了
這邊我們準備把所有公司的所有財報撈出來啦
啊對,撈之前記得清Django的Database

今天我們不會進django看看他了
畢竟models views那些東東我們都架好了
今天就只會改BeautifulSoup的部分
首先最重要的,就是先找所有公司代碼
這裡我們就要改去台灣證券交易所啦
https://www.twse.com.tw/zh/page/listed/listed_company/new_listing.html
這裡就是所有上市公司
可是他的預設只有10筆公司怎辦呢
沒關係,咱們看看上面有"列印/HTML"
這裡點進去就可以看到所有公司啦

那這邊的url自然就是所有公司的HTML原始碼連結啦
廢話不多說,撈

import requests
import json
from bs4 import BeautifulSoup
# 所有上市公司列表url
url = 'https://www.twse.com.tw/company/newlisting?response=html&yy='
# 取得所有上市公司原始碼
res = requests.get(url=url)
# 用BeautifulSoup分析HTML
soup = BeautifulSoup(res.text, 'html.parser')
# 取得table內容
table_body = soup.find("tbody")
# 將所有公司id存成list
all_comp_id = []
#將每個tr取出
for i in table_body.find_all('tr'):
    #取出公司ID
    inte = i.find_all('td')[0].getText()
    # 6位數代碼為存託公司,不在我們分析範圍,因此剔除
    if int(inte) < 100000:
        all_comp_id.append(all_comp_id)

這樣我們就把所有公司撈出來啦

接下來就是把公司每季財報撈出來啦
這裡我們先回頭看原本POST的data

data={
        'co_id': '1201',
        'queryName': 'co_id',
        'inputType': 'co_id',
        'isnew': 'true',
        'TYPEK': 'all',
        'encodeURIComponent': '1',
        'step': '1',
        'firstin': '1',
        'off': '1',
        'year': None,
        'season': None
}

可以看到co_id就是公司id部分啦
然後這裡isnew代表是否直接撈最新財報
這裡我們改成false
然後我們撈財報的範圍根據查詢只有105年~109年的資料
然後109年只有兩季
所以我們要寫一個迴圈去改data內year跟season的
所以我們的data先改寫成這樣

data={
        'co_id': co_id,
        'queryName': 'co_id',
        'inputType': 'co_id',
        'isnew': 'false',
        'TYPEK': 'all',
        'encodeURIComponent': '1',
        'step': '1',
        'firstin': '1',
        'off': '1',
        'year': year,
        'season': season
}

然後python有個range可以迭代範圍內的數字
記得range含頭不含尾
所以我們的迴圈寫成如下:

for year in range(105, 110): #105含,110不含
    season_range = 4 #預設撈四季財報
    if year == 109:
        season_range = 2 #若是109年則只撈前2
    for season in range(1, season_range+1): #從1開始到n
        for co_id in all_comp_id: #剛剛存的所有公司id
        ...

最後有些公司可能是在106年後建立的
所以可能會有找不到財報的情況
就像最知名的八方雲集,108年第一季就沒有財報

老牌公司味全就有108第一季財報

因此我們萬一沒撈到財報就要跳過
這特徵也不難找,反正找不到財報時就會跳"查詢無資料"
所以我們就設一個條件,如果在湯裡面找到"查詢無資料"這個字串就跳過
如下面code所示

if bool(soup.findAll(text="查詢無資料")):
    print("查詢無資料")
    continue

把以上CODE加上之前寫的CODE合併,我們的BeautifulSoup的code部分應該就會變成如下

import requests
import json
from bs4 import BeautifulSoup

#================撈取所有公司part==================
# 所有上市公司列表url
url = 'https://www.twse.com.tw/company/newlisting?response=html&yy='
# 取得所有上市公司原始碼
res = requests.get(url=url)
# 用BeautifulSoup分析HTML
soup = BeautifulSoup(res.text, 'html.parser')
# 取得table內容
table_body = soup.find("tbody")
# 將所有公司id存成list
all_comp_id = []
#將每個tr取出
for i in table_body.find_all('tr'):
    #取出公司ID
    inte = i.find_all('td')[0].getText()
    # 6位數代碼為存託公司,不在我們分析範圍,因此剔除
    if int(inte) < 100000:
        all_comp_id.append(inte)
        
#================撈取財報part==================
for year in range(105, 110): #105含,110不含
    season_range = 4 #預設撈四季財報
    if year == 109:
        season_range = 2 #若是109年則只撈前2
    for season in range(1, season_range+1): #從1開始到n
        for co_id in all_comp_id: #剛剛存的所有公司id
            sheet_url = 'https://www.twse.com.tw/company/newlisting?response=html&yy='
            data={
                    'co_id': co_id,
                    'queryName': 'co_id',
                    'inputType': 'co_id',
                    'isnew': 'false',
                    'TYPEK': 'all',
                    'encodeURIComponent': '1',
                    'step': '1',
                    'firstin': '1',
                    'off': '1',
                    'year': 108,
                    'season': 1
            }
            headers = {
                #'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36',
            }
            res = requests.post(url=sheet_url,data=data,headers=headers)
            soup = BeautifulSoup(res.text, 'html.parser')
            #若查詢無資料,則顯示該公司該年該季度查詢無資料之提示,並直接進行下一迴圈
            if bool(soup.findAll(text="查詢無資料")):
                print("公司代碼:{} {}年{}季 查詢無資料".format(comp_id, year ,season))
                continue
            tr_tag = soup.find_all("tr", {"class": ["odd", "even"]})
            data_table = {} #公司財務報表
            balance_sheet = {} #負債表
            income_statement = {} #損益表
            for i in tr_tag:
                td_tag = i.find_all("td")
                if len(td_tag) == 3: #三個td tag代表為負債表資料
                    inner = []
                    for j in td_tag:
                        inner.append(j.getText())
                    balance_sheet[inner[0]] = {'金額': inner[1], '百分比': inner[2]}
                if len(td_tag) == 5: #五個td tag代表為損益表資料
                    inner = []
                    for j in td_tag:
                        inner.append(j.getText())
                    income_statement[inner[0]] = {'金額': inner[1], '預測金額': inner[2], '年度財務預測達成率': inner[3], '截至第2季止財務預測季達成率': inner[4]}
            url = "http://172.16.15.123:8000/stonks/set_stonks_data/"
            data={'comp_id':co_id,
                'year':year,
                'season':season,
                'balance_sheet':json.dumps(balance_sheet),
                'income_statement':json.dumps(income_statement)}
            res_post = requests.post(url=url,data=data,headers=headers)
            
            #如果回傳status code非200,則代表出錯,印出該公司該年度該季財報錯誤
            if res_post.status_code != 200: 
                print("公司代碼:{} {}年{}季 存入資料庫錯誤".format(comp_id, year ,season))
                
            #若回傳200則提示成功訊息
            else:
                print("公司代碼:{} {}年{}季 存入資料庫成功".format(comp_id, year ,season))

最後執行

成功啦~剩下等他自動執行完畢就好了

以上就是自動撈取所有財報的內容啦
然後先預告一下
由於本人明天要回台中
因此下一篇會再做一次中場休息
我們會來講一下github這個東東,以及如何把你的code丟到github上
想知道如何把你的code存到github這個地方
咱們下回分解~


上一篇
[Day 18] 第一主餐 pt.10-中文資料存料至文中,django如何存取中文
下一篇
[Day 15] 中場休息-GitHub,團隊自用兩相宜的code管理服務平台
系列文
BeautifulSoup網頁爬蟲佐Django伺服器框架附AWS雲端運算服務30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言