Ruby:多线程队列(Queue)下载博客文章到本地
Ruby:多线程下载博客文章到本地的完整代码
#encoding:utf-8
require 'net/http'
require 'thread'
require 'open-uri'
require 'nokogiri'
require 'date' $queue = Queue.new
#文章列表页数
page_nums = 8
page_nums.times do |num|
$queue.push("http://www.cnblogs.com/hongfei/default.html?page="+num.to_s)
end threads = []
#获取网页源码
def get_html(url)
html = ""
open(url) do |f|
html = f.read
end
return html
end def fetch_links(html)
doc = Nokogiri::HTML(html)
#提取文章链接
doc.xpath('//div[@class="postTitle"]/a').each do |link|
href = link['href'].to_s
if href.include?"html"
#add work to the queue
$queue.push(link['href'])
end
end
end def save_to(save_to,content)
f = File.new("./"+save_to+".html","w+")
f.write(content)
f.close()
end #程序开始的时间
$total_time_begin = Time.now.to_i #开辟的线程数
threadNums = 10
threadNums.times do
threads<<Thread.new do
until $queue.empty?
url = $queue.pop(true) rescue nil
html = get_html(url)
fetch_links(html)
if !url.include?"?page"
title = Nokogiri::HTML(html).css('title').text
puts "["+ Time.now.strftime("%H:%M:%S") + "]「" + title + "」" + url
save_to("pages/" + title.gsub(/\//,""),html) if url.include?".html"
end
end
end
end
threads.each{|t| t.join} #程序结束的时间
$total_time_end = Time.now.to_i
puts "线程数:" + threadNums.to_s
puts "执行时间:" + ($total_time_end - $total_time_begin).to_s + "秒"
多线程部分讲解
$queue = Queue.new
#文章列表页数
page_nums = 8
page_nums.times do |num|
$queue.push("http://www.cnblogs.com/hongfei/default.html?page="+num.to_s)
end
首先声明一个Queue队列,然后往队列中添加文章列表页,以便后面可以从这些列表页中提取文章链接,另外queue声明成全局变量($),以便在函数中也可以访问到
我的曾是土木人博客文章列表总共有8页,所以需要实现给page_nums赋值为8
#开辟的线程数
threadNums = 10
threadNums.times do
threads<<Thread.new do
until $queue.empty?
url = $queue.pop(true) rescue nil
html = get_html(url)
fetch_links(html)
if !url.include?"?page"
title = Nokogiri::HTML(html).css('title').text
puts "["+ Time.now.strftime("%H:%M:%S") + "]「" + title + "」" + url
save_to("pages/" + title.gsub(/\//,""),html) if url.include?".html"
end
end
end
end
threads.each{|t| t.join}
通过Thread.new来创建线程
创建线程后,会进入until $queue.empty?循环,直到任务队列为空(即:没有要采集的网址了)
开辟的线程,每次都会从任务队列(queue)取到一个url,并通过get_html函数获取网页源码
由于任务队列中的url有分页url和文章url两种,所以要进行区分。
如果是分页url(url中含有“?page”),就直接提取文章链接。
如果是文章url,就保存到本地(save_to(),文件名为文章title)
在循环体外,创建线程完毕后,需要将创建的线程执行Thread#join方法,以便让主线程等待,
直到所有的线程执行完毕才结束主线程
代码执行时间统计
#程序开始的时间
$total_time_begin = Time.now.to_i
#执行过程 #程序结束的时间
$total_time_end = Time.now.to_i
puts "执行时间:" + ($total_time_end - $total_time_begin).to_s + "秒"
TIme模块的#now方法可以获取当前时间,然后使用to_i,可以将当前时间转换成从1970年1月1日00:00:00 UTC开始所经过的秒数。
获取网页源码
#获取网页源码
def get_html(url)
html = ""
open(url) do |f|
html = f.read
end
return html
end
ruby中,获取网页的方法用Net::HTTP模块和OpenURI模块。OpenURI模块最简单,可以直径将指定网页当成普通文件一样进行操作。
执行结果:使用多线程采集130多篇文章,耗时15秒(单线程:47s左右)
推荐阅读:
作 者:曾是土木人(http://www.cnblogs.com/hongfei)
原文地址:http://www.cnblogs.com/hongfei/p/3696392.html
Ruby:多线程队列(Queue)下载博客文章到本地的更多相关文章
- CSDN博客文章的备份及导出电子书CHM
需要用到的工具集合下载:http://download.csdn.net/source/2881423 在CSDN.百度等写博客文章的应该很多,很多时候担心服务器有一天突然挂了,或者担心自己的号被封了 ...
- 年度十佳 DevOps 博客文章(后篇)
如果说 15 年你还没有将 DevOps 真正应用起来,16 年再不实践也未免太落伍了.在上篇文章中我们了解到 15 年十佳 DevOps 博客文章的第 6-10 名,有没有哪一篇抓住了您的眼球,让您 ...
- [Python学习] 简单网络爬虫抓取博客文章及思想介绍
前面一直强调Python运用到网络爬虫方面很有效,这篇文章也是结合学习的Python视频知识及我研究生数据挖掘方向的知识.从而简介下Python是怎样爬去网络数据的,文章知识很easy ...
- 一文搞定scrapy爬取众多知名技术博客文章保存到本地数据库,包含:cnblog、csdn、51cto、itpub、jobbole、oschina等
本文旨在通过爬取一系列博客网站技术文章的实践,介绍一下scrapy这个python语言中强大的整站爬虫框架的使用.各位童鞋可不要用来干坏事哦,这些技术博客平台也是为了让我们大家更方便的交流.学习.提高 ...
- 利用爬虫将Yuan先生的博客文章爬取下来
由于一次巧遇,我阅读了Yuan先生的一篇博客文章,感觉从Yuan先生得博客学到很多东西,很喜欢他得文章.于是我就关注了他,并且想阅读更多出自他手笔得博客文章,无奈,可能Yuan先生不想公开自己得博客吧 ...
- 使用IntelliJ IDEA开发SpringMVC网站(五)博客文章管理
原文:使用IntelliJ IDEA开发SpringMVC网站(五)博客文章管理 摘要 通过对博客文章的管理,实现外键操作. 目录[-] 八.博客文章管理 1.查看文章 2.添加博客 3 ...
- HelloDjango 第 08 篇:开发博客文章详情页
作者:HelloGitHub-追梦人物 文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库 首页展示的是所有文章的列表,当用户看到感兴趣的文章时,他点击文章的标题或者继续阅读的按 ...
- 利用爬虫爬取指定用户的CSDN博客文章转为md格式,目的是完成博客迁移博文到Hexo等静态博客
文章目录 功能 爬取的方式: 设置生成的md文件命名规则: 设置md文件的头部信息 是否显示csdn中的锚点"文章目录"字样,以及下面具体的锚点 默认false(因为csdn中是集 ...
- SQL Sever 博客文章目录(2016-07-06更新)
SQL Server方面的博客文章也陆陆续续的写了不少了,顺便也将这些知识点整理.归纳一下下.方便自己和他人查看. MS SQL 数据类型 三大数据库对比研究系列--数据类型 MS SQL 表和视图 ...
随机推荐
- 音频管理器(AudioManager)
MainActivity.java package com.wwj.serviceandboardcast; import android.app.Activity; import android ...
- vmware虚拟机centOs安装教程
1安装vmware 虚拟机软件 1.解压vmware安装 汉化vmware虚拟机 复制注册码,并填写进vmware 2安装linux(centos)虚拟机 1. 点击文件----->新建虚拟机 ...
- adb push init.rc /
http://blog.csdn.net/jumper511/article/details/28856249 修改Android init.rc文件后,需要将修改后的文件上传到手机,但是发下如下问题 ...
- javascript 获取用户当前 经纬度 位置
<!DOCTYPE html> <html> <body><p>http协议支持部分浏览器</p><p>https支持所有浏览器 ...
- 学以致用十六-----Centos7.2编译安装mysql5.6.22
一.系统环境 二.卸载系统自带的mariadb rpm -qa | grep db rpm -e --nodeps mariadb-libs-5.5.60 rpm -e --nodeps mariad ...
- 深入浅出javascript(二)函数和this对象
一.函数对象的属性和方法 函数是一种数据类型,也是对象,这一点很明确.因此,函数对象也可以添加属性和方法,但是这里的属性和方法是静态的,之所以这样说,就是为了区别构造函数. 示例如下: ①创建一个空的 ...
- DeepFace和GAN
由于换脸技术的影响,现在造假视频的成本越来越低.AI换脸视频也越来越热门,甚至有一些已经达到了以假乱真的程度.虽然有明星反对表示无奈,可是.... 据报道,2018年,arXiv上发布了902篇GAN ...
- android上的i-jetty (1)环境搭建
介绍下如果把android设备作为一个web服务器使用, 编译i-jetty 1. 将源码download下来,http://code.google.com/p/i-jetty/downloads/l ...
- G 最水的一道
G - Here Be Dragons The Triwizard Tournament's third task is to negotiate a corridor of many segment ...
- CentOS 7配置nginx-1.13.10支持http/2和Server Push
0.确保openssl版本大于1.0.2 openssl version 1.下载nginx-1.13.10 wget http://nginx.org/download/nginx-1.13.10. ...