Ruby爬虫如何控制并发数量:爬取京东电子产品

1. 引言

京东作为中国最大的电商平台之一,拥有海量的商品信息,其中电子产品是其热门品类之一。对于市场研究人员、数据分析师和开发者来说,能够高效地爬取和分析这些数据具有重要的价值。然而,京东网站的复杂性和反爬措施使得爬取任务更具挑战性。合理控制并发数量不仅能提高爬取效率,还能避免触发网站的反爬机制,确保爬虫的稳定运行。

Ruby语言以其简洁的语法和强大的并发处理能力,结合Nokogiri等库,成为开发高效爬虫的理想选择。本文将通过一个实战案例,展示如何在Ruby爬虫中控制并发数量,同时解析京东电子产品页面并提取标题。

2. 爬虫设计与实现

在本节中,我们将详细介绍如何设计和实现一个Ruby爬虫,用于爬取京东电子产品页面并提取标题。我们将从简单的单线程爬虫开始,逐步扩展到并发爬虫,并最终实现动态并发控制。

2.1 单线程爬虫

单线程爬虫是最基本的爬虫形式,适用于小规模数据爬取。以下是单线程爬虫的实现代码:

ruby 复制代码
require 'nokogiri'
require 'open-uri'

proxy_host = "www.16yun.cn"
proxy_port = 5445
proxy_user = "16QMSOML"
proxy_pass = "280651"

def fetch_title(url, proxy_host, proxy_port, proxy_user, proxy_pass)
  begin
    # 使用代理服务器打开网页
    doc = Nokogiri::HTML(URI.open(url, proxy_addr: proxy_host, proxy_port: proxy_port,
                                  proxy_user: proxy_user, proxy_pass: proxy_pass))
    doc.at('title').text
  rescue StandardError => e
    puts "Error fetching #{url}: #{e.message}"
    nil
  end
end

# 示例:爬取京东电子产品首页
url = 'https://www.jd.com/category/1320-13753-13883.html'
title = fetch_title(url, proxy_host, proxy_port, proxy_user, proxy_pass)
puts "Title: #{title}"

2.2 并发爬虫

单线程爬虫效率较低,尤其是在爬取大量页面时。通过并发处理,可以显著提高爬取效率。以下是使用concurrent-ruby库实现的并发爬虫代码:

ruby 复制代码
require 'nokogiri'
require 'open-uri'
require 'concurrent'

proxy_host = "www.16yun.cn"
proxy_port = 5445
proxy_user = "16QMSOML"
proxy_pass = "280651"

def fetch_title(url, proxy_host, proxy_port, proxy_user, proxy_pass)
  begin
    doc = Nokogiri::HTML(URI.open(url, proxy_addr: proxy_host, proxy_port: proxy_port,
                                  proxy_user: proxy_user, proxy_pass: proxy_pass))
    doc.at('title').text
  rescue StandardError => e
    puts "Error fetching #{url}: #{e.message}"
    nil
  end
end

# 创建线程池,最大并发数为5
pool = Concurrent::ThreadPoolExecutor.new(max_threads: 5)

urls = [
  'https://www.jd.com/category/1320-13753-13883.html', # 电子产品
  'https://www.jd.com/category/1320-13754-13884.html', # 手机
  'https://www.jd.com/category/1320-13755-13885.html'  # 笔记本电脑
]

# 使用线程池并发爬取
results = urls.map do |url|
  pool.post(url, proxy_host, proxy_port, proxy_user, proxy_pass) do |u, host, port, user, pass|
    fetch_title(u, host, port, user, pass)
  end
end

titles = results.map(&:value).compact
titles.each { |title| puts "Title: #{title}" }

pool.shutdown

2.3 动态并发调整

在实际应用中,目标网站的响应时间可能因网络状况和服务器负载而波动。通过动态调整并发数量,可以优化爬取效率,同时避免对目标网站造成过大压力。以下是动态并发调整的实现代码:

ruby 复制代码
require 'nokogiri'
require 'open-uri'
require 'concurrent'

def fetch_title(url, pool)
  start_time = Time.now
  begin
    doc = Nokogiri::HTML(URI.open(url))
    title = doc.at('title').text
    puts "Fetched #{url}: #{title}"
    title
  rescue StandardError => e
    puts "Error fetching #{url}: #{e.message}"
    nil
  ensure
    elapsed_time = Time.now - start_time
    adjust_concurrency(pool, elapsed_time)
  end
end

def adjust_concurrency(pool, elapsed_time)
  if elapsed_time < 0.5
    pool.resize([pool.max_threads + 1, 10].min) # 最大并发数不超过10
  elsif elapsed_time > 2.0
    pool.resize([pool.max_threads - 1, 1].max) # 最小并发数为1
  end
end

pool = Concurrent::ThreadPoolExecutor.new(max_threads: 5)
urls = [
  'https://www.jd.com/category/1320-13753-13883.html',
  'https://www.jd.com/category/1320-13754-13884.html',
  'https://www.jd.com/category/1320-13755-13885.html'
]

results = urls.map { |url| pool.post(url, pool, &method(:fetch_title)) }
titles = results.map(&:value).compact

titles.each { |title| puts "Title: #{title}" }

pool.shutdown

总结

本文通过一个具体的实战案例------爬取京东电子产品页面并提取标题,详细介绍了如何在Ruby爬虫中控制并发数量。从基础的单线程爬虫到并发爬虫,再到动态并发调整和分布式爬虫,本文为读者提供了一个全面的指南。通过合理控制并发数量,不仅可以提高爬取效率,还可以避免触发目标网站的反爬机制,确保爬虫的稳定运行。

相关推荐
花酒锄作田22 分钟前
[python]基于动态实例的命令处理设计
python
Evand J22 分钟前
【matlab例程】无迹粒子滤波(UPF)的例程,用于三维环境下多雷达目标跟踪,非线性系统
开发语言·matlab·目标跟踪
1892280486132 分钟前
NX947NX955美光固态闪存NX962NX966
大数据·服务器·网络·人工智能·科技
2501_9248787342 分钟前
无人机光伏巡检缺陷检出率↑32%:陌讯多模态融合算法实战解析
开发语言·人工智能·算法·视觉检测·无人机
计算机毕设定制辅导-无忧学长1 小时前
InfluxDB 与 Python 框架结合:Django 应用案例(三)
开发语言·python·django
惜.己1 小时前
python中appium
开发语言·python·appium
小沈熬夜秃头中୧⍤⃝1 小时前
Python 入门指南:从零基础到环境搭建
开发语言·python
睿思达DBA_WGX1 小时前
Python 程序设计讲义(54):Python 的函数——函数概述
开发语言·python
真智AI1 小时前
打破数据质量瓶颈:用n8n实现30秒专业数据质量报告自动化
大数据·运维·人工智能·python·自动化
Algebraaaaa1 小时前
C++ 中 NULL 与 nullptr 有什么区别?
开发语言·c++