<!-- .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 主線課程"}
    1010 views