【Ruby】anemone과 nokogiri로 크롤러를 만들어 보았다.

시스템 개발에 있어서, 다른 WEB 페이지로부터 정보를 취득할 필요가 있었으므로, 크롤러를 작성했습니다.

처음 생각한 것



내가 시도한 것은 다른 웹 페이지에서 정보를 얻고 현재 작성중인 앱의 DB에 저장하는 것이 었습니다. 그렇다고 해서, 어쨌든 「정보를 취득」이라고 하는 것은 스크래핑인가! 라는 느낌으로 의욕하고 있었습니다···.

조사를 시작하고 알았던 것



자신이 하려고 했던 것은 확실히 스크래핑. 그러나 그 정보를 얻기 위해서는 먼저 크롤러라는 것을 만들어야 한다는 것이 밝혀졌다.

크롤러란?



한편 크롤러는 웹 페이지에 있는 모든 링크를 순회하여 심해지면서 원하는 정보를 얻는 방법입니다. 이 행위 자체는 크롤링이라고합니다.
크롤러에서 링크를 찾을 때는 물론 스크래핑을 하여 HTML 태그를 구문 분석하여 링크 대상을 가져옵니다.


스크래핑이란?



스크래핑은 웹 페이지의 HTML을 구문 분석하고 데이터를 추출하는 것입니다.



즉,
● 스크래핑은 한 페이지에 정보가 모여있는 경우 사용할 수 있습니다.
● 크롤러는 WEB 사이트내를 순회해 준다.

그래서 クローラーを作成し→その中にスクレイピングに関するコードを記述する→DBに保存する記述を書く라는 흐름이 보였습니다.

완성된 소스 코드


# ruby gemを使用 nokogiri anemoneを使えるようにした
require 'nokogiri'
require 'anemone'
require 'pry'
# 巡回起点となるURL
URL = 'https://********/********'.freeze

area_urls = []
prefecture_urls = []
city_urls = []
# サイト内を巡回する記述
Anemone.crawl(URL, depth_limit: 0, delay: 1) do |anemone|
  anemone.focus_crawl do |page|
    page.links.keep_if do |link|
      link.to_s.match(%r{*********/[0-9]{1,2}})
    end
    page.links.each do |link|
      area_urls << link
    end
  end
end

area_urls.each do |area|
  Anemone.crawl(area, depth_limit: 0, delay: 1) do |anemone|
    anemone.focus_crawl do |page|
      page.links.keep_if do |link|
        link.to_s.match(%r{**********/[0-9]{1,2}/[0-9]{5}})
      end
      page.links.each do |link|
        prefecture_urls << link
      end
    end
  end
end

prefecture_urls.each do |prefecture|
  Anemone.crawl(prefecture, depth_limit: 1, delay: 1, skip_query_strings: true) do |anemone|
    anemone.focus_crawl do |page|
      page.links.keep_if do |link|
        link.to_s.match(%r{**********/[0-9]{1,2}/[0-9]{5}/[0-9]})
      end
      page.links.each do |link|
        city_urls << link
      end
    end

    PATTERN = %r[**********/[0-9]{1,2}/[0-9]{5}/[0-9]].freeze

    anemone.on_pages_like(PATTERN) do |page|
      url = page.url.to_s

      str = url.to_s

      html = URI.parse(url).open
      # ここからスクレイピングの記述
      doc = Nokogiri::HTML.parse(html, nil, 'UTF-8')
# XpathでHTMLを指定
      name = doc.xpath('/html/body/div[4]/div/div[2]/div[1]/h1').text
      pos = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[3]/td/text()[1]').text
      post = pos.strip
      postcode = post.match(/[0-9]{7}/)
      add = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[3]/td/text()[2]').text
      address = add.strip
      tel = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[4]/td').text
      fax = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[5]/td').text
      staff_number = doc.xpath('/html/body/div[4]/div/div[2]/table[4]/tbody/tr[1]/td/p').text
      company = doc.xpath('/html/body/div[4]/div/div[2]/table[5]/tbody/tr[2]/td').text
      office_url = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[6]/td/a').text
      # 正規表現でURLから5桁の数字を抜き出す
      if str =~ %r{/(\d{5})(/|$)}
        city_number = Regexp.last_match(1)
        p Regexp.last_match(1)
      end
# インスタンスを作成し、スクレイピングで取得した情報をDBに保存、その際にバリデーションを無視する。
      offices = Office.new(name: name,
                           postcode: postcode,
                           tel: tel,
                           fax: fax,
                           address: address,
                           staff_number: staff_number,
                           company: company,
                           url: office_url,
                           city_number: city_number)
      offices.save(validate: false)
    end
  end
end


좋은 웹페이지 즐겨찾기