Vincent550102
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- type: slide tags: presentation title: Python Package 與網路爬蟲 - SITCON Camp 2023 主線課程 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 --- <!-- .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

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully