0Pricing
R Academy · レッスン

テーブルとリンクのスクレイピング

HTMLテーブルをデータフレームに解析し、ページ上のすべてのハイパーリンクを収集します。

「テーブルとリンクのスクレイピング」はCoddyKit上の無料R Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはR Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 R Academyコースには全4レッスンが含まれています。

WebページのHTMLテーブル

HTMLテーブル(<table>)は、すでに構造化されているため、スクレイピングの対象として最も扱いやすいものです。rvestのhtml_table()を使うと、ヘッダーを自動的に処理しながら、テーブルを直接Rのデータフレームに変換できます。

library(rvest)
html <- read_html('
  <table>
    <thead><tr><th>Country</th><th>GDP</th><th>Pop</th></tr></thead>
    <tbody>
      <tr><td>USA</td><td>25T</td><td>330M</td></tr>
      <tr><td>China</td><td>18T</td><td>1400M</td></tr>
    </tbody>
  </table>
')
# html_table converts to data frame
tbl <- html_table(html_element(html, 'table'))
class(tbl)      # 'data.frame'
names(tbl)      # c('Country', 'GDP', 'Pop')
nrow(tbl)       # 2
print(tbl)

ページ全体に対するhtml_table()

ページに複数のテーブルがある場合は、html_elements()(複数形)ですべてのテーブルを取得し、結果のnodesetに対してhtml_table()を使用すると、データフレームのリストが返されます。インデックスで必要なテーブルを選択します。

library(rvest)
html <- read_html('
  <table id="t1"><tr><th>A</th></tr><tr><td>1</td></tr></table>
  <table id="t2"><tr><th>X</th><th>Y</th></tr>
    <tr><td>10</td><td>20</td></tr></table>
')
# Get ALL tables as a list of data frames
tables <- html_table(html_elements(html, 'table'))
length(tables)  # 2

# First table
tables[[1]]

# Second table
tables[[2]]

# Select a specific table by its id
table2 <- html_table(html_element(html, '#t2'))
print(table2)

テーブルデータのクリーニング

Webサイトから取得したテーブルには、扱いにくいヘッダー、結合セル、余分な空白が含まれていることがよくあります。ヘッダーにはjanitor::clean_names()を使用し、セルの値には通常のdplyrやstringrの処理を適用して整形します。

library(rvest)
html <- read_html('
  <table>
    <tr><th>Product Name</th><th>Price (USD)</th><th>In Stock?</th></tr>
    <tr><td>  Widget A  </td><td>$12.50</td><td>Yes</td></tr>
    <tr><td>Gadget B</td><td>$7.99</td><td>No</td></tr>
  </table>
')
df <- html_table(html_element(html, 'table'))

# Clean column names
names(df) <- c('product', 'price', 'in_stock')

# Strip whitespace and dollar signs
df$product  <- trimws(df$product)
df$price    <- as.numeric(gsub('[$]', '', df$price))
df$in_stock <- df$in_stock == 'Yes'
print(df)

ページ上のすべてのリンクをスクレイピングする

リンクは、href属性を持つアンカー(<a>)タグです。html_elements(page, 'a')ですべてのアンカーを取得し、URLにはhtml_attr('href')、リンクテキストにはhtml_text2()を使用します。

library(rvest)
html <- read_html('
  <div>
    <a href="/about">About Us</a>
    <a href="/products">Products</a>
    <a href="https://partner.com" rel="external">Partner</a>
    <a>No href link</a>
  </div>
')
# Get all anchor elements
anchors <- html_elements(html, 'a')

# Extract text and href
link_text <- html_text2(anchors)
link_href <- html_attr(anchors, 'href')

data.frame(text = link_text, href = link_href)
# Note: last row has NA href

意味のあるリンクの絞り込み

実際のページには、必要なリンクに加えて、ナビゲーションリンク、フッターリンク、内部アンカーなども混在しています。NA、アンカー(#)、javascript:リンクを除外し、パターンマッチングを適用して関連するURLだけを残します。

library(rvest)
html <- read_html('
  <div>
    <a href="/article/1">Article One</a>
    <a href="/article/2">Article Two</a>
    <a href="#top">Back to top</a>
    <a href="javascript:void(0)">JS link</a>
    <a href="/article/3">Article Three</a>
  </div>
')
anchors <- html_elements(html, 'a')
hrefs <- html_attr(anchors, 'href')
texts <- html_text2(anchors)

# Keep only article links
article_idx <- grepl('^/article/', hrefs) & !is.na(hrefs)
article_links <- data.frame(
  text = texts[article_idx],
  href = hrefs[article_idx]
)
print(article_links)

相対URLから絶対URLへ

スクレイピングで取得したhrefの値は、/pageのような相対パスであることがよくあります。ベースURLを先頭に付けて絶対URLに変換します。xml2::url_absolute()関数を使うと正しく処理できます。

library(rvest)
base_url <- 'https://books.toscrape.com'

html <- read_html('
  <ul>
    <li><a href="/catalogue/book1">Book One</a></li>
    <li><a href="/catalogue/book2">Book Two</a></li>
    <li><a href="https://external.com/book">External</a></li>
  </ul>
')
hrefs <- html_attr(html_elements(html, 'a'), 'href')

# xml2::url_absolute resolves relative + keeps absolute
abs_urls <- xml2::url_absolute(hrefs, base = base_url)
abs_urls
# 'https://books.toscrape.com/catalogue/book1'
# 'https://books.toscrape.com/catalogue/book2'
# 'https://external.com/book'  <- kept as-is

対象を絞ったリンクのスクレイピング

すべてのリンクを取得してから絞り込む代わりに、特定のCSSセレクターを使って必要なリンクだけを対象にします。要素のコンテキストと属性セレクターを組み合わせると、より正確に指定できます。

library(rvest)
html <- read_html('
  <nav class="breadcrumb">
    <a href="/">Home</a> > <a href="/books">Books</a>
  </nav>
  <ul class="products">
    <li><a href="/books/1" class="prod-link">Clean Code</a></li>
    <li><a href="/books/2" class="prod-link">Refactoring</a></li>
  </ul>
  <footer>
    <a href="/privacy">Privacy</a>
  </footer>
')
# Target ONLY product links (not nav or footer)
prod_links <- html_elements(html, 'ul.products a.prod-link')
data.frame(
  title = html_text2(prod_links),
  url   = html_attr(prod_links, 'href')
)

テーブルデータとリンクデータの結合

テーブルのセルにリンクが含まれていることはよくあります。テキスト値にはhtml_table()を使用し、埋め込まれたリンクには対象を絞ったhtml_attr()を使用して、より情報量の多いデータフレームを作成します。

library(rvest)
html <- read_html('
  <table class="results">
    <tr><th>Book</th><th>Author</th></tr>
    <tr>
      <td><a href="/b/1">Clean Code</a></td>
      <td>Robert Martin</td>
    </tr>
    <tr>
      <td><a href="/b/2">Refactoring</a></td>
      <td>Martin Fowler</td>
    </tr>
  </table>
')
# Get text from table
df <- html_table(html_element(html, 'table'))

# Get links embedded in first column
links <- html_attr(html_elements(html, 'table td a'), 'href')
df$url <- links
print(df)

html_table()のfillパラメーター

HTMLテーブルには、セルの欠落や不規則な構造の行が含まれることがあります。html_table()のfill=TRUEパラメーターを使うと、エラーを発生させず、欠落した値をNAで埋められます。

library(rvest)
html <- read_html('
  <table>
    <tr><th>Name</th><th>Score</th><th>Grade</th></tr>
    <tr><td>Alice</td><td>95</td><td>A</td></tr>
    <tr><td>Bob</td><td>80</td></tr>
  </table>
')
# Without fill=TRUE this may error on uneven rows
df <- html_table(html_element(html, 'table'), fill = TRUE)
print(df)
# Name  Score Grade
# Alice    95     A
# Bob      80  <NA>

# fill=TRUE is safe even when rows are uniform
is.na(df[2, 'Grade'])  # TRUE

画像ソースの抽出

画像はsrc属性を使用します(遅延読み込みではdata-srcが使われることもあります)。同じhtml_attr()の方法で画像URLを抽出し、ダウンロードやカタログ化に利用できます。

library(rvest)
html <- read_html('
  <div class="gallery">
    <img src="/img/photo1.jpg" alt="Sunset">
    <img src="/img/photo2.jpg" alt="Mountains">
    <img data-src="/img/lazy.jpg" class="lazy" alt="Lake">
  </div>
')
# Regular images
images <- html_elements(html, 'img')
srcs  <- html_attr(images, 'src')
alts  <- html_attr(images, 'alt')

data.frame(alt = alts, src = srcs)
# For lazy-loaded images check data-src
lazy_src <- html_attr(html_element(html, '.lazy'), 'data-src')
lazy_src  # '/img/lazy.jpg'

スクレイピングしたデータの保存

テーブルやリンクをデータフレームに抽出したら、write.csv()またはreadr::write_csv()で結果を保存します。データの出所を追跡できるよう、必ずタイムスタンプまたはソースURLを含めてください。

library(rvest)
html <- read_html('
  <table>
    <tr><th>Product</th><th>Price</th></tr>
    <tr><td>Widget</td><td>9.99</td></tr>
    <tr><td>Gadget</td><td>14.50</td></tr>
  </table>
')
df <- html_table(html_element(html, 'table'))

# Add metadata
df$scraped_at <- Sys.time()
df$source_url <- 'https://example.com/products'

# Save to CSV
# write.csv(df, 'products.csv', row.names = FALSE)
print(df)
cat('Data ready for analysis or storage')

クイックチェック

rvestを使ったHTMLテーブルとリンクのスクレイピングについて、理解度を確認しましょう。

まとめ:テーブルとリンク

重要なポイント: html_table()はHTMLテーブルを自動的にデータフレームへ変換します。不規則なテーブルにはfill=TRUEを使用します。リンクについては、html_elements('a')ですべてのアンカーを取得し、html_text2()でテキストを、html_attr('href')でURLを取得します。相対URLはxml2::url_absolute()で絶対URLに変換します。パターンによって不要なリンクを絞り込みます。テーブルのテキストと埋め込まれたリンクURLを結合すると、より情報量の多いデータセットを作成できます。

library(rvest)
# Table scraping pattern:
# tables <- html_table(html_elements(page, 'table'))
# df <- tables[[1]]

# Link scraping pattern:
# links <- html_elements(page, 'a[href]')
# data.frame(
#   text = html_text2(links),
#   url  = xml2::url_absolute(
#            html_attr(links, 'href'),
#            base = base_url
#          )
# )

# Combine: scrape table text AND embedded link URLs
cat('Tables + links = most of what the web offers')

よくある質問

「テーブルとリンクのスクレイピング」レッスンは無料ですか?

はい。「テーブルとリンクのスクレイピング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、R Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 R Academyコースには全4レッスンが含まれています。

「テーブルとリンクのスクレイピング」で何を学びますか?

HTMLテーブルをデータフレームに解析し、ページ上のすべてのハイパーリンクを収集します。 ブラウザで直接実行するハンズオンコードでR Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

R Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのR Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「テーブルとリンクのスクレイピング」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このR Academyレッスンでコードを書いて実行できますか?

はい。すべてのR Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. HTML構造とCSSセレクター
  2. html_element()とhtml_text()の基礎
  3. テーブルとリンクのスクレイピング
  4. ページネーションと複数ページの処理
← R Academyに戻る