Web Scraping with Capybara

Thông thường chúng ta muốn lấy dữ liệu từ một website, chúng ta thường dùng API mà website này cung cấp ví dụ như Twitter có Twitter API, Facebook cũng co Graph API của mình. Những API này thực tế là một đường dẫn URL mà khi request sẽ trả về những loại dữ liệu có thể xư lý (parse) được như JSON hoặc XML. Tuy nhiên, không phải website nào cũng cung cấp API cho người dùng lấy dữ liệu, như vậy thì làm thế nào.

Xử lý HTML thuần

Các Website thì đều hoạt động dựa trên giao thức HTTP, mà giao thức này chỉ đơn giản là gủi các request dưới dạng text từ server cho client. Những dữ liệu text này có format là HTML và ta hoàn toàn có thể xử lý chúng để lấy ra được dữ liệu mong muốn từ trang web.

Để xử lý một văn bản HTML thì trong ruby có một gem là nokogiri. Nokorigi giúp ta xử lý dễ dàng hơn với html. Nó có thể giúp query các thẻ html như là DOM trên trình duyệt vậy.

Thử nghiệm Nokorigi

Để dùng được nokorigi, đầu tiên ta cần cài gem này:

gem install nokogiri

Hoặc đưa nó vào Gemfile

#Gemfile

gem "nokogiri"

Bây giờ ta có thể trải nghiệm nó:

require 'nokogiri'
require 'net/http'

# get the HTML from the website
uri  = URI("http://www.google.com/?q='hello world'")
body = Net::HTTP.get(uri)

# parse it and use CSS selectors to find all links in list elements
document = Nokogiri::HTML(body)
links    = document.css("a")

# print each interesting looking link
links.each do |link|
  next if link.text.empty? || link['href'].empty?
  puts link.text, "  #{link['href']}", "\n"
end

Chương trình trên sẽ request đến google với query là hello world thông qua thư viện net/http của ruby. Sau khi lấy được HTML về thì nó sẽ được đưa vào Nokorigi::HTML để xử lý và trả về một object Nokorigi chứa cấu trúc của trang HTML. Từ đây, ta có thể tương tác với trang HTML thông qua Nokorigi object. Ở đoạn chương trình trên, ta dùng hàm css của Nokorigi object để lấy toàn bộ các link của trang web này.

Xử lý một Website có nhiều tính năng

Các bạn có thể thấy công việc khá là đơn giả đúng không. Ta chỉ cần kết nối đến trang web để lấy dữ liệu và dùng một thư viện nào đó có khả năng xử lý HTML để có thể tương tác được với trang web rồi từ đây có thể dễ dàng lấy dữ liệu từ trang web đó.

Tuy nhiên, trên thực tế lại hoàn toàn không phải đơn giản như vậy. Các website trên thực tế sẽ đòi hỏi chúng ta phải làm nhiều hơn như nhập dữ liệu vào form, xử lý các redirect request sau khi submit form. Ngoài ra, các website có thể đòi hỏi đăng nhập, kiểm tra cookies và các dữ liệu session. Nokorigi và các thư viện xử lý HTML khác chỉ đơn thuần làm nhiệm vụ là xử lý HTML chử không thể làm các nhiệm vụ khác được.

ruby có khá nhiều gem có thể hỗ trợ bạn xử lý những vấn đề trên. tiêu biểu nhất là gem mechanize. mechanize có thể giúp chúng ta điền dữ liệu vào form, lưu cookies và session data, submit và follow redirect sau khi submit form. tuy nhiên, mechanize thực tế cũng chỉ dung nokorigi để xử lý html rồi từ đó cung cấp một cơ chế để ta có thể tương tác với trang web một cách đơn giản nhất. và điểm hạn chế lớn nhất của nokorigi chính là nó không thể xử lý được javascript. các website hiện nay đa số đếu sử dụng javascript để thể hiện nội dung của minh thì nếu ta chỉ đơn thuần xử lý html thì sẽ không thể nào lấy được dữ liệu từ các site đó.

Capybara và Capybara webkit

để có thể thực sự tương tác với một trang web, ta phải cần một trình duyệt. capybara-webkit là một driver cho capybara để có thể tương tác với headless webkit (webkit là một web browser engine, headless có nghĩa là chạy không cần ui). như vậy, ta sẽ dùng webkit làm trình duyệt để xử lý các web page, còn capybara-webkit là driver để caapybara có thể tương tác với webkit.

vậy capybara đóng vai trò gì? capybara cung cấp một interface để tương tác với các trang web từ ruby. mục đích chính của capybara là để phục vụ việc viết test nhưng ta có thể lợi dụng các tính năng của nó để thực hiện việc lấy dữ liệu từ web. như vậy, có thể hiểu là ta sẽ dùng capybara để tương tác với trang web: click links, submit form... nhưng capybara sẽ dùng capybara-webkit để thực hiện các hành động này trên webkit.

Cài đặt

ta có thể cài đặt capybara và capybara-webkit thông qua:

  • gemfile
#gemfile

gem "capybara"
gem "capybara-webkit"
  • cài thông qua gem
gem install capybara
gem install capybara-webkit

tuy nhiên, capybara-webkit cần nhiều dependencies để có thể cài được. các bạn có thể lên trang readme và trang wiki của capybara-webkit để có thể biết thêm chi tiết.

sau khi cài đặt thì bạn có thể sẽ cần config cho capybara-webkit như sau:

capybara::webkit.configure do |config|
  # enable debug mode. prints a log of everything the driver is doing.
  config.debug = true

  # by default, requests to outside domains (anything besides localhost) will
  # result in a warning. several methods allow you to change this behavior.

  # silently return an empty 200 response for any requests to unknown urls.
  config.block_unknown_urls

  # allow pages to make requests to any url without issuing a warning.
  config.allow_unknown_urls

  # allow a specific domain without issuing a warning.
  config.allow_url("example.com")

  # allow a specific url and path without issuing a warning.
  config.allow_url("example.com/some/path")

  # wildcards are allowed in url expressions.
  config.allow_url("*.example.com")

  # silently return an empty 200 response for any requests to the given url.
  config.block_url("example.com")

  # timeout if requests take longer than 5 seconds
  config.timeout = 5

  # don't raise errors when ssl certificates can't be validated
  config.ignore_ssl_errors

  # don't load images
  config.skip_image_loading

  # use a proxy
  config.use_proxy(
    host: "example.com",
    port: 1234,
    user: "proxy",
    pass: "secret"
  )
end

nếu bạn dùng capybara-webkit với rails thì bạn có thể đặt config trên vào một file bất kì trong thư mục config/initializers

Thử nghiệm

require "capybara/dsl"
class crawlgoogle
  include capybara::dsl

  capybara.run_server = false
  capybara.current_driver = :webkit
  capybara.app_host = "https://google.com"

  def perform
    visit "/"
    fill_in "q", with: "hello world\n"
    puts body
  end
end

đây là một chương trình đơn giản sử dụng capybara để request đến google, nhập từ khóa hello world và ấn enter. với capybara, khi bạn điền \n vào ô input, nó sẽ được coi như là gõ phím enter. sau khi tương tác và thực hiên các request, bạn có thể lấy kết quả html của trang đã được xử lý thông qua hàm body và từ đây có thể dùng nokorigi đễ xử lý string html này và lấy ra kết quả mong muốn.

ngoài việc sử dụng webkit, các bạn hoàn toàn có thể sủ dụng một browser như chrome hay firefox để chạy (kết hợp với các driver cho chúng nữa). chưa kể đến còn có phantom.js và poltergeist là driver để sử dụng phantom.js nữa.

References

bài viết có một số tham khảo từ scraping with capybara