R Academy · درس

التعامل مع تقسيم الصفحات والصفحات المتعددة

كرّر على النتائج المقسّمة إلى صفحات وادمج البيانات المكشوطة في مجموعة بيانات واحدة.

الدرس 4 من 413 خطوة

التعامل مع تقسيم الصفحات والصفحات المتعددة درس مجاني في R Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 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() بين الطلبات احترامًا للخادم. ويكون التأخير من ثانية إلى ثانيتين كافيًا عادةً.

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)

اختبار سريع

اختبروا مدى فهمكم للكشط المهذّب والمتين لصفحات متعددة.

مراجعة: تقسيم الصفحات والكشط المهذّب

أهم النقاط: أنشئوا عناوين الصفحات باستخدام 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 مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
43
الدروس
159

الأسئلة الشائعة

هل درس «التعامل مع تقسيم الصفحات والصفحات المتعددة» مجاني؟

نعم — نص درس «التعامل مع تقسيم الصفحات والصفحات المتعددة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة R Academy، انتقل إلى CoddyKit PRO. تتضمن دورة R Academy 4 دروس في المجموع.

ماذا ستتعلم في «التعامل مع تقسيم الصفحات والصفحات المتعددة»؟

كرّر على النتائج المقسّمة إلى صفحات وادمج البيانات المكشوطة في مجموعة بيانات واحدة. تتمرن على R Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ R Academy؟

لا تُشترط خبرة سابقة. R Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «التعامل مع تقسيم الصفحات والصفحات المتعددة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس R Academy هذا؟

نعم. كل درس في R Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. بنية HTML ومحدّدات CSS
  2. أساسيات html_element() وhtml_text()
  3. كشط الجداول والروابط
  4. التعامل مع تقسيم الصفحات والصفحات المتعددة
← العودة إلى R Academy