R Academy · บทเรียน

การจัดการการแบ่งหน้าและหลายหน้า

วนดูผลลัพธ์ที่แบ่งหน้าและรวมข้อมูลที่ขูดมาเป็นชุดข้อมูลเดียว

บทเรียน 4 จาก 413 ขั้นตอน

การจัดการการแบ่งหน้าและหลายหน้า เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน R Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

ทำความเข้าใจการแบ่งหน้า

เว็บไซต์จำนวนมากแบ่งเนื้อหาออกเป็นหลายหน้า การแบ่งหน้าโดยใช้ URL จะเติมหมายเลขหน้าใน URL เช่น ?page=2 หรือ /page/2/ ให้ระบุรูปแบบดังกล่าวเพื่อสร้าง URL ด้วยโปรแกรม

library(rvest)

# Common URL pagination patterns:
# Pattern 1: query parameter
# https://site.com/products?page=1
# https://site.com/products?page=2

# Pattern 2: path segment
# https://site.com/products/page/1/
# https://site.com/products/page/2/

# Build URLs for pages 1 to 5
base_url <- 'https://books.toscrape.com/catalogue/page-'
page_urls <- paste0(base_url, 1:5, '.html')
page_urls
# [1] 'https://books.toscrape.com/catalogue/page-1.html'
# [2] 'https://books.toscrape.com/catalogue/page-2.html' ...

สร้างรูปแบบ URL ด้วย sprintf

sprintf() และ paste0() ต่างก็ใช้สร้างสตริง URL ได้ แต่ sprintf() ควบคุมการเติมศูนย์ด้านหน้าและการจัดรูปแบบได้มากกว่า ให้เลือกใช้ตามโครงสร้าง URL ของเว็บไซต์

# Various URL building approaches

# paste0 for simple concatenation
pages <- 1:5
urls_v1 <- paste0('https://site.com/list?p=', pages)
urls_v1[1]  # 'https://site.com/list?p=1'

# sprintf for formatted strings
urls_v2 <- sprintf('https://site.com/page/%02d/', pages)
urls_v2[1]  # 'https://site.com/page/01/'

# With multiple parameters
urls_v3 <- sprintf('https://site.com/items?page=%d&size=20', pages)
urls_v3[3]  # 'https://site.com/items?page=3&size=20'

# glue package alternative
# glue('https://site.com/page/{pages}')

ดึงข้อมูลหลายหน้าด้วย map()

purrr::map() ใช้ฟังก์ชันดึงข้อมูลกับเวกเตอร์ URL และส่งคืนรายการผลลัพธ์ เมื่อนำมาใช้ร่วมกับ dplyr::bind_rows() จะสามารถรวมผลลัพธ์เป็นกรอบข้อมูลเดียวได้

library(rvest)
library(purrr)

# Define a function to scrape one page
scrape_page <- function(url) {
  # In real code: page <- read_html(url)
  # Here we simulate with local HTML
  page <- read_html(sprintf(
    '<ul><li class="item">Item %d-A</li><li class="item">Item %d-B</li></ul>',
    url, url
  ))
  data.frame(
    title = html_text2(html_elements(page, '.item')),
    page  = url
  )
}

# Apply over pages 1 and 2 (simulated with numbers)
results <- map(1:2, scrape_page)
do.call(rbind, results)

การดึงข้อมูลอย่างสุภาพ: Sys.sleep()

การส่งคำขอไปยังเซิร์ฟเวอร์อย่างรวดเร็วต่อเนื่องถือว่าไม่เหมาะสม และอาจทำให้ถูกจำกัดอัตราการเข้าถึงหรือถูกแบน IP ให้เพิ่ม Sys.sleep() ระหว่างคำขอเพื่อเคารพการทำงานของเซิร์ฟเวอร์ โดยทั่วไปการหน่วงเวลา 1–2 วินาทีก็เพียงพอ

library(rvest)

# Polite scraping with delays between requests
scrape_with_delay <- function(urls, delay = 1.5) {
  results <- vector('list', length(urls))
  for (i in seq_along(urls)) {
    cat(sprintf('Scraping page %d of %d\n', i, length(urls)))
    # results[[i]] <- read_html(urls[[i]])
    Sys.sleep(delay)  # Wait before next request
  }
  results
}

# Also: randomize delay to appear more human-like
random_delay <- function(min = 1, max = 3) {
  Sys.sleep(runif(1, min = min, max = max))
}
random_delay()
cat('Always be polite to servers you scrape')

การตั้งค่า User Agent

ระบุโปรแกรมดึงข้อมูลของคุณอย่างสุภาพด้วยการตั้งส่วนหัว User-Agent ที่บอกรายละเอียด เซิร์ฟเวอร์ใช้ข้อมูลนี้เพื่อระบุบอต User-Agent ที่ดีควรมีชื่อและข้อมูลติดต่อของคุณ เพื่อให้เจ้าของเว็บไซต์ติดต่อได้

library(rvest)

# Default user agent reveals R/rvest
# Better: set a descriptive, honest UA
ua <- paste0(
  'MyResearchBot/1.0 ',
  '(Academic research; ',
  'contact: researcher@university.edu)'
)

# With httr/httr2 for UA control:
# library(httr2)
# response <- request(url) |>
#   req_headers('User-Agent' = ua) |>
#   req_perform()
# html <- read_html(resp_body_string(response))

# Or use polite package for full compliance:
# library(polite)
# session <- bow('https://example.com', user_agent = ua)
cat('Honest UA: better for everyone')

การเคารพ robots.txt

robots.txt ระบุเส้นทางที่โปรแกรมรวบรวมข้อมูลไม่ได้รับอนุญาตให้เข้าถึง แพ็กเกจ robotstxt ช่วยตรวจสอบด้วยโปรแกรมได้ว่า URL นั้นอนุญาตให้ดึงข้อมูลหรือไม่ก่อนเริ่มดำเนินการ

library(rvest)
# library(robotstxt)  # uncomment to use

# Check if scraping is allowed:
# rtxt <- robotstxt(domain = 'books.toscrape.com')
# rtxt$check(paths = '/catalogue/', bot = '*')
# TRUE means allowed

# Robots.txt typically looks like:
# User-agent: *
# Disallow: /admin/
# Disallow: /private/
# Allow: /catalogue/
# Crawl-delay: 2

# The polite package combines UA + robots.txt + delays:
# library(polite)
# session <- bow('https://books.toscrape.com')
# page <- scrape(session)
cat('Always check robots.txt before large-scale scraping')

ติดตามลิงก์แบ่งหน้า

แทนที่จะคาดเดา URL ให้ติดตามลิงก์ 'ถัดไป' ที่มีอยู่จริงในแต่ละหน้า html_attr(html_element(page, 'a.next'), 'href') จะค้นหาลิงก์ไปยังหน้าถัดไปแบบพลวัต และรองรับรูปแบบการแบ่งหน้าที่ไม่ได้เรียงต่อเนื่อง

library(rvest)

# Pattern: follow 'next' links dynamically
scrape_all_pages <- function(start_url, max_pages = 10) {
  all_data <- list()
  url <- start_url
  i <- 1
  while (!is.null(url) && i <= max_pages) {
    # page <- read_html(url)
    # data <- extract_data(page)
    # all_data[[i]] <- data
    # next_link <- html_attr(html_element(page, 'li.next a'), 'href')
    # url <- if (!is.na(next_link)) xml2::url_absolute(next_link, url)
    #        else NULL
    cat(sprintf('Would scrape page %d: %s\n', i, url))
    url <- NULL  # Stop in this demo
    i <- i + 1
  }
  do.call(rbind, all_data)
}
scrape_all_pages('https://books.toscrape.com')

session_follow_link() กับ rvest

session() ของ rvest สร้างเซสชันการเรียกดูที่เก็บรักษาสถานะ โดยคงคุกกี้และประวัติการเข้าชมไว้ session_follow_link() ใช้นำทางไปยังลิงก์ เหมาะสำหรับเว็บไซต์ที่ต้องเข้าสู่ระบบหรือจำเป็นต้องรักษาสถานะระหว่างหน้า

library(rvest)
# Stateful session with rvest
# s <- session('https://example.com/login')
# s <- session_submit(s,
#   html_form(read_html(s))[[1]],
#   list(username='me', password='pw')
# )
# After login, navigate:
# page2 <- session_follow_link(s, 'Products')
# page3 <- session_back(page2)   # go back
# session_history(page2)         # show history

# For simple cases, follow href directly:
# href <- html_attr(html_element(page, 'a.next'), 'href')
# next_page <- session_jump_to(s, href)
cat('session() maintains cookies across requests')

ตรวจหาหน้าสุดท้าย

ควรทราบว่าจะหยุดเมื่อใด: ตรวจสอบว่าปุ่ม 'ถัดไป' มีอยู่หรือไม่ ตรวจสอบว่าจำนวนรายการในหน้าปัจจุบันน้อยกว่าที่คาดไว้หรือไม่ หรือดูว่าหมายเลขหน้าเกินจำนวนหน้าทั้งหมดที่ทราบหรือไม่ จัดการกรณีพิเศษต่าง ๆ อย่างเหมาะสม

library(rvest)
# Strategy 1: Check if 'Next' link exists
has_next <- function(page) {
  next_link <- html_element(page, 'li.next a')
  !is.na(html_attr(next_link, 'href'))
}

# Strategy 2: Compare item count to expected page size
page_size <- 20
check_done <- function(items_on_page) {
  items_on_page < page_size
}

# Strategy 3: Read total from pagination text
# e.g., 'Page 1 of 50' -> extract 50
extract_total_pages <- function(page) {
  text <- html_text2(html_element(page, '.current'))
  as.integer(gsub('.*of (\\d+).*', '\\1', text))
}
cat('Always plan your stopping condition')

การจัดการข้อผิดพลาดในการดึงข้อมูล

ข้อผิดพลาดของเครือข่าย การหมดเวลา และข้อผิดพลาด 404 ล้วนเกิดขึ้นได้ ให้ครอบคำขอด้วย tryCatch() เพื่อจัดการความล้มเหลวอย่างเหมาะสม และบันทึกว่าหน้าใดล้มเหลว เพื่อให้ลองใหม่ภายหลังได้

library(rvest)

safe_scrape <- function(url) {
  tryCatch({
    # page <- read_html(url)
    # data <- extract_data(page)
    # return(data)
    cat(sprintf('Scraping: %s\n', url))
    data.frame(url = url, status = 'ok')
  }, error = function(e) {
    cat(sprintf('FAILED: %s -> %s\n', url, e$message))
    data.frame(url = url, status = 'error')
  })
}

urls <- c('https://example.com/page/1',
          'https://example.com/page/2')
results <- lapply(urls, safe_scrape)
do.call(rbind, results)

การแคชหน้าเว็บที่ดึงมา

บันทึก HTML ที่ดาวน์โหลดไว้ในดิสก์ก่อนแยกวิเคราะห์ วิธีนี้ช่วยให้ไม่ต้องดาวน์โหลดใหม่หากการแยกวิเคราะห์ล้มเหลว การอ่านซ้ำจะมาจากดิสก์ ไม่ใช่เครือข่าย จึงสุภาพต่อเซิร์ฟเวอร์และรวดเร็วระหว่างการพัฒนา

library(rvest)

scrape_cached <- function(url, cache_dir = 'cache') {
  dir.create(cache_dir, showWarnings = FALSE)
  # Create a filename from URL hash
  fname <- file.path(cache_dir,
    paste0(digest::digest(url), '.html'))
  if (file.exists(fname)) {
    cat('Loading from cache\n')
    return(read_html(fname))
  }
  cat('Downloading...\n')
  # page <- read_html(url)
  # xml2::write_html(page, fname)
  # return(page)
  cat('Cached to:', fname, '\n')
}

# Without digest: use URLencode or gsub
url <- 'https://example.com/page/1'
fname <- gsub('[^a-z0-9]', '_', tolower(url))
cat(fname)

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจเกี่ยวกับการดึงข้อมูลหลายหน้าอย่างสุภาพและมีความทนทาน

ทบทวน: การแบ่งหน้าและการดึงข้อมูลอย่างสุภาพ

ประเด็นสำคัญ: สร้าง URL ของหน้าด้วย paste0() หรือ sprintf() ใช้ purrr::map() เพื่อดำเนินการดึงข้อมูลกับ URL จำนวนมาก เพิ่ม Sys.sleep() ระหว่างคำขอเสมอ ตรวจสอบ robots.txt ด้วยแพ็กเกจ robotstxt ติดตามลิงก์ 'ถัดไป' แบบพลวัตด้วย html_attr() หรือ session_follow_link() ตรวจหาหน้าสุดท้ายโดยตรวจสอบว่าลิงก์ถัดไปหายไปหรือไม่ ครอบคำขอด้วย tryCatch() เพื่อรองรับข้อผิดพลาด และแคช HTML ลงดิสก์ระหว่างการพัฒนา

# Multi-page scraping template:
# urls <- paste0(base, 1:n_pages)
# results <- purrr::map(urls, function(url) {
#   Sys.sleep(runif(1, 1, 2))  # polite delay
#   page <- read_html(url)
#   extract_data(page)          # your parser
# })
# df <- dplyr::bind_rows(results)

# Key principles:
# 1. Respect robots.txt
# 2. Add delays (Sys.sleep)
# 3. Set honest User-Agent
# 4. Cache HTML during development
# 5. Handle errors with tryCatch
cat('Polite scraping = sustainable scraping')
เริ่มต้นได้ฟรี

เรียนรู้ R ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
43
บทเรียน
159

คำถามที่พบบ่อย

บทเรียน “การจัดการการแบ่งหน้าและหลายหน้า” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การจัดการการแบ่งหน้าและหลายหน้า” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การจัดการการแบ่งหน้าและหลายหน้า”

วนดูผลลัพธ์ที่แบ่งหน้าและรวมข้อมูลที่ขูดมาเป็นชุดข้อมูลเดียว คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การจัดการการแบ่งหน้าและหลายหน้า” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม

ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. โครงสร้าง HTML และตัวเลือก CSS
  2. พื้นฐาน html_element() และ html_text()
  3. การขูดตารางและลิงก์
  4. การจัดการการแบ่งหน้าและหลายหน้า
← กลับไปที่ R Academy