<!-- .slide: data-background="https://hackmd.io/_uploads/ryOcSesP2.png" -->
# Package <br>與網路爬蟲
Vincent55 楊竣鴻
Note:
2023-07-22 09:00 - 12:00
---
## \`whoami\`
- ![](https://hackmd.io/_uploads/SJbunf3F2.png =80x80)
- 楊竣鴻 aka Vincent55
- 成大資工大二、自由工作者、CTF
- SITCON Camp
- 2019 學員、2021 隊輔組
- 網路爬蟲
- iKala 實習、[IThome 鐵人賽](https://ithelp.ithome.com.tw/users/20134430/ironman/4307)
- https://vincent55.tw
----
## 這堂課你會學/操作到
- Package
- 虛擬開發環境
- 常用套件 - 基礎網路爬蟲
----
## 複習一下 Module
- 一個獨立的 .py 檔案
- 將函式或變數放在不同檔案,解決重複使用與好維護
Note:
由於 Package 與 Module 有一定程度相關,因此先複習一下 Module
根據 Python 的定義,Module 就是一個獨立的 py 檔案,我們可以透過將不同功能切分在不同的 Module 要使用的時候就 import 進來,解決重複使用與使我們專案更好維護
----
## import
```text
telegram/ 專案頂層目錄
├── __init__.py ├── 初始化
├── commands/ ├── 指令相關模組
│ ├── __init__.py │
│ ├── options.py │
│ ├── context.py │
│ └── core.py │
├── utils.py │
└── __main__.py └── 專案進入點
...
>$ python -m telegram
```
- 在 \_\_main__.py 中
- `import utils`
- `from commands import core`
- `from commands import *`
- 在正式環境為不良習慣
ref: https://hackmd.io/@Sean64/py-module-sitcon2023#/5/1
Note:
這是一個專案的基本架構,我們可以透過 python -m telegram 來運作這個專案,並且會以 `__main__.py` 為進入點
在 `__main__.py` 內,我們可以使用 import 的方式來使用其他 module
複習 import 的幾種方式,也可透過 as 去設定別名
其實這個專案使用到了我們今天的主題 Package,等等會詳細介紹我們要怎麼去定義一個 Package
----
## Python Standard Library
- Python 預設的標準庫,包含許多面向的現成 Module
![](https://hackmd.io/_uploads/rJwZQ2uSh.png)
`/usr/lib/python3.10/`
Note:
為何大家都說 Python 是很方便的語言,主因之一就是許多面向的現成 module
----
## 挑戰 1 - 找原始碼
- 有人能幫我找到 http.server 在 python 標準庫的 code 嗎
- Hint: `/usr/lib/python3.10/`
---
# 什麼是 Package
- 數個 Module 在同資料夾下
- 可以有 subpackage
- \_\_init__.py
- 用像 module 的方式 import
- 一種以點分隔模組名稱組織 Python 模組命名空間
- `from commands.core import Core`
Note:
Module 的定義只是單一的 py 檔案,若專案中有許多 Module,可使用 Package 來組織
package 的關鍵字,資料夾、 \_\_init__.py、Module
一個 Python Package 一定需要一個 \_\_init__.py 才會被 Python 認為是 Package
----
## 為何需要 Package
- 給開發者一個高級別的 Module 組織機制
- Package 間命名空間隔離
- 不用重造輪子
- 可下載/上傳寫好的 Package
- Python 的開發精神
- https://peps.python.org/pep-0020/
Note:
給予開發者一個管理 Module 組織的機制
每個 Package 都是一個 Namespace 用來區分變數、函式、類別的名稱
若有多個 Package,不用擔心兩個 Package 裡面的 Module 有名稱衝突
可以回去看之前提到的例子
可下載別人的套件來快速完成你的需求
----
## Module vs Package (1/2)
- Module
- 能被其他 Module 引用的 python 檔案
- 內容定義了 classes、functions、variables
- Package
- 包含 \_\_init__.py 與數個 Module 的資料夾
- 組織與管理 Module
----
## Module vs Package (2/2)
![](https://hackmd.io/_uploads/Sy4vb4YB3.png)
Note:
這張圖解釋了 Module 跟 Package 之間的關係
---
# 如何使用 Package
- 用剛才提到的方式自己寫
- 用 pip、poetry 等方式到像 pypi 等套件庫下載
- 自己寫好後上傳到 pypi 供大家使用
Note:
講解完什麼是 Package 以及為什麼要用 Package 還有比較 Package 與 Module 的差異後,我們要來看我們如何使用一個 Package,第一種方式就是我們可以使用剛才提到的資料夾與 `__init__.py` 和 Module 的方式撰寫
或者是使用套件管理系統去 pypi 這種套件庫下載別人已經寫好的
----
## pypi ( Python Package Index )
> Python 軟體包索引 (PyPI) 是 Python 程式設計語言的軟體存儲庫 [https://pypi.org/]
- 供開發者能搜尋、下載、貢獻 Python Package
- 為絕大多數的套件管理工具的預設下載來源
- ex. pip、poetry
Note:
pypi 是目前最廣為使用的套件庫,開發者能上傳自己的 Package 上去,或者下載 Package,我們接下來會教到的 pip poetry 預設就是使用 pypi 當作下載來源
----
## pip
- Python 預設的套件管理工具
- `pip install <package-name>` 安裝套件
- `pip uninstall <package-name>` 移除套件
- `pip list` 查看當前安裝的套件
Note:
介紹完套件的儲存庫後,要來介紹如何將套件安裝到本地,我們需要一個套件管理工具
live demo,並注意下載的來源以及依賴套件
現代 Python 發布版自帶的套件管理工具
----
## 挑戰 2 - 安裝套件
- 用 pip 安裝 PythonTurtle
- 用 `pip show PythonTurtle` 測試是否安裝成功
- ![](https://hackmd.io/_uploads/HkcrL2tLn.png)
- Hint: 去 pypi 找要如何安裝
----
## pip problem?
- 套件管理
- pip 會安裝到全域
- 基本上沒有相依性管理
Note:
了解完 pip 如何使用後,要來介紹 pip 存在的一些問題,首先 pip 在預設情況下會將套件安裝到全域,當你今天要開發兩個以上的專案,若要使用的套件版本不同,就會出現問題,無法好好的去做專案開發的環境切分
我們下一張投影片會介紹 pip 的相依性管理的問題
----
## 當你想要安裝一個套件
- `pip install selenium`
```unix
sitconcamp@SITCONCamp2023:~$ pip install selenium
...
Installing collected packages: sortedcontainers, sniffio, PySocks, h11, exceptiongroup, certifi, attrs, async-generator, wsproto, outcome, trio, trio-websocket, selenium
Successfully installed PySocks-1.7.1 async-generator-1.10 attrs-23.1.0 certifi-2023.5.7 exceptiongroup-1.1.1 h11-0.14.0 outcome-1.2.0 selenium-4.9.1 sniffio-1.3.0 sortedcontainers-2.4.0 trio-0.22.0 trio-websocket-0.10.2 wsproto-1.2.0
# 包含原本的 Selenium,共裝了 13 個套件
```
----
## 如果我們要刪除一個套件
```unix
sitconcamp@SITCONCamp2023:~$ pip list | wc -l
88
sitconcamp@SITCONCamp2023:~$ pip uninstall selenium
...
Would remove:
/home/sitconcamp/.local/lib/python3.10/site-packages/selenium-4.9.1.dist-info\/\*
/home/sitconcamp/.local/lib/python3.10/site-packages/selenium\/\*
...
Successfully uninstalled selenium-4.9.1
sitconcamp@SITCONCamp2023:~$ pip list | wc -l
87
```
- 手動將相依套件刪除?
Note:
pip uninstall 只會刪除套件本身,並不會連同相依套件一起刪除
有可能相依套件被其他套件相依,會出問題
----
# 虛擬環境
- 為了解決開發環境 "很髒" 的問題
![](https://hackmd.io/_uploads/ryZV3MsSh.png)
Note:
剛才提到 pip 安裝在全域會發生版本衝突的問題,虛擬環境將開發環境切開可以大大降低這個問題的風險
虛擬環境的原理是他會幫你開一個專屬於你的專案的資料夾,當你安裝套件就會裝到那個資料夾內。
各位在使用的時候只要專注在,一個專案就是一個資料夾,在這個資料夾下寫你的專案,安裝套件
----
## 常見虛擬環境解決方案
- pipenv
- [為什麼不選擇這套](https://github.com/pypa/pipenv/issues/4058)
- poetry
Note:
常見的虛擬環境的解決方案有 pipenv 跟 poetry,在這個營期我們都是使用 poetry,目前的主流也漸漸從 pipenv 轉向 poetry 了
----
## pipenv lock vs poetry lock
![](https://hackmd.io/_uploads/r1Ypkc0B2.png)
- requests selenium beautifulsoup4 PyPDF2 pdf2image openpyxl pyautogui pygame pymysql pymongo PyQt6 tensorflow
Note:
我們來比較 pipenv 跟 poetry 兩者 lock 的速度,lock 是一個解析依賴並鎖定版本的一個動作,等等會詳細介紹
兩者都安裝了 requests selenium beautifulsoup4 PyPDF2 pdf2image openpyxl pyautogui pygame pymysql pymongo PyQt6 tensorflow ,用 time 指令為兩個的 lock 速度進行測速
可以看到 pipenv lock 的速度 poetry 的 8 倍
----
## poetry
- 專案化
- `poetry init`
- 強制虛擬環境
- `poetry env use python`
- pyproject.toml
- https://peps.python.org/pep-0518/
- https://peps.python.org/pep-0621/
- poetry.lock
- 版本鎖
- lock 很快
Note:
使用了與其他套件(npm)類似的專案化管理
套件都安裝在虛擬環境,不會裝在全域汙染環境,使用了 virtualenv
pyproject.toml 是 PEP 518 所提出的新標準, PEP 612 給出了擴充
最重要的一點是 poetry 有針對 lock 優化,因此速度相較 pipenv 快很多
----
## poetry 安裝
- https://python-poetry.org/docs/
1. 使用官方腳本安裝
- `curl -sSL https://install.python-poetry.org | python3 -`
2. 將 ~/.local/bin 放到環境變數
- `echo 'export PATH="~/.local/bin:$PATH"' >> ~/.bashrc`
3. 重啟終端機看是否成功安裝
- `poetry --version`
Note:
這邊列出了 poetry 如何安裝,如果是用教室電腦的我已經先幫各位安裝好了,可以不用再次安裝
如果是使用自己電腦的可以去官網看,如果是 linux 環境可以直接照簡報打
----
## poetry 基本使用 (1/5)
- 初始化專案
- `poetry init`
![](https://hackmd.io/_uploads/rkDM6EoSn.png)
Note:
各位也可以跟著做
前面提到 poetry 需要 pyproject.toml,因此我們需要使用 poetry init 來初始化專案
----
## poetry 基本使用 (2/5)
- 創建虛擬環境
- `poetry env use python3`
- ![](https://hackmd.io/_uploads/SJT2yHoS3.png)
- `poetry add` or `poetry install`
Note:
可使用 env use 來指定創建的虛擬環境使用的 python 版本
在使用 poetry add 或 install 時,若當前目錄下有使用虛擬環境則會建立一個,否則會安裝到該虛擬環境
----
## poetry 基本使用 (3/5)
- 開啟虛擬環境的 shell
- `poetry shell`
- ![](https://hackmd.io/_uploads/SkZogSsS3.png)
- 退出虛擬環境的 shell
- 在 shell 內按 Ctrl+D
- ![](https://hackmd.io/_uploads/BkZ-ZSsHh.png)
Note:
各位這幾天都頻繁的使用 shell,那我們現在要使用 poetry shell 這個指令來進入剛才準備的虛擬環境的 shell
----
## 錯誤訊息
:::danger
Poetry could not find a pyproject.toml file in /home/sitconcamp or its parents
:::
![](https://hackmd.io/_uploads/rkhv-BjHn.png)
----
## poetry 基本使用 (4/5)
- 新增套件
- `poetry add beautifulsoup4`
- ![](https://hackmd.io/_uploads/SyqSPSoS2.png)
- 安裝虛擬環境依賴(補充)
- `poetry install`
- 自動安裝 poetry.lock 的內容
- 用在想部屬在新環境的時候
Note:
可以使用 poetry add 安裝新的套件,發現目錄下多了個 poetry.lock 的文件,該文件為版本鎖,有興趣可以打開看看
補充一個 poetry install 用在今天要在新的電腦繼續開發專案的時候,下 poetry install 可以將 poetry.lock 的內容自動安裝,甚至不用 poetry init
例如如果你的組員寫完了部分的專案內容,要由你繼續完成剩下的專案,他給你了專案的檔案,你只要下一行 `poetry install` 你就可以有跟他一樣的虛擬環境與套件了
分享一個案例,這次在開發各位這幾天使用的 Telegram bot 的時候,由於裡面使用的某個套件的最新版本在某些情況下會出問題,但執行了 poetry install 後卻發現運作正常,往下看了才知道原來是因為 poetry.lock 將該套件版本鎖定在之前的版本
----
## poetry 基本使用 (5/5)
- 試看看 `from bs4 import BeautifulSoup`
- ![](https://hackmd.io/_uploads/SyD-THirh.png)
:::warning
- 如果翻車
- ![](https://hackmd.io/_uploads/SyqRpHsH2.png)
- 可能原因
- 沒有成功安裝 BeautifulSoup
- `poetry add beautifulsoup4`
- 沒有進入虛擬環境 shell
- `poetry shell`
:::
Note:
安裝好後,我們可以進去虛擬環境的 shell 來並使用剛才安裝的套件
----
## pip poetry 哪時候要用哪個
- 常用且確保不會刪除的套件: pip
- 開發專案: poetry
Note:
我們介紹了 pip 與 poetry,那我們什麼時候要用什麼呢,由於 pip 預設會安裝到全域,若你平常是使用 python 當作日常腳本,就可以將常用的套件安裝到全域
若你今天要開發專案,那就可以使用 poetry 切分開發環境
----
## 在 Vscode 使用 poetry 虛擬環境 (1/4)
- 在專案根目錄打入 `code .` 即可在當前目錄開啟 Vscode
- 在終端機打入 `poetry env info` 查看虛擬環境路徑,並將其複製
- ![](https://hackmd.io/_uploads/rJBfMYoS3.png)
Note:
在這個營期間各位都是使用 VScode 做開發,那現在要跟各位介紹的是如何讓 VScode 使用虛擬環境
----
## 在 Vscode 使用 poetry 虛擬環境 (2/4)
![](https://hackmd.io/_uploads/HyHkWFsHn.png)
----
## 在 Vscode 使用 poetry 虛擬環境 (3/4)
![](https://hackmd.io/_uploads/Hy8jGKjHh.png)
----
## 在 Vscode 使用 poetry 虛擬環境 (4/4)
![](https://hackmd.io/_uploads/H1kF7FsSh.png)
Note:
確認學員環境都能正常使用了,就可以先下課休息
---
# 網頁基本原理與複習
- HTML、JavaScript、CSS
----
## 網頁前端三要素
- HTML - 骨骼
- CSS - 皮膚
- JavaScript - 大腦
Note:
將網頁比做人體,HTML CSS JavaScript 分別對應了骨骼 皮膚 大腦
HTML 提供了我們網頁的基本架構,比如我們需要一段文字跟一個按鈕
有了基本架構後,CSS 可以美化這個頁面,讓文字的自行修改,與按鈕的大小
以上都只是網頁外表的部分,我們需要 JavaScript 來提供邏輯,建立出可以與使用者互動的介面。
----
## HTML(1/2)
- 超文本標記語言
- DOM (Document Object Model)
![](https://hackmd.io/_uploads/Hk7Uwutth.png)
Note:
HTML 是一個標記語言,可以看到途中的下方, html head title 各是一個 tag,由一個角括號與文字表示
瀏覽器透過 http requests 取得 HTML 後,會將其轉換為 DOM,並渲染到畫面上,DOM 是一個樹狀的架構,每個標籤都是一個節點,可以用來表示我們的 HTML
可以看到我們最上層的標籤是 html,接下來有 head 跟 body,head 代表了我們網頁的基本資訊, body 代表了網頁的內容。
可以看到有些標籤裡面有一些屬性 class id 等,能讓 CSS 跟 JavaScript 鎖定到元素
----
## HTML(2/2)
- DOM (Document Object Model)
- 節點之間的關係
![](https://hackmd.io/_uploads/SkwDnjjBh.png)
Note:
我們有了 DOM 後,猶豫他是一個樹狀結構,因此我們能簡單的在節點與節點之間移動
----
## CSS
- CSS 通常會寫在 HTML 的 head 或者獨立出來一個 CSS file
- CSS Selector
- CSS 用來鎖定元素的 [規範](https://developer.mozilla.org/zh-TW/docs/Web/CSS/CSS_Selectors)
```HTML=
<head>
<link rel="stylesheet" type="text/css" href="mycss.css">
<style>
body{
background:#fff;
color:#777;
}
h1 {
font-weight:bold;
font-style:italic;
font-family:sans-serif;
color:green;
}
a {
color: #0077cc;
text-decoration: none;
}
.container {
border: 2px solid #ccc;
padding: 20px;
border-radius: 10px;
}
</style>
</head>
```
Note:
CSS 可以用來美化我們的介面,CSS 通常會寫在 HTML 的 head 用 style 標籤包起來,或者獨立一個 css file 再透過引入的方式使用。
在爬蟲這堂課裡面,CSS 只需要了解 CSS 選擇器,在 CSS 裡面是透過 CSS 選擇器來鎖定元素的去替換屬性,那這個特性我們可以來利用在爬蟲的時候定位元素。
----
## JavaScript
- 語言特性
- 單執行緒
- [非同步](http://latentflip.com/loupe/)
- [動態弱型別](https://openhome.cc/zh-tw/javascript/basics/wat/)
Note:
單執行緒: 一次只做一件事,一次只占用一個執行緒
非同步: 在執行非同步函式的時候不會等待回傳值占用執行緒,透過事件迴圈 (Event loop)實現
動態語言: 變數的型態不在定義階段時決定
弱型別: 變數在與不同型態的變數互動時,可以被隱式轉換為另一個類型
----
## 挑戰 3 - 開發人員工具練習
https://jupiter.challenges.picoctf.org/problem/9670/
- 找到完整的 flag
- picoCTF{...}
- 共有三個部分
Hint: 使用開發人員工具,檢查 HTML CSS JavaScript
Note:
demo chrome://dine
---
# 爬蟲常用套件
----
## 爬蟲是什麼
- 一種依照特定規則抓取網路資訊的程式
- 股票爬蟲
- PTT 爬蟲
- 搜尋引擎
Note:
剛才我們操作的都是透過瀏覽器向伺服器發送 HTTP 請求,但其實不只瀏覽器可以做到,可以透過程式來向伺服器發送 HTTP 請求
網路爬蟲就只是一種透過特定的規則去抓取網路資訊一個程式
https://www.cloudflare.com/robots.txt
----
## 爬蟲是怎麼運作的
- 取得網路資訊
- 網頁原始碼、API
- 解析資訊
- 解析工具們
- 開發人員工具、眼睛...
- 資料清洗工具們
- BeautifulSoup、regex...
- 後續使用
- 存起來
- 傳給自己
- Telegram、Line...
Note:
網路爬蟲是怎麼從零到有產生的
----
## Requests (1/4)
> Requests is a simple, yet elegant, HTTP library.
- 用 Python 向網站發 HTTP 請求
- <img src="https://warehouse-camo.ingress.cmh1.psfhosted.org/98d69ff5a75b6a9a8cbb54b7ce9c126f9d857f79/68747470733a2f2f706570792e746563682f62616467652f72657175657374732f6d6f6e7468" alt="Downloads">
Note:
request 是一個 Python 的函式庫,讓我們可以透過簡單的語法向伺服器發出 HTTP 請求
----
## Requests (2/4)
- 安裝
- `pip install requests`
- `poetry add requests`
```python=
import requests
#先將欲發出 GET 請求的網址先存在 url
url = 'https://example.com/'
#對 url 發出 GET 請求,並將 Response 物件存在 res
res = requests.get(url)
print(type(res), res)
#Output: <class 'requests.models.Response'> <Response [200]>
```
Note:
requests 在 Python3.7 以上都被併入預設庫了,所以各位環境上不用自行安裝
這邊是一個範例
----
## Requests (3/4)
- Response 物件的使用方式
- res.status_code : 該 HTTP 狀態碼
- res.text : 回應物件的字串(str)型態
- res.json() : 將回應物件透過 JSON decoder 回傳 JSON 格式。
- ...
- [官方文件](https://requests.readthedocs.io/en/latest/user/quickstart/#response-content)
Note:
取得 Response 物件後,我們可以有許多使用的方法,可以使用 status_code 取得 HTTP response code,或者使用 text 取得字串型態的回傳,我們接下來會很常使用這個,以及 .json() 可以幫助我們解析回傳值為 json 格式
----
## Requests (4/4)
```python=
import requests
#先將欲發出 GET 請求的網址先存在 url
url = 'https://example.com/'
#對 url 發出 GET 請求,並將 Response 物件存在 res
res = requests.get(url)
print(res.text)
'''
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
background-color: #fdfdff;
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
'''
```
----
## 練習 - 取得官網原始碼
`https://sitcon.camp/2023/`
----
## 挑戰 4 - 取得官網所有連結
`https://sitcon.camp/2023/`
- Hint
- 觀察連結都會出現在怎樣的格式,並使用正規表達式把連結找出來
- `re.findall(pattern, text)`
- https://regex101.com
Note:
舉個例子取得括號內的文字
1*(3+2*5)
----
## API
http://dev.vincent55.tw
Note:
快速複習一下 API
把網站比做一個餐廳,前端就像一個外場,就是現在各位看的的頁面,而後端就是一個餐廳的後台,用來處理外場的需求,API 就是一個菜單,供客人知道該怎麼取得對應資料或服務,之間傳遞資料的格式現今最常見的就是 JSON
這個網站提供了很多 API 讓我們使用,打開網站後可以看到一個 API 文件,並測試 JSON。
----
## JSON
- Python 標準庫裡面有 json 工具
- `import json`
- https://docs.python.org/zh-tw/3/library/json.html
- Requests 裡面也有內建
- `response.json()`
Note:
JSON 被廣泛利用在資料交換,與設定檔格式,像是 minecraft 就是使用 JSON 作為設定檔格式,講條亮度的案例,甚至有些人會選擇將他當作資料庫來使用,因此很多語言都有內建 JSON 的函式庫
我們在 Python 裡面可以透過 import 的方式來引入 json,以及剛才提到的 Requests 的 Response 物件也有內建 JSON 解析器
----
## JSON 檔案操作
- 檔案名稱
- `xxx.json`
- JSON 儲存到 `.json` 檔案
```
with open('result.json', 'w', encoding='utf-8') as f:
json.dump(res, f, indent=2, sort_keys=True, ensure_ascii=False)
```
- 從 `.json` 檔案取得 JSON
```
with open('result.json', 'r') as f:
result_file = json.load(f)
print(result_file)
```
Note:
我們可以透過存檔讀檔的方式將 json 作為一種資料庫來儲存資料。
----
## 小練習
```python=
import requests
import json
#先將欲發出 GET 請求的網址先存在 url
url = 'https://httpbin.org/json'
#對 url 發出 GET 請求,並將 Response 物件透過 json 解析後存在 res
res = requests.get(url).json()
print(type(res), res)
print(res['slideshow']['slides'][1]['title'])
# 將回傳值存於 result.json
with open('result.json', 'w', encoding='utf-8') as f:
json.dump(res, f, indent=2, sort_keys=True, ensure_ascii=False)
'''
<class 'dict'> {'slideshow': {'author': 'Yours Truly', 'date': 'date of publication', 'slides': [{'title': 'Wake up to WonderWidgets!', 'type': 'all'}, {'items': ['Why <em>WonderWidgets</em> are great', 'Who <em>buys</em> WonderWidgets'], 'title': 'Overview', 'type': 'all'}], 'title': 'Sample Slide Show'}}
Overview
'''
```
----
## 挑戰 5 - 取得貓貓圖片
https://api.thecatapi.com/v1/images/search
- 可以輸入一個數字,取得該數量的貓貓圖片,並儲存到 `result.json` 裡面
- 進階挑戰
- 如果有重複執行該程式,`result.json` 不會被覆蓋
- Hint: 可以善用讀檔與寫檔
Note:
讓學員做之前,先 demo 成品
----
## BeautifulSoup (1/4)
- 從 HTML 或 XML 檔案中解析資料
- 也可拿來修復未閉合標籤等錯誤的文件
Note:
若沒有 API 可供使用, 我們就需要自行去解析原始碼內容,BeautifulSoup 是一套可以解析 HTML 的工具,提供了很多好用的選取器取得想要的資料。
我們可以透過 requests 的 Response 物件的 text 取得字串型態的回傳值,再來我們可以透過 BeautifulSoup 去解析內容。
----
## BeautifulSoup (2/4)
- 安裝
- `poetry add beautifulsoup4`
```python=
from bs4 import BeautifulSoup
html_text = """
<html><head></head><body><h1>Hello, World!</h1></body></html>
"""
soup = BeautifulSoup(html_text, "html.parser")
print(soup.prettify())
```
```text
<html>
<head>
</head>
<body>
<h1>
Hello, World!
</h1>
</body>
</html>
```
Note:
html_text 是一個 HTML 字串的範例,透過 BeautifulSoup 解析,之後使用 prettify 查看解析的狀態。
----
## Beautifulsoup (3/4)
- soup.find() : 根據條件回傳"第一個"符合的元素
- `soup.find('p', id='myid', class_='myclass')`
- soup.find_all() : 根據條件回傳"所有"符合的元素,由串列表示。
- soup.select_one() : 透過 CSS Selector "第一個"符合的元素
- soup.select() : 透過 CSS Selector "所有"符合的元素,由串列表示。
Note:
BeautifulSoup 提供了一些選取器
----
## Beautifulsoup (4/4)
```python=
from bs4 import BeautifulSoup
import requests
# 將 resp.text 也就是原始碼字串資料放到 BeautifulSoup 第一個參數內,並用 html.parser 當作第二個參數解析 HTML 內容
soup = BeautifulSoup(requests.get(url).text, "html.parser")
# 網頁的 title
print(soup.title.getText())
# 第一個尋找到的 p 標籤的文字
print(soup.find('p').getText())
# 第一個尋找到 class 為 magic 的標籤
print(soup.find(class_="magic"))
# a 標籤的 href 屬性
print(soup.find('a')['href'])
# 全部 class 為 article 的標籤的文字
articles = soup.find_all(class_="article")
for article in articles:
print(article.getText())
```
Note:
demo 取得官網圖片的過程
要 demo CSS selector 的方法
----
## 案例 - ptt 棒球版爬蟲 (1/3)
https://www.ptt.cc/bbs/Baseball/index.html
- class="r-ent"
![](https://hackmd.io/_uploads/Byjn9KnH2.png)
Note:
觀察一下頁面可以發現各個文章有個共通點就是都有 r-ent 這個 class ,因此我們能透過 find_all 的方式取得所有文章
----
## 案例 - ptt 棒球版爬蟲 (2/3)
```python=
from bs4 import BeautifulSoup
import requests
url = "https://www.ptt.cc/bbs/Baseball/index.html"
r = requests.get(url)
soup = BeautifulSoup(r.text, "html.parser")
for article in soup.find_all(class_="r-ent"):
print(article)
```
Note:
取得所有文章後,檢查我們需要元素的 class
----
## 案例 - ptt 棒球版爬蟲 (3/3)
```python=
from bs4 import BeautifulSoup
import requests
import json
url = "https://www.ptt.cc/bbs/Baseball/index.html"
r = requests.get(url)
soup = BeautifulSoup(r.text, "html.parser")
results = []
for article in soup.find_all(class_="r-ent"):
results.append({
"title":article.find(class_="title").text.strip(),
"author": article.find(class_="author").text.strip(),
"link": article.find(class_="title").a['href']
})
# 將回傳值存於 result.json
with open('result.json', 'w', encoding='utf-8') as f:
json.dump(results, f, indent=2, sort_keys=True, ensure_ascii=False)
```
----
## 挑戰 6 - ptt 棒球版爬蟲(自動換頁)
https://www.ptt.cc/bbs/Baseball/index.html
Hint: 可將目前的爬蟲寫成一個 function,每次爬取到上一頁連結後就呼叫自己
Note:
觀察時間,如果時間快不夠,就 demo 到把 function 做出來
---
## 補充
----
### 更多爬蟲技巧
- 模擬瀏覽器(Selenium...)
- 異步爬蟲
- 分析經驗
----
### 反爬蟲
- headers
- cookies
- proxy
----
### 黑客松上的建議
- 在開始動手前,先分析網站,搞不好能發現隱藏 API
- 不到最後關頭不使用模擬瀏覽器(Selenium)
----
### 感謝各位
https://vincent55.tw/contacts
![](https://hackmd.io/_uploads/HkUiDDf92.png)
----
### Sponsor
![](https://hackmd.io/_uploads/BkJ-CHAq3.png)
----
### 如果一個 Package 沒有 \_\_init__.py
- Namespace package
- https://python3-cookbook-personal.readthedocs.io/zh_CN/latest/c10/p05_separate_directories_import_by_namespace.html
----
## more pip
- Wheel ( .whl )
- ![](https://hackmd.io/_uploads/r1NEtZqHh.png)
- 安裝包
- 本質上是一個 zip 檔
- 一種預編譯發行版的格式
- ready-to-install format
- `pip install <wheel file>.whl`
Note:
更小、安裝更快
解釋為何需要 compile
分享案例,在一家診所,需要自動讀取健保卡資料填入 X 光機控制軟體,作業系統是 windows XP,Python3 最高支援版本為 python3.4.4,沒有辦法連到外網,無法使用 pip 來下載 pypi 的 package,因此只好用 USD 將 wheel file 放到機器上用 pip install 下載
----
## pypi package structure
- 當你想要上傳自己的套件到 pypi
```text
packaging_tutorial/
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│ └── example_package_YOUR_USERNAME_HERE/
│ ├── __init__.py
│ └── example.py
└── tests/
```
----
## pipenv
- pip + virtualenv
- Pipfile
- Pipfile.lock
----
## JavaScript 補充
- JavaScript 能拿來寫後端?
- Node.js ? JavaScript ?
- 為什麼要把 JavaScript 移植到後端?
> Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
V8 engine: https://chromium.googlesource.com/v8/v8
Note:
以 V8 為核心,加上一系列 C/C++ 的套件,成功的讓 Server 端也可以執行 JavaScript
JavaScript 自帶非同步,且語言特性適合用來接收高併發的需求
----
## dir(object)
- 回傳該物件的有效屬性列表
![](https://hackmd.io/_uploads/SJC65Y0Sn.png)
Note:
在進到虛擬環境前補充一個東西
有時候在沒有文件可以看得時候,可以透過這個函式來通靈可以用的東西
----
## pipenv bad?
![](https://hackmd.io/_uploads/SyutirqSh.png)
- https://github.com/pypa/pipenv/issues/4058
Note:
大部分的問題是 Lock 太慢且每次裝新套件都需重新 Lock、Windows 支持不好和 bug 太多
但被 Python Packaging Authority(pypa) 接手後這些問題都漸漸被改善,但還是看不太到人說 pipenv 又回歸了
與此同時,有個更被人們接受的解決方案 poetry
j
{"metaMigratedAt":"2023-06-17T09:30:21.115Z","metaMigratedFrom":"YAML","breaks":true,"description":"Vincent 楊竣鴻 / 想要有效地利用 Python 套件 / Package / poetry / crawling / crawler / Requests / BeautifulSoup4 / BeautifulSoup / 2023-07-22 09:00","slideOptions":"{\"backgroundTransition\":\"none\",\"parallaxBackgroundSize\":\"cover\",\"parallaxBackgroundHorizontal\":0,\"parallaxBackgroundVertical\":0,\"parallaxBackgroundImage\":\"https://hackmd.io/_uploads/SkaithcP2.png\"}","title":"Python Package 與網路爬蟲 - SITCON Camp 2023 主線課程","contributors":"[{\"id\":\"1e882b7f-b741-4bc1-9480-d5e91f0d2819\",\"add\":30599,\"del\":9042}]"}