RubyでHTMLを扱うメリット
RubyでHTMLを操作することは、Webアプリケーション開発やデータ収集の現場で大きな価値を生み出します。具体的なメリットを、実際の業務シーンに基づいて解説していきましょう。
Webスクレイピングの効率化で工数を50%削減
Rubyを使用したHTMLスクレイピングは、データ収集作業を劇的に効率化します。以下のような具体的なメリットがあります:
- 自動化による作業時間の大幅削減
- 手動収集:1日あたり8時間
- Ruby自動化後:1日あたり4時間以下
- 効率化率:約50%以上
- 大量データの高速処理
- 1秒あたり100件以上のページ処理が可能
- 並列処理による更なる高速化
- メモリ効率の良い段階的処理
- 柔軟なデータ抽出
- CSS セレクタによる直感的な要素指定
- XPath による複雑な条件指定
- 正規表現を使用した高度なパターンマッチング
実際の活用例:
require 'nokogiri'
require 'open-uri'
# Webページから特定の情報を抽出する例
url = "https://example.com/data"
doc = Nokogiri::HTML(URI.open(url))
# CSS セレクタで要素を抽出
prices = doc.css('.price').map(&:text)
自動化による人的ミスのゼロ化を実現
HTMLの手動操作で発生しがちな人的ミスを、Rubyによる自動化で確実に防止できます:
- データ収集時のミス削減効果
- タイプミス:100%削減
- データの欠落:98%削減
- フォーマットの不統一:100%削減
- 品質管理の向上
- 一貫性のある処理
- データ検証の自動化
- エラーログの自動記録
- 作業の標準化
- 処理手順の明確化
- 再現性の確保
- ドキュメント化の容易さ
実装例:
def validate_html_content(content)
begin
# HTMLの構文チェック
doc = Nokogiri::HTML(content) { |config| config.strict }
# 必要な要素の存在確認
required_elements = doc.css('title, meta[description], h1')
raise "必須要素が不足しています" if required_elements.empty?
# データの形式確認
prices = doc.css('.price').map(&:text)
prices.each do |price|
raise "価格フォーマットが不正です" unless price.match?(/^\d+円$/)
end
true
rescue => e
logger.error "バリデーションエラー: #{e.message}"
false
end
end
このように、RubyでHTMLを扱うことで、作業効率の向上だけでなく、品質の向上も実現できます。特に大規模なデータ処理や繰り返し作業が必要な場面では、その効果は顕著です。
次のセクションでは、これらのメリットを実現するための具体的な実装テクニックについて解説していきます。
RubyでHTMLを操作する基本テクニック
RubyでHTMLを操作する際の基本的なテクニックについて、実践的なコード例を交えながら解説します。
NokogirigemでHTMLをパースする方法
Nokogiriは、RubyでHTMLやXMLを操作する際の標準的なライブラリです。以下に基本的な使い方を示します:
- インストールと基本設定
# Gemfileに追加
gem 'nokogiri'
# プログラムでの読み込み
require 'nokogiri'
require 'open-uri'
# HTMLの読み込み
doc = Nokogiri::HTML(URI.open('https://example.com'))
- 要素の検索と取得
# CSS セレクタを使用した要素の取得
doc.css('.article-title') # クラスで検索
doc.css('#main-content') # IDで検索
doc.css('div p') # 階層関係で検索
# XPathを使用した要素の取得
doc.xpath('//div[@class="article"]')
doc.xpath('//h1[contains(text(), "Ruby")]')
# テキスト内容の取得
title = doc.at_css('h1').text
description = doc.at_css('meta[name="description"]')['content']
- 要素の操作
# 新しい要素の作成と追加
new_div = Nokogiri::HTML::DocumentFragment.parse('<div class="new">新しい内容</div>')
doc.at_css('body').add_child(new_div)
# 属性の変更
element = doc.at_css('.target')
element['class'] = 'modified'
element['data-value'] = '新しい値'
ERBテンプレートでHTMLを生成するベストプラクティス
ERB(Embedded Ruby)は、RubyのコードをHTMLに埋め込んでテンプレートを作成するための強力なツールです。
- 基本的な使い方
require 'erb'
# テンプレートの作成
template = <<-HTML
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= heading %></h1>
<% items.each do |item| %>
<div class="item">
<h2><%= item.name %></h2>
<p><%= item.description %></p>
</div>
<% end %>
</body>
</html>
HTML
# テンプレートの実行
title = "商品一覧"
heading = "おすすめ商品"
items = [
OpenStruct.new(name: "商品A", description: "説明文A"),
OpenStruct.new(name: "商品B", description: "説明文B")
]
erb = ERB.new(template)
result = erb.result(binding)
- パーシャルの活用
# _header.erb
<header>
<h1><%= site_title %></h1>
<nav>
<% navigation_items.each do |item| %>
<a href="<%= item[:url] %>"><%= item[:text] %></a>
<% end %>
</nav>
</header>
# メインテンプレート
def render_partial(partial_name, locals = {})
path = "_#{partial_name}.erb"
template = File.read(path)
erb = ERB.new(template)
erb.result_with_hash(locals)
end
# パーシャルの使用
header_html = render_partial('header', {
site_title: 'My Site',
navigation_items: [
{ url: '/', text: 'Home' },
{ url: '/about', text: 'About' }
]
})
CGIライブラリを使ったHTML操作の基礎
CGIライブラリは、WebフォームやHTTPリクエストの処理に便利な機能を提供します。
- 基本的なフォーム処理
require 'cgi'
cgi = CGI.new
# フォームパラメータの取得
name = cgi['name']
email = cgi['email']
# HTMLのエスケープ処理
escaped_text = CGI.escapeHTML('<script>alert("XSS");</script>')
# レスポンスの生成
print cgi.header
print <<-HTML
<!DOCTYPE html>
<html>
<head>
<title>フォーム処理結果</title>
</head>
<body>
<h1>送信された情報</h1>
<p>名前: #{CGI.escapeHTML(name)}</p>
<p>メール: #{CGI.escapeHTML(email)}</p>
</body>
</html>
HTML
- クッキーの処理
# クッキーの設定
cookie = CGI::Cookie.new(
'name' => 'user_id',
'value' => '12345',
'expires' => Time.now + 3600
)
# レスポンスヘッダーにクッキーを含める
print cgi.header('cookie' => [cookie])
# クッキーの読み取り
cookies = cgi.cookies
user_id = cookies['user_id'].first if cookies['user_id']
これらの基本テクニックを組み合わせることで、HTMLの解析、生成、フォーム処理など、様々なWebアプリケーションの要件に対応できます。次のセクションでは、これらの技術を使った実践的なプログラミング例を紹介します。
実践的なHTML操作プログラミング
実際の開発現場で使える、実践的なHTML操作プログラミングについて解説します。エラー処理やパフォーマンス最適化も含めた、本番環境で使用可能なコード例を紹介します。
スクレイピングスクリプトの作成手順
大規模なWebスクレイピングを安全かつ効率的に行うためのスクリプトを実装します。
require 'nokogiri'
require 'open-uri'
require 'logger'
require 'csv'
class WebScraper
def initialize
@logger = Logger.new('scraping.log')
@retry_count = 3
@delay = 1 # リクエスト間隔(秒)
end
def scrape_pages(urls)
results = []
urls.each do |url|
begin
# リクエスト間隔を設定してサーバーに負荷をかけない
sleep @delay
# ページの取得を試行
data = fetch_with_retry(url)
results << data if data
rescue StandardError => e
@logger.error("Error scraping #{url}: #{e.message}")
next
end
end
save_to_csv(results)
results
end
private
def fetch_with_retry(url)
tries = 0
begin
doc = Nokogiri::HTML(URI.open(url))
extract_data(doc)
rescue OpenURI::HTTPError, SocketError => e
tries += 1
if tries < @retry_count
@logger.warn("Retry #{tries}/#{@retry_count} for #{url}")
sleep(@delay * tries)
retry
else
raise e
end
end
end
def extract_data(doc)
{
title: doc.at_css('h1')&.text&.strip,
description: doc.at_css('meta[name="description"]')&.[]('content'),
price: doc.at_css('.price')&.text&.gsub(/[^\d]/, ''),
categories: doc.css('.category').map(&:text)
}
end
def save_to_csv(results)
CSV.open('scraped_data.csv', 'wb') do |csv|
csv << results.first.keys
results.each { |row| csv << row.values }
end
end
end
動的なWebページの生成テクニック
ユーザー入力に応じて動的にHTMLを生成する実装例です。
class DynamicPageGenerator
def initialize(template_dir)
@template_dir = template_dir
@cache = {}
end
def generate_page(template_name, data)
template = load_template(template_name)
layout = load_template('layout')
# XSS対策
sanitized_data = sanitize_data(data)
# テンプレートの実行
content = ERB.new(template).result_with_hash(sanitized_data)
# レイアウトへの埋め込み
ERB.new(layout).result_with_hash(
content: content,
title: sanitized_data[:title],
meta_description: sanitized_data[:description]
)
end
private
def load_template(name)
@cache[name] ||= begin
path = File.join(@template_dir, "#{name}.erb")
File.read(path)
end
end
def sanitize_data(data)
data.transform_values do |value|
case value
when String
CGI.escapeHTML(value)
when Array
value.map { |v| v.is_a?(String) ? CGI.escapeHTML(v) : v }
else
value
end
end
end
end
フォーム処理の実装方法
セキュアで使いやすいフォーム処理の実装例です。
require 'sinatra'
require 'rack/csrf'
class SecureFormHandler < Sinatra::Base
use Rack::Session::Cookie, secret: ENV['SESSION_SECRET']
use Rack::Csrf, raise: true
configure do
set :views, './views'
enable :logging
end
# フォームの表示
get '/contact' do
erb :contact, locals: {
csrf_token: Rack::Csrf.token(env),
csrf_tag: Rack::Csrf.tag(env)
}
end
# フォームの処理
post '/contact' do
begin
# バリデーション
validate_form_data(params)
# データの保存
save_contact_form(params)
# メール送信
send_notification_email(params)
# 成功ページへリダイレクト
redirect '/contact/thanks'
rescue ValidationError => e
# エラー時の処理
status 422
erb :contact, locals: {
errors: e.messages,
params: params,
csrf_token: Rack::Csrf.token(env),
csrf_tag: Rack::Csrf.tag(env)
}
end
end
private
def validate_form_data(params)
errors = []
errors << "名前は必須です" if params[:name].to_s.empty?
errors << "メールアドレスは必須です" if params[:email].to_s.empty?
errors << "メールアドレスの形式が不正です" unless params[:email] =~ /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
raise ValidationError.new(errors) unless errors.empty?
end
def save_contact_form(params)
# データベースへの保存処理
Contact.create!(
name: params[:name],
email: params[:email],
message: params[:message],
ip_address: request.ip,
user_agent: request.user_agent
)
end
def send_notification_email(params)
# メール送信処理
Mailer.contact_notification(
to: ENV['ADMIN_EMAIL'],
from: params[:email],
subject: "新しいお問い合わせ: #{params[:name]}",
body: params[:message]
).deliver_now
end
end
class ValidationError < StandardError
attr_reader :messages
def initialize(messages)
@messages = messages
super(messages.join(", "))
end
end
これらの実装例は、以下の重要な点を考慮しています:
- エラー処理
- 適切な例外処理
- リトライ機構
- ログ記録
- セキュリティ
- XSS対策
- CSRF対策
- 入力バリデーション
- パフォーマンス
- キャッシュの活用
- 適切なリクエスト間隔
- 効率的なデータ処理
- メンテナンス性
- クラスベースの設計
- 責務の分離
- 設定の外部化
これらのコードは実務での利用を想定して作成されていますが、実際の使用時には、プロジェクトの要件に応じて適切にカスタマイズすることをお勧めします。
HTML操作時の注意点とトラブルシューティング
RubyでHTMLを操作する際に直面する可能性のある問題と、その解決方法について解説します。実際の開発現場で役立つ具体的なトラブルシューティング手法を紹介します。
文字エンコーディングの適切な処理方法
文字エンコーディングの問題は、特に日本語を扱う際によく発生します。以下に主な対処方法を示します。
class EncodingHandler
def self.process_html(html_content)
# 文字エンコーディングの自動検出と変換
detected_encoding = detect_encoding(html_content)
# UTF-8への変換
content_utf8 = if detected_encoding
html_content.force_encoding(detected_encoding).encode('UTF-8')
else
html_content.force_encoding('UTF-8')
end
# 不正なバイト列の処理
content_utf8.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
end
private
def self.detect_encoding(content)
require 'charlock_holmes'
detection = CharlockHolmes::EncodingDetector.detect(content)
detection[:encoding] if detection
end
end
# 使用例
begin
html_content = File.read('webpage.html', encoding: 'ASCII-8BIT')
processed_content = EncodingHandler.process_html(html_content)
# Nokogiriでパース
doc = Nokogiri::HTML(processed_content)
rescue EncodingError => e
logger.error "エンコーディングエラー: #{e.message}"
end
メモリ使用量の最適化テクニック
大量のHTMLデータを処理する際のメモリ使用量を最適化する方法です。
class MemoryOptimizedParser
def initialize
@batch_size = 1000
@logger = Logger.new('memory_usage.log')
end
def process_large_html_file(file_path)
# メモリ使用量のモニタリング
initial_memory = memory_usage
File.open(file_path) do |file|
# ストリーミング処理でファイルを読み込み
Nokogiri::HTML::SAX::Parser.new(DocumentHandler.new).parse_io(file)
end
log_memory_usage(initial_memory)
end
def batch_process_elements(doc)
doc.css('target_element').each_slice(@batch_size) do |elements|
elements.each do |element|
yield element
end
# メモリの解放
GC.start if memory_critical?
end
end
private
def memory_usage
`ps -o rss= -p #{Process.pid}`.to_i
end
def memory_critical?
memory_usage > 1_000_000 # 1GB超過で警告
end
def log_memory_usage(initial_memory)
current_memory = memory_usage
@logger.info "メモリ使用量: #{current_memory - initial_memory}KB 増加"
end
end
# SAXパーサー用のハンドラー
class DocumentHandler < Nokogiri::XML::SAX::Document
def start_element(name, attributes = [])
# 要素の開始タグの処理
end
def end_element(name)
# 要素の終了タグの処理
end
def characters(string)
# テキストノードの処理
end
end
セキュリティ対策の実装ポイント
HTML操作時のセキュリティリスクと、その対策について解説します。
class SecureHTMLProcessor
ALLOWED_TAGS = %w(p br b i u h1 h2 h3 ul ol li)
ALLOWED_ATTRIBUTES = %w(href title alt)
def initialize
@sanitizer = Rails::HTML::SafeListSanitizer.new
end
def sanitize_html(html_content)
# HTMLの無害化
@sanitizer.sanitize(html_content,
tags: ALLOWED_TAGS,
attributes: ALLOWED_ATTRIBUTES
)
end
def process_user_input(input)
# XSS対策
escaped_input = CGI.escapeHTML(input)
# SQLインジェクション対策
sanitized_input = ActiveRecord::Base.connection.quote(escaped_input)
# パストラバーサル対策
safe_path = File.basename(input)
{
escaped: escaped_input,
sanitized_sql: sanitized_input,
safe_path: safe_path
}
end
def validate_url(url)
uri = URI.parse(url)
return false unless %w(http https).include?(uri.scheme)
# ホストの検証
allowed_hosts = ['example.com', 'api.example.com']
return false unless allowed_hosts.include?(uri.host)
true
rescue URI::InvalidURIError
false
end
def secure_file_write(content, path)
# 安全なディレクトリの確認
raise "不正なパス" unless safe_directory?(path)
# 一時ファイルを使用した安全な書き込み
temp_path = "#{path}.tmp"
File.write(temp_path, content)
File.rename(temp_path, path)
rescue => e
File.unlink(temp_path) if File.exist?(temp_path)
raise e
end
private
def safe_directory?(path)
allowed_dirs = ['/var/www/html/', '/tmp/safe/']
allowed_dirs.any? { |dir| path.start_with?(dir) }
end
end
主な注意点とその対策をまとめると:
- 文字エンコーディング
- 入力データのエンコーディング検出
- UTF-8への適切な変換
- 不正なバイト列の処理
- メモリ管理
- バッチ処理の活用
- ストリーミング処理の利用
- 定期的なGCの実行
- メモリ使用量のモニタリング
- セキュリティ
- HTMLサニタイズ
- XSS対策
- SQLインジェクション対策
- パストラバーサル対策
- URL検証
これらの対策を適切に実装することで、安全で効率的なHTML操作を実現できます。ただし、セキュリティ対策は常に最新の脅威に対応する必要があるため、定期的な見直しと更新を行うことをお勧めします。
実務で使えるコード例とサンプル
ここでは、実務でそのまま使用できる具体的なコード例を提供します。各実装には詳細なコメントと使用方法の説明を付記しています。
HTMLパーサーの実装例
複数のWebページから必要な情報を抽出し、構造化されたデータとして保存する実用的なHTMLパーサーです。
require 'nokogiri'
require 'open-uri'
require 'json'
require 'logger'
class HTMLParser
class ParserError < StandardError; end
def initialize(config = {})
@config = {
cache_enabled: true,
cache_duration: 3600, # 1時間
retry_count: 3,
retry_delay: 1,
user_agent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
timeout: 30
}.merge(config)
@logger = Logger.new('parser.log')
@cache = {}
end
def parse(url, selectors)
content = fetch_with_cache(url)
doc = Nokogiri::HTML(content)
result = {}
selectors.each do |key, selector|
result[key] = extract_data(doc, selector)
end
result
rescue => e
@logger.error "Parsing error for #{url}: #{e.message}"
raise ParserError, "Failed to parse #{url}: #{e.message}"
end
private
def fetch_with_cache(url)
return @cache[url][:content] if cache_valid?(url)
content = fetch_with_retry(url)
cache_store(url, content) if @config[:cache_enabled]
content
end
def cache_valid?(url)
return false unless @config[:cache_enabled]
return false unless @cache[url]
cache_time = @cache[url][:timestamp]
Time.now - cache_time < @config[:cache_duration]
end
def cache_store(url, content)
@cache[url] = {
content: content,
timestamp: Time.now
}
end
def fetch_with_retry(url)
retries = 0
begin
URI.open(
url,
'User-Agent' => @config[:user_agent],
read_timeout: @config[:timeout]
).read
rescue OpenURI::HTTPError, SocketError => e
retries += 1
if retries < @config[:retry_count]
sleep(@config[:retry_delay] * retries)
retry
else
raise e
end
end
end
def extract_data(doc, selector)
case selector
when String
doc.css(selector).text.strip
when Hash
if selector[:type] == 'attribute'
doc.css(selector[:selector])[selector[:attribute]]
elsif selector[:type] == 'array'
doc.css(selector[:selector]).map(&:text).map(&:strip)
end
end
end
end
# 使用例
parser = HTMLParser.new(
cache_enabled: true,
cache_duration: 1800 # 30分
)
selectors = {
title: 'h1.article-title',
description: 'meta[name="description"]',
tags: {
type: 'array',
selector: '.tag'
},
image_url: {
type: 'attribute',
selector: 'meta[property="og:image"]',
attribute: 'content'
}
}
begin
result = parser.parse('https://example.com/article', selectors)
puts JSON.pretty_generate(result)
rescue HTMLParser::ParserError => e
puts "エラーが発生しました: #{e.message}"
end
テンプレートエンジンの活用例
再利用可能なコンポーネントを持つ、実用的なテンプレートエンジンの実装例です。
require 'erb'
require 'ostruct'
class TemplateEngine
class RenderError < StandardError; end
def initialize(template_dir)
@template_dir = template_dir
@components = {}
@helpers = Module.new
load_components
end
def render(template_name, locals = {})
template = load_template(template_name)
context = create_context(locals)
ERB.new(template).result(context.instance_eval { binding })
rescue => e
raise RenderError, "Template rendering failed: #{e.message}"
end
def register_helper(name, &block)
@helpers.define_method(name, &block)
end
def component(name, locals = {})
raise RenderError, "Component not found: #{name}" unless @components[name]
render(@components[name], locals)
end
private
def load_template(name)
path = File.join(@template_dir, "#{name}.erb")
File.read(path)
rescue Errno::ENOENT
raise RenderError, "Template not found: #{name}"
end
def load_components
component_dir = File.join(@template_dir, 'components')
return unless Dir.exist?(component_dir)
Dir.glob(File.join(component_dir, '*.erb')).each do |file|
name = File.basename(file, '.erb')
@components[name] = "components/#{name}"
end
end
def create_context(locals)
context = OpenStruct.new(locals)
context.extend(@helpers)
context.define_singleton_method(:component) { |name, **opts| component(name, opts) }
context
end
end
# 使用例
# ヘルパーメソッドの定義
engine = TemplateEngine.new('templates')
engine.register_helper(:format_date) do |date|
date.strftime('%Y年%m月%d日')
end
engine.register_helper(:sanitize) do |text|
CGI.escapeHTML(text)
end
# テンプレートの例(templates/article.erb)
=begin
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<%= component 'header', title: title %>
<article>
<h1><%= sanitize(title) %></h1>
<time><%= format_date(published_at) %></time>
<%= content %>
</article>
<%= component 'footer' %>
</body>
</html>
=end
# コンポーネントの例(templates/components/header.erb)
=begin
<header>
<h1><%= title %></h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
=end
# 使用例
begin
html = engine.render('article', {
title: '記事タイトル',
content: '記事の内容...',
published_at: Time.now
})
puts html
rescue TemplateEngine::RenderError => e
puts "レンダリングエラー: #{e.message}"
end
実用的なスクレイピングコード
複数ページの巡回や並列処理に対応した、実用的なスクレイピング実装です。
require 'nokogiri'
require 'open-uri'
require 'concurrent'
require 'csv'
require 'logger'
class WebCrawler
class CrawlError < StandardError; end
def initialize(config = {})
@config = {
max_threads: 5,
max_depth: 3,
delay: 1,
max_pages: 1000,
output_file: 'crawl_results.csv',
allowed_domains: []
}.merge(config)
@visited = Concurrent::Set.new
@queue = Queue.new
@results = Concurrent::Array.new
@logger = Logger.new('crawler.log')
end
def crawl(start_url, selectors)
@start_time = Time.now
@queue.push([start_url, 0])
threads = @config[:max_threads].times.map do
Thread.new do
while !@queue.empty? && @visited.size < @config[:max_pages]
process_url(@queue.pop, selectors)
end
end
end
threads.each(&:join)
save_results
log_summary
rescue => e
@logger.error "Crawl error: #{e.message}"
raise CrawlError, "Crawling failed: #{e.message}"
end
private
def process_url((url, depth), selectors)
return if depth >= @config[:max_depth]
return if @visited.include?(url)
return unless allowed_domain?(url)
@visited.add(url)
sleep(@config[:delay])
begin
doc = Nokogiri::HTML(URI.open(url))
data = extract_data(doc, selectors)
@results << data.merge(url: url)
# 次のURLを抽出
next_urls = doc.css('a').map { |link| link['href'] }
next_urls.each do |next_url|
next unless next_url
absolute_url = URI.join(url, next_url).to_s
@queue.push([absolute_url, depth + 1])
end
rescue => e
@logger.warn "Failed to process #{url}: #{e.message}"
end
end
def extract_data(doc, selectors)
result = {}
selectors.each do |key, selector|
result[key] = case selector
when String
doc.css(selector).text.strip
when Hash
if selector[:type] == 'array'
doc.css(selector[:selector]).map(&:text).map(&:strip)
else
doc.css(selector[:selector]).first&.[](selector[:attribute])
end
end
end
result
end
def allowed_domain?(url)
return true if @config[:allowed_domains].empty?
uri = URI.parse(url)
@config[:allowed_domains].any? { |domain| uri.host.end_with?(domain) }
end
def save_results
CSV.open(@config[:output_file], 'wb') do |csv|
csv << @results.first.keys
@results.each { |result| csv << result.values }
end
end
def log_summary
duration = Time.now - @start_time
@logger.info "Crawl completed:"
@logger.info "Pages processed: #{@visited.size}"
@logger.info "Data collected: #{@results.size} items"
@logger.info "Duration: #{duration.round(2)} seconds"
end
end
# 使用例
crawler = WebCrawler.new(
max_threads: 3,
max_depth: 2,
delay: 1.5,
allowed_domains: ['example.com'],
output_file: 'products.csv'
)
selectors = {
title: 'h1.product-title',
price: '.price',
description: 'meta[name="description"]',
images: {
type: 'array',
selector: '.product-images img'
}
}
begin
crawler.crawl('https://example.com/products', selectors)
rescue WebCrawler::CrawlError => e
puts "クロールエラー: #{e.message}"
end
これらのコード例は以下の特徴を持っています:
- エラーハンドリング
- 適切な例外処理
- リトライメカニズム
- ログ記録
- パフォーマンス最適化
- キャッシュ機構
- 並列処理
- メモリ使用量の制御
- 拡張性
- 設定のカスタマイズ
- モジュール化された設計
- 再利用可能なコンポーネント
- 実用的な機能
- 進捗のログ記録
- 結果の保存
- 豊富なオプション
これらのコードは実際の開発現場での要件を想定して作成されていますが、使用時には必要に応じて適切にカスタマイズすることをお勧めします。また、セキュリティ面での考慮事項も必ず確認してください。