6. ruby - ウェブスクレイピング - リンク切れをチェック 基本

 
6.1 概要
6.2 ソースを3分割2
6.3 リンク URI を抽出する
6.4 リンク先をチェックする
6.5 現時点での実行結果

6.1 概要

 第一段階の目標点が、前ページまでで取得したリンクをチェックして、リンク切れが発生していないかを調べるというものなのです。  「Ruby - サイト内リンク切れチェック!」にまんまみたいなものがありますが、参考にしながら。

6.2 ソースを3分割に

 とりあえず、ソースを3つに分けました。  まず、メイン。  コマンドライン引数を受け取って渡す部分。

#!/usr/bin/env ruby

require './checkparent'

tree = { ARGV[0] => 'UNKNOWN' }

parent = CheckParent.new()
parent.do(ARGV[0], tree)
 5行目の tree という連想配列は、まだできていませんが、ドメイン内のリンクであれば再帰的にたどって、リンク切れを探すようにしたいので。  再帰的にたどるなかで既にチェック済の URI かどうか判定するためにチェック済の URI をためる配列です。

6.3 リンク URI を抽出する

 この章の前の方で作成した部分をクラス化して、リンク URI を抽出するようにしました。

#!/usr/bin/env ruby

require './checkchild'					←	リンク先をチェックするクラス
require 'open-uri'
require 'nokogiri'

class CheckParent
  def initialize()
  end

  def do(uri, tree)
    begin

      tree.each { | key, value |		←	ここらでチェック済かどうかを判定している
        if (key == uri)
          if (value != 'UNKNOWN')
            return;						←	判定済であれば処理しない
          end
        end
      }

      uri = URI.encode(uri)				←	ここからリンク先を抽出
      uri = URI.parse(uri)
      html = open(uri).read

      html.sub!(/^<!DOCTYPE html(.*)$/, '<!DOCTYPE html>')

      doc  = Nokogiri::HTML(html)

      link = []

      doc.css('a').each do |anchor|
        link.push(anchor[:href])
      end

      doc.css('input').each do |anchor|
        if s = anchor[:onclick]
          s = s[/\'.*\'/]
          link.push(s.delete!("'"))
        end
      end

      doc.css('img').each do |anchor|
        link.push(anchor[:src])
      end

      link.sort!

      check = Check.new()				←	リンク先をチェック
      check.do(uri, link)

										←	この先でドメイン内のコンテンツであれば再帰的にリンクチェックしたい

    rescue => error
      puts "例外発生"
      puts "#{error.backtrace}"
      puts "[#{self.class.name}][#{error.message}]"
      exit 1
    end
  end
end

6.4 リンク先をチェックする

 前項からの呼び出し先、リンクをチェックする部分。  これが全然未完なのですが・・・。

#!/usr/bin/env ruby

require 'open-uri'
require 'nokogiri'

class Check
  def initialize()
  end

  def do(parent, child)

    res = 'OK'

    for item in child do
      case item[0]
      when '#'
#          puts "ページ内リンク   => #{item}"
        # ページ内リンクなので html 内に id=item が存在すること

      when 'h'
        # 外部リンクなので存在の有無のみ

        res = fetch(item)

        puts "外部    リンク   => #{item} 結果[#{res}]"

      else
        if item[-3, 3] == 'png'
#          puts "イメージファイル => #{item}"
          # イメージなので存在の有無のみ

        elsif item[-4, 4] == 'html' || item[-1, 1] == '/'
#          puts "内部    リンク   => #{item}"
          # 内部リンクなので可能であればたどりたい

        else
#          puts "                 => #{item}"
          # 上記以外なのでチェックしない

        end
      end
    end
  end

private
  def fetch(url)

    begin
      uri = URI.encode(url)
      uri = URI.parse(uri)

      open(uri)

    rescue OpenURI::HTTPError => error

      return 'NG'

    rescue => error
      puts "例外発生"
      puts "#{error.backtrace}"
      puts "[#{self.class.name}][#{error.message}]"
      exit 1
    end

    return 'OK'
  end
end

6.5 現時点での実行結果

 現時点で実行してみます。  わざと、リンク先がないものをいれています。

./ソースファイル名.rb http://freebsd.sing.ne.jp/windows/01/99.html
外部    リンク   => http://net-3.blogspot.jp/2013/03/blog-post_16.html 結果[OK]
外部    リンク   => http://net-3.blogspot.jp/2013/03/blog-post_99.html 結果[NG]