爬蟲方式(模擬使用者)

卓亦苇發表於2024-05-23

基於rake的爬取程式碼

require 'nokogiri'
require 'json'
require 'open-uri'
namespace :spider_sbi_code_info do
  task table_data: :environment do
    options = Selenium::WebDriver::Chrome::Options.new
    options.add_argument('--headless') # 無頭模式,不顯示瀏覽器介面
    driver = Selenium::WebDriver.for :chrome, options: options
    csv_filename_list = ["table_data_0_普通株式.csv", "table_data_1_米國ETF.csv", "table_data_2_各國ADR.csv"]
    begin
      # 初始化檔案
      csv_filename_list.each do |file|
        if File.exist?("db/csv/#{file}")
          File.delete("db/csv/#{file}")
          p "刪除已存在的檔案 #{file}"
        end
      end
      # 訪問目標網站
      url = 'https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_usequity_list.html'
      driver.get(url)
      dropdowns = driver.find_elements(css: '.form-control.input-sm')

      # 遍歷每個下拉選單並選擇選項為 "-1"
      dropdowns.each do |dropdown|
        if dropdown.tag_name == 'select'
          # 初始化 Select 物件
          select = Selenium::WebDriver::Support::Select.new(dropdown)

          # 透過 value 屬性選擇選項為 "-1"
          select.select_by(:value, '-1')
        end
      end

      # 等待頁面載入完全
      wait = Selenium::WebDriver::Wait.new(timeout: 10)
      wait.until { driver.execute_script('return document.readyState') == 'complete' }

      # 獲取頁面內容
      html_content = driver.page_source

      doc = Nokogiri::HTML(html_content)
      tables = doc.css('.foo_table, div.accTbl01 > table[summary="layout"]')

      if tables.any?
        # 提取表格資料並寫入 CSV 檔案
        tables.each_with_index do |table, index|
          # 提取表格資料
          table_data = table.css('tr').reject do |row|
            index > 2 && row.css('th, td').map(&:text) == ["ティッカー", "銘柄(英語)", "事業內容", "市場"]
          end.map { |row| row.css('th, td').map { |cell| cell.text.gsub("\n", '') } }

          # 確定 CSV 檔名
          csv_filename = if index > 2
                           "db/csv/#{csv_filename_list.last}"
                         else
                           "db/csv/#{csv_filename_list[index]}"
                         end

          # 寫入 CSV 檔案
          CSV.open(csv_filename, 'a') do |csv|
            table_data.each { |row| csv << row }
          end

          p "存入資料到 #{csv_filename}"
        end

      else
        p "沒有找到表格"
      end

      title = "SBI証券取扱銘柄リスト一覧の送付_#{Date.today.strftime('%Y/%m/%d')}"
      content = "関係者各位<br>お疲れ様です。<br>SBI証券のサイトより、取扱銘柄一覧をスクレイピングしましたので、<br>メールにて送付させて頂きました。<br>スクレイピング先のURL:<br>https://search.sbisec.co.jp/v2/popwin/info/stock/pop6040_usequity_list.html<br><br>ご確認をお願い致します。"
      attachments = csv_filename_list.map { |filename| File.join('db/csv', filename) }
      ExtMail.send_mail(title: title, body: content, template_name: 'system_mail', attachments: attachments, to: Yml::MAIL[:spider_sbi_stocks][Rails.env])

      csv_filename_list.each do |file|
        if File.exist?("db/csv/#{file}")
          File.delete("db/csv/#{file}")
          p "刪除已存在的檔案 #{file}"
        end
      end
    rescue Exception => e
      p "發生錯誤: #{e.message}"
    ensure
      driver.quit if driver
    end
  end
end
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument('--headless') # 無頭模式,不顯示瀏覽器介面
  driver = Selenium::WebDriver.for :chrome, options: options

配置並啟動 Selenium WebDriver:

  • Selenium::WebDriver::Chrome::Options.new 建立一個 Chrome 瀏覽器的選項例項。
  • options.add_argument('--headless') 新增一個選項,使瀏覽器以無頭模式執行(不顯示介面)。
  • Selenium::WebDriver.for :chrome, options: options 啟動 Chrome 瀏覽器並應用這些選項。
dropdowns = driver.find_elements(css: '.form-control.input-sm')

找到頁面上的所有下拉選單元素:

  • driver.find_elements(css: '.form-control.input-sm') 使用 CSS 選擇器找到頁面上所有具有 form-control input-sm 類的元素。
dropdowns.each do |dropdown|
        if dropdown.tag_name == 'select'
          select = Selenium::WebDriver::Support::Select.new(dropdown)
          select.select_by(:value, '-1')
        end
      end

遍歷每個找到的下拉選單,並選擇值為 -1 的選項:

  • dropdowns.each do |dropdown| 迭代每個下拉選單。
  • if dropdown.tag_name == 'select' 檢查元素是否是 select 標籤。
  • select = Selenium::WebDriver::Support::Select.new(dropdown) 建立一個新的 Select 物件。
  • select.select_by(:value, '-1') 透過 value 屬性選擇值為 -1 的選項。
wait = Selenium::WebDriver::Wait.new(timeout: 10)
wait.until { driver.execute_script('return document.readyState') == 'complete' }

等待頁面完全載入:

  • wait = Selenium::WebDriver::Wait.new(timeout: 10) 建立一個新的 Wait 物件,設定超時時間為 10 秒。
  • wait.until { driver.execute_script('return document.readyState') == 'complete' } 等待頁面的 readyState 變為 complete,表示頁面載入完成。
html_content = driver.page_source
doc = Nokogiri::HTML(html_content)

這段程式碼獲取頁面內容並使用 Nokogiri 解析:

  • html_content = driver.page_source 獲取當前頁面的 HTML 原始碼。
  • doc = Nokogiri::HTML(html_content) 使用 Nokogiri 解析 HTML 內容,建立一個文件物件。
tables = doc.css('.foo_table, div.accTbl01 > table[summary="layout"]')

這行程式碼使用 CSS 選擇器找到頁面上的特定表格:

  • tables = doc.css('.foo_table, div.accTbl01 > table[summary="layout"]') 找到具有特定 CSS 類和屬性的表格元素

相關文章