Upgrade to Pro — share decks privately, control downloads, hide ads and more …

不要小看我的情報網_上吧網路爬蟲!!@HackerSir 11th

不要小看我的情報網_上吧網路爬蟲!!@HackerSir 11th

Avatar for YUKAI

YUKAI

May 30, 2025
Tweet

More Decks by YUKAI

Other Decks in Education

Transcript

  1. • 安裝 python 套件:requests、beautifulsoup4 • 指令: • Requests:用來發送網路請求 • Beautifulsoup4:分析

    HTML,並讓 Python 能選取 Element Before Class pip install requests beautifulsoup4
  2. • 每次請求 Server 都回傳相同的 HTML、CSS、JavaScript • 根據 JavaScript 生成網頁 Client-Side

    Render Server side rendering, client side rendering, or static site generation? - IONOS 圖源:IONOS
  3. • 優點 • 伺服器負擔少 • 網頁好維護 • 缺點 • 需要等待

    JavaScript 執行 • 網頁渲染速度取決於使用者裝置性能 Client-Side Render
  4. • Server 先建立好要回傳的 HTML • 會根據 request 每次重新抓取資料,生成 HTML(動態網頁) Server-Side

    Render Server side rendering, client side rendering, or static site generation? - IONOS CA 圖源:IONOS
  5. • 優點 • 直接爬取 HTML 就可以獲得想要的資料 • 不必等到 JavaScript 執行完才看得到畫面

    • 缺點 • 程式邏輯與架構會較複雜 • 載入速度取決伺服器性能 Server-Side Render
  6. • 根據 request 直接將對應的 HTML 傳回使用者,不需要重新生成 HTML • 優點 •

    更快的加載速度與穩定性 • 缺點 • 網頁內容不能有太多變化,動態內容不建議使用 補充:Static Side Generation
  7. • SSR 需要使用爬蟲分析網頁 • CSR 可以呼叫 API 來直接獲取資料 • Hydration:SSR

    + CSR • 為了網頁效能,先請求渲染好的網頁,再呼叫 API 請求資料 小節
  8. 以 逢甲大學的新聞與活動 為例 1. 打開 DevTools 2. 點擊 Network 3.

    點擊第一筆內容,通常會是載入的頁面 如何辨識渲染方式
  9. 4. 在 Response 按下 Ctrl+F 5. 搜尋想要爬蟲的內容 6. 如果找得到就可判斷是 SSR

    以這個畫面而言,找得到內容所以是 SSR 如何辨識渲染方式
  10. 以 巴哈的新聞網 為例 • 可以用 Ctrl + Shift + C

    協助定位 Element • 發現是由 h1 的區塊組成
  11. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. import requests from bs4 import BeautifulSoup url = "https://gnn.gamer.com.tw/" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", } res = requests.get(url, headers=headers) # GET 方法取得網頁 soup = BeautifulSoup(res.text, "html.parser") # 解析網頁 html 發送請求
  12. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. # 找出所有 h1 標籤,且 class 為 GN-lbox2D posts = soup.find_all('h1', class_='GN-lbox2D') # 將資料提取後記錄在 results results = [] for post in posts: results.append({ 'title': post.find('a').text.strip(), # 找出 a 標籤,取得文字內容 'link': post.find('a')['href'] # 找出 a 標籤,取得 href 屬性 }) 找出 Element
  13. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. import json # 將結果寫入 result.json with open('result.json', 'w', encoding='utf-8') as f: json.dump(results, f, ensure_ascii=False, indent=4) 資料匯出
  14. • 從 Headers 可以看出是以 POST 呼叫此 API • 並且 Request

    攜帶的資料格式是 json 呼叫 API 獲取更多資料
  15. • 從 Payload 可以看到 Request 攜帶的資料 呼叫 API 獲取更多資料 lang

    課程語言 sms 上/下學期 year 學年度 classId 班級 degree 學制 deptId 學院 unitId 系所
  16. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. import requests, json # 要呼叫的 API 網址 result_url = "https://coursesearch04.fcu.edu.tw/Service/Search.asmx/GetType1Result" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0 Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", } 直接呼叫 API
  17. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. # 設定要傳送的資料 data = { "baseOptions": { "lang": "cht", "year": 113, "sms": 1 }, "typeOptions": { "degree": "1", "deptId": "CI", "unitId": "CE07", "classId": "CE07131" } } 直接呼叫 API
  18. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. # 呼叫 API res = requests.post(result_url, headers=headers, json=data) # 將結果寫入 result.json with open('result.json', 'w', encoding='utf-8') as f: json.dump(res.json(), f, ensure_ascii=False, indent=4) 直接呼叫 API
  19. • Step1: • 需要先在下載 browser 的 driver,這邊以 chromedriver 為例 •

    Download Link:Chromedriver#stable • 把 driver 放在與程式同一個資料夾 • 備註:下載的 driver 要與 browser 的版本一樣 • Step2: • 安裝 selenium 套件 • 指令: Selenium pip install selenium
  20. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. # 引入 webdriver from selenium import webdriver # 引入 By 語法用來查找 Elemnent from selenium.webdriver.common.by import By # 引入 time 模組,用來暫停程式 import time # 設定帳號密碼和 URL username = "" password = "" url = "https://ilearn.fcu.edu.tw/login/index.php" 帳號密碼輸入、按鈕點擊
  21. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. # 創建 Chrome 瀏覽器實例,並前往網址 driver = webdriver.Chrome() driver.get(url) # 找輸入框和按鈕 username_input = driver.find_element(By.ID, "username") password_input = driver.find_element(By.ID, "password") submit_button = driver.find_element(By.ID, "loginbtn") 帳號密碼輸入、按鈕點擊
  22. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. # 輸入帳號密碼後點擊登入 username_input.send_keys(username) password_input.send_keys(password) submit_button.click() # 等待 10 秒後關閉瀏覽器 time.sleep(10) driver.quit() 帳號密碼輸入、按鈕點擊
  23. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

    11. 12. 13. 14. # 用 JavaScript 實現滾動 js = "document.querySelector('div#page').scrollTop = 100000;" driver.execute_script(js) 畫面滾動
  24. • reCAPTCHA 驗證機制 • 常見解法 • 人工輸入驗證碼 • 模擬人類動作,ex:selenium •

    OCR 辨識驗證碼,ex:pytesseract、ddddocr • 第三方平台驗證碼辨識服務,ex:Anti-captcha • User Session 爬蟲會遇到的其他問題
  25. • Rate Limit / Throttle(頻率限制) • 常見解法 • 設定隨機延遲時間 •

    輪流切換 IP 位址 • 更換 User-Agent 爬蟲會遇到的其他問題