---
# System prepended metadata

title: 2022-12-04 第四天 Python網路爬蟲應用實務班上課記錄
tags: [已轉移]

---

# 2022-12-04 第四天 Python網路爬蟲應用實務班上課記錄
###### tags: `python` `爬蟲`

## HTML基礎
```html=
<!DOCTYPE html>  <!-- 網頁的註解  -->
<html>  <!-- 起始標籤 -->
  <head> <!-- 網頁的設定 -->
    <meta charset="utf-8" /> <!-- meta 標籤, 屬性名稱charset, 屬性值utf-8-->
    <title>我的網站</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes" />
  </head>

  <body>  <!-- 網頁的內容 -->


    <h1>網站的標題</h1> <!-- 標籤可以巢狀, 但不可以交錯 -->

    <h2>文章</h2>

    <h2>相簿</h2>


    <h2>事件</h2>


  </body>
</html> <!-- 結束標籤 -->
```

#### 加上了CSS屬性
```html=
<!DOCTYPE html>  <!-- 網頁的註解  -->
<html>  <!-- 起始標籤 -->
  <head> <!-- 網頁的設定 -->
    <meta charset="utf-8" /> <!-- meta 標籤, 屬性名稱charset, 屬性值utf-8-->
    <title>我的網站</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes" />
    <style>
        * {
            padding: 0;
            margin: 0;
            border: 0;
            box-sizing: border-box;
        }
    </style>
  </head>

  <body style="background-color:aquamarine;">  <!-- 網頁的內容 -->


    <h1>網站的標題</h1> <!-- 標籤可以巢狀, 但不可以交錯 -->
    <header>
        <h3>今日大事</h3>
        <h4>2022年12月14日</h4>
        <h4>Aaron Ho</h4>
    </header>
    <p>今日大事內容今日大事內容今日大事內容今日大事內容今日大事內容今日大事內容今日大事內容今日大事內容今日大事內容</p>

    <header>
        <h3>明日日大事</h3>
        <h4>2022年12月15日</h4>
        <h4>Aaron Ho</h4>
    </header>
    <p>明日大事段落一明日大事段落一明日大事段落一</p>
    <p>明日大事段落二明日大事段落<br/>
        二明日<br/>
        大事段<br/>
        落<br/>
        二</p>

    <h2>文章</h2>
    <a href="https://www.yahoo.com.tw">前往Yahoo</a>

    <h2>相簿</h2>
    <div style="text-align: center;">
    <img width="40%" style="box-sizing: border-box; margin-right: 50px;" src="https://cdn.pixabay.com/photo/2013/07/18/20/26/sea-164989_1280.jpg" />
    <img width="40%" style="box-sizing: border-box;" src="https://cdn.pixabay.com/photo/2016/10/18/21/22/beach-1751455__480.jpg" />
    </div>

    <h2>事件</h2>
    <p style="margin: 5px; font-size: 1.5em; color:darkorange;">事件內容事件內容事件內容事件內容事件內容事件內容</p>


  </body>
</html> <!-- 結束標籤 -->
```

## BeautifulSoup
```python=
from bs4 import BeautifulSoup # 引入靜態網頁解析模組

html_doc = """
<html>
    <head>
    <title>這是HTML文件標題</title>
    </head>

    <body>
        <h1 id="article" class="banner">網頁標題</h1>
        <p data-author='aaron'>文章段落</p>
        <a href="https://www.aaronlife.com/ref1">參考資料連結1</a>
        <a href="https://www.aaronlife.com/ref2">參考資料連結2</a>
        <p>這是一份<b class="boldtext>HTML文件</b>。</p>
        <h2 id="article">網頁標題</h2>
    </body>
</html>
"""

# 建立BeautifulSoup物件並載入html內容
soup = BeautifulSoup(html_doc, 'html.parser')

print(    soup.prettify()    )  # 將網頁內容排版後回傳

print(soup.title)
print(soup.html.body.h1)
print(soup.a)  # 取得第一個a標籤

print(soup.title.string)
print(soup.html.body.h1.string)
print(soup.a.string)  # 取得第一個a標籤內容

tag_p = soup.find_all('p')  # 回傳list
print(tag_p)

for p in tag_p:
    print(p.getText())

# 取得全部a標籤內容
tag_a = soup.find_all('a')
for a in tag_a:
    print('a標籤內容:', a.getText()) # 標籤內容(並去掉內容的其他標籤)
    print('a標籤的href屬性值:', a.get('href'))  # 取得標籤內某個屬性的屬性值

tag_a_and_p = soup.find_all(  ['a', 'p']   )  # 使用list來一次搜尋多種不同的標籤

for t in tag_a_and_p:
    print(t.getText())

tag = soup.find('a')  # 搜尋第一筆a標籤
print('第一筆a標籤:', tag)

tag = soup.find(['a', 'p'])  # 搜尋第一筆標籤
print('第一筆a或p標籤:', tag)

# 取得全部a標籤內容
tag_a = soup.find_all('a', limit=1)  # 限制要取得的標籤數量
for a in tag_a:
    print('限制標籤數量:', a.getText())
```

#### 練習
```python=
# 1. 建立index.html檔案，並貼上早上的html練習的全部網頁內容
# 2. 寫一程式，使用BeautifulSoup4來爬取該網頁內所有照片的網址並顯是在畫面上
# 輸出為:
# https://cdn.pixabay.com/photo/2013/07/18/20/26/sea-164989_1280.jpg
# https://cdn.pixabay.com/photo/2016/10/18/21/22/beach-1751455__480.jpg

with open('index.html', 'r', encoding='utf-8') as web_file:
    html_doc = web_file.read()    #讀取全部檔案內容

from bs4 import BeautifulSoup
    
soup = BeautifulSoup(html_doc, 'html.parser')
image = soup.find_all('img')

for i in image:
    print(i.get('src'))
```

#### 根據某一層來取得指定的標籤
```python=
html_doc = """
<html>
<head>
</head>
<body>
<h1>網頁大標題</h1>
<header>
<h1>文章標題</h1>
<p>文章內容</p>
<h1>第二篇文章標題</h1>
<p>第二篇文章內容</p>
</header>
</body>
</html>
"""

from bs4 import BeautifulSoup

soup = BeautifulSoup(html_doc, 'html.parser')

result = soup.html.body.header.find_all('h1', recursive=False) # 指定只取得header內的h1標籤

print(result)
```

#### 繼續解析
```python=
html_doc = """
<html>
<head>
</head>
<body>
  <h1 id="abc">網頁大標題</h1>
  <div>
    <header>
        <h1 id="abc" title="arc">文章標題</h1>
        <p data-attr="content">文章內容</p>
        <h1>第二篇文章標題</h1>
        <p class="def">第二篇文章內容</p>
        <h1 id="third">第3篇文章標題</h1>
        <p>第3篇文章內容</p>
        <h1>第4篇文章標題</h1>
        <p>第4篇文章內容</p>
    </header>
  </div>
</body>
</html>
"""

from bs4 import BeautifulSoup

soup = BeautifulSoup(html_doc, 'html.parser')

result = soup.html.body.find_all('h1', recursive=False) # 指定只取得header內的h1標籤

print('body內的h1標籤:', result)

# 使用屬性來爬資料
result = soup.find_all(id='abc')
print(result)

result = soup.find_all(id='abc', title='arc')
print(result)

result = soup.find_all(class_='def')
print(result)

result = soup.find_all(attrs={'data-attr': 'content'}) # 以data-attr屬性來搜尋
print(result)

result = soup.find_all(string='網頁大標題') # 使用標籤內容只會回傳該標籤內容，而非完整標籤
print('網頁大標題的id=', result)

# 往內搜尋
print('往內搜尋h1標籤:', soup.header.find_all('h1'))
print('往外搜尋h1標籤:', soup.find('header').find_parents('body'))  # 注意: 往外找標籤，但僅限包住header的標籤


# 往前, 往後
result = soup.find(id='third')
result = result.find_next_sibling('p')  # 往前是呼叫 find_previous_sibling()
print(result)
```

## 實戰練習(爬取台灣銀行匯率)
```python=
from bs4 import BeautifulSoup
import requests  # 下載網頁用的模組
import csv
import time

url = 'https://rate.bot.com.tw/xrt?Lang=zh-TW'  # 匯率網址

# 下載台灣銀行匯率網頁原始碼
response = requests.get(url)

html_doc = response.text

# 寫入本地端確認有下載完整
# with open('rate.html', 'w', encoding='utf-8') as rate:
#     rate.write(html_doc)

soup = BeautifulSoup(html_doc, 'html.parser')
# print(soup.prettify())  # 格式化下載後的網頁


tbody = soup.find('tbody')

all_rates_rows = tbody.find_all('tr')

all_rate_data = []

for row in all_rates_rows:
    # 解析每一列資料
    columns = row.find_all('td')
    
    # 存放匯率資訊
    rate_data = []

    for data in columns:
        # 解析每一個欄位

        # 取得幣別
        if data.attrs['data-table'] == '幣別':
            divs = data.find_all('div')
            rate_data.append(divs[3].string.strip())

        if data.attrs['data-table'] == '本行現金買入' and 'print_width' in data.attrs['class']:
            rate_data.append(data.string.strip())

        if data.attrs['data-table'] == '本行現金賣出' and 'print_width' in data.attrs['class']:
            rate_data.append(data.string.strip())

        if data.attrs['data-table'] == '本行即期買入' and 'print_width' in data.attrs['class']:
            rate_data.append(data.string.strip())

        if data.attrs['data-table'] == '本行即期賣出' and 'print_width' in data.attrs['class']:
            rate_data.append(data.string.strip())

    all_rate_data.append(rate_data)
            

# 全部資料
print(all_rate_data)

# 以目前時間產生檔名
now = time.localtime()
file_name = time.strftime('%Y%m%d_%H%M%S.csv', now)
print('輸出的檔案名稱:', file_name)

with open(file_name, 'w', encoding='utf-8', newline='') as csvfile:
    csvfile.write('\ufeff') # UTF-8 BOM
    writer = csv.writer(csvfile) # 建立CSV寫入器
    writer.writerow(['幣別', '現金買入', '現金賣出', '即期買入', '即期賣出'])
    writer.writerows(all_rate_data)
```