[Day 5] 餐前浓汤 pt.2-BeautifulSoup meets Stocks

上一篇我们设定完了vagrant,安装完了BeautifulSoup
这一篇我们就要来让BeutifulSoup正式发功啦
废话不多说,砸们累狗~

BeautifulSoup的第一大魔王:

好的,根据我们专业股市分析团队a.k.a财报狗的书籍指出
要知道哪支股票有潜力,首先就要了解公司财报
因此我们就先来把公司财报的资料捞出来吧
首先先进我们的公开资讯观测站的财报网页,这里我们采IFRSs後
传送们在这https://mops.twse.com.tw/mops/web/t163sb01
然後一进去之後我们就会发现
就会发现...

啊我的财报资料勒,啊挖A财报资料勒
没错,这里网页使用了一个相当特殊的方式呈现资料
怎麽个特殊法呢,这里我们先使用一个魔法
首先先看到你的键盘,看到了齁
按下那颗可爱的F12
或是你也可以抬起头来,再网页空白处点选右键,选择检查

好的你的网页下面左边右边或上面,反正其中一面应该会出现像是console的东东
这个东西就叫做开发人员工具,专门用来监控修改网页资料用的
不过别担心,这些修改都只会呈现在你的本地端而已
啊如果你真的把人家的网页改成功了,相信我,该愧疚的不是你,是那些写网页的
回到正题,我们把这边的选项选成network

之後我们在公司代号或简称栏位随便输入,这里就输入1201,然後查询

可以发现我们的console多了好几个东东,其中一个叫做ajax_t163sb01
这就代表网页呈现方式是用ajax方式动态呈现的
你直接捞只会捞到静态框架这些空气而已

那怎麽办呢?简单~
ajax这东西说穿了其实也只是用POST方式送出request把资料捞回来做动态更新元件而已
因此我们只要在送request之前多一个header,然後把我们要送出去的data用dict包起来一起送出去就好
程序码如下

import requests
import json
url = 'https://mops.twse.com.tw/mops/web/ajax_t163sb01'
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
}
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=url,data=data,headers=headers)
file = open('res.html', 'w', encoding="utf-8")
file.write(res.text)
file.close()

第一二行不用说,就是把套件import进来
由於json套件python已经帮你内建好了就不用下载了
第三行是你要送的url目的地
第四到第十六行就是你要送的data内容
比较需要提的地方有两个
第一个是co_id 代表公司代号
第二个是isnew,这代表是否直接捞最新财报资料
是的话就设定true(记得是要用字串传,不是bool),就会捞回醉金财报
否的话就设定false,然後财报的年度跟季度都要填,分别填在year跟season栏位
第十七到十九行是设定header,就是跟server讲说你何许人也
虽然这里server好像也不会检查就是
最後就是送出request,并且把结果用res接住啦
这里的最後我们用点比较不一样的方式输出结果
我们开启一个file物件,然後把这物件设定成写入模式,档名叫做res.html,後面记得编码模式选utf-8以免报错
然後我们把我们的res的原始码存到file内就好啦
记得最後要把file这个class关掉释放记忆体

好的我们就可以来执行看看结果如何啦

一样刚刚讲过了,python是个沉默寡言的人,只要你不print不搞事,他是不会有任何反应的
不过大家可以看到在我们的py档旁边多了一个我们刚刚定义的res.html档

点进去看如果是长这样,那就表示捞取成功啦~

帮我把牛魔刀拿来: 开始支解HTML原始码

前面提到BeautifulSoup最重要的目的就是把HTML原始码做分割,取出我们要的部分
所以这个环节我们就要来实际开切HTML啦
HTML:

师承前面的code,我们先把file output的部分,也就是最後三行给删除
除此之外,我们会需要原始页面来帮助我们寻找我们要的部分
所以一样,我们先在财报页面输入1201,然後按下查询
此时你的页面应该长这样

接着我们就要来找哪些部份是我们要的资讯啦
这次我们先把流动资产这一栏资料给捞出来吧,那怎麽捞呢?

我们对流动资产这四的字的区域按下右键>检查

就可以看到这个资料是在原始码的哪个区域
所以我们可以看到这笔资料是由一个tr的html tag包起来的
因此我们就先把所有有tr tag的资料拿出来
首先记得在档案开头引用我们的bs4的BeautifulSoup套件
from bs4 import BeautifulSoup
捞取方式使用下列code

soup = BeautifulSoup(res.text, 'html.parser')
tr_tag = soup.find_all('tr')

第一行就是把我们的原始码使用html.parser的方式支解
第二行则是支解完之後我们把所有tr标签的东东全部找出来
这些步骤操作完後,你的code应该会长这样

import requests
import json
from bs4 import BeautifulSoup
url = 'https://mops.twse.com.tw/mops/web/ajax_t163sb01'
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
}
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=url,data=data,headers=headers)
soup = BeautifulSoup(res.text, 'html.parser')
tr_tag = soup.find_all('tr')

此时我们可以先来print一下看看长怎样 先在最後面加入
print(tr_tag)

可以看到好像有捞东西出来的,但这捞出来的东西实在是有点让人密集恐惧症发作
毕竟这个网页的tr tag也不只一个,所以他会把所有符合tr tag的资料都拿出来
进而造成这种密恐发作输出
不过还好,这个搜寻结果是用list的方式取得的
因此我们可以用遍历的方式将list内元素一个一个print出来
我们把print改成下列程序码

for i in tr_tag:
	print(i)

最後再看一下执行结果

这样就舒服多了
可是tr结果这麽多,怎麽找到我们要的流动资产资料呢
我们再回到我们的原始码看看,发现我们的目标tr tag有个属性叫class="even"
所以我们可以再把搜寻条件加上class要是even才拿出来
增加条件的方式我们会使用python的dict,如下面的code所示
tr_tag = soup.find_all("tr", {"class": "even"})
这样我们就只会捞出是tr tag且class为even的东东了
我们一样把tr_tag改掉後再执行一次

这次的结果就少了许多了
可以发现我们要的流动资产资料在这个搜寻结果的第四个
所以我们就把第3个index的资料捞出(请不要问我要捞第四个index却是3,因为人家计算机是re:0粉)
把print这段改成:
print(tr_tag[3])
输出结果

恭喜你,你成功的用这碗漂亮的汤捞出你人生第一笔资料啦~
不过每次要捞资料都要这样慢慢比对
不仅对不起你浪费的时间,更对不起这个功能强大的BeautifulSoup还有Python
因此下一篇,我们会教你如何把里面的东西一次捞出来,并且怎麽转成JSON方便送给其他人
欲知这个BeautifulSoup还有甚麽隐藏在深处的强大力量
咱们下回分解~


<<:  DAY16 服务室--JSON Server RESTful API简单用

>>:  没收到资讯的第二天...

Composite 合成模式

今天要来介绍一个比较特别、平常可能不太常见的模式。就让我们直接进入问题吧 问题 假设有间百货公司周年...

网页基础介绍及开发环境准备(DAY1)

前言 第一次参加铁人赛,想藉由这次的铁人赛更加熟悉以前学过的网页前端技术和学习新的技术Vue.js,...

Day18 - 轻前端 Vue - 复杂型别 object

先说明一下 我用轻前端 Vue 的目的,不是把整个网站都改用轻前端,而是为了把复杂的 js 取值、给...

误打误撞跳到网路组

前情提要 找到指导教授後发生意外结果我又必须要重新找老师啦 QQ 进入正题 之前的故事有提到,我大学...

CSS overflow

前言 当子元素溢出母元素时该如何处理 可单指设定X轴或Y轴 overflow-x overflow-...