テーブルとリンクのスクレイピング
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フィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- HTML構造とCSSセレクター
- html_element()とhtml_text()の基礎
- テーブルとリンクのスクレイピング
- ページネーションと複数ページの処理