Web Scraping trong Ruby với Watir
Bài đăng này đã không được cập nhật trong 7 năm
Watir là một thư viện mã nguồn mở sử dụng cho việc automating test
. Watir
tương tác với trình duyệt giống như cách con người làm: nhấp vào liên kết, điền vào các biểu mẫu và xác nhận văn bản. Nhưng không chỉ vậy, tôi sẽ xây dựng một web scraper
mô phỏng việc vào một trang để đăng nhập, comment, tải dữ liệu và nhiều thứ khác.
Chức năng chính của Watir
là nó sử dụng Selenium web-driver
, có nghĩa là chúng ta có thể tạo một trang web động với JavaScript
. Một gem tương tự là Mechanize
- phù hợp cho các trang tĩnh và không sử dụng nhiều JavaScript
hoặc AJAX
.
Modes
Có thể chạy Watir
trong trình duyệt bình thường (Chrome/Firefox) hoặc headless
.
Chế độ headless
cho phép phân tích một trang không có giao diện - trong hầu hết các hệ thống UNIX
, Watir
yêu cầu cài đặt sẵn Xvfb
(trên Ubuntu). Watir
sử dụng PhantomJS
để mô phỏng trình duyệt web và chạy một trang trong trình mô phỏng. Nếu muốn phân tích trang bằng Chrome
, cần cài đặt chrome-driver
. Ngoài ra, Watir
còn cho phép chạy một trang như iPhone, iPad hoặc các thiết bị di động khác.
Tôi sẽ xây dựng một gem đơn giản, cho phép đăng ký, đăng nhập, mời bạn bè hoặc like trang trên Facebook.
Source code
Nào cùng bắt đầu.
def initialize(email, password)
@email = email
@password = password
end
Đơn giản là chỉ định email và mật khẩu.
def browser
@_browser ||= Watir::Browser.new(:chrome)
end
Chỉ định trình duyệt chạy là Chrome. Nếu bỏ qua phantomjs
ở đây, nó sẽ chạy chế độ headless
.
def login
return true if @logged_in
browser.goto('https://www.facebook.com/')
form = browser.form(id: 'login_form')
return false unless form.exist?
form.text_field(name: 'email').set(email)
form.text_field(name: 'pass').set(password)
form.input(value: 'Log In').click
sleep(2)
@logged_in = main_page?
end
Phương thức đăng nhập vào Facebook với các thông tin cần thiết.
- Sử dụng
goto
để redirect từ trang hiện tại sang trang chủ Facebook. form
- tìm kiếm form đăng nhập của Facebook vớiid: login_form
.
Chú ý ở đây, nếu tìm một phần tử không tồn tại thì script trên sẽ đợi (mặc định 30s
) sau đó sẽ trả về false
. Nên tốt nhất là bạn kiểm tra xem phần tử đó có thực sự có trên trang web đích không.
text_field
tìm field input và dùng phương thức set truyền params vào field.- dễ thấy phương thức
click
dùng để nhấp chuột vào một phần tử.
Tại sao phải chạy phương thức sleep
trong 2s
? - là để chờ cho tất cả asset
và javascript
được tải xong.
def main_page?
browser.element(id: 'userNavigationLabel').exist?
end
Phương thức main_page?
kiểm tra nếu thanh điều hướng tồn tại nghĩa là đã đăng nhập thành công.
def registration_params_valid?(params)
return false unless params.keys.uniq.sort == REGISTRATION_INPUTS.uniq.sort
return false if params.values.map(&:blank?).include?(true)
return false if EMAIL_REGEX.match(params[:email]).nil?
true
end
registration_params_valid?
kiểm tra tất cả các trường đăng ký đều đã được điền và hợp lệ.
def create_account(**args)
raise unless registration_params_valid?(args)
browser.goto('https://www.facebook.com/')
form = browser.form(id: 'reg')
form.text_field(name: 'firstname').set(args[:first_name])
form.text_field(name: 'lastname').set(args[:last_name])
form.text_field(name: 'reg_email__').set(email)
form.text_field(name: 'reg_email_confirmation__').set(email)
form.text_field(name: 'reg_passwd__').set(password)
form.select_list(name: 'birthday_day').select(args[:day])
form.select_list(name: 'birthday_month').select(args[:month])
form.select_list(name: 'birthday_year').select(args[:year])
form.radio(name: 'sex', value: sex(args[:sex])).set
form.button(name: 'websubmit').click
end
Phương thức create_account
dùng để đăng ký trên Facebook. Check registration_params_valid?
trước khi đến main page Facebook và tiến hành đăng ký.
def sex(value)
value.downcase.strip == 'male' ? '2' : '1'
end
Phương thức này nhận vào tham số và trả ra giá trị hợp lệ.
def search(query)
login unless logged_in
form = browser.form(action: '/search/web/direct_search.php')
form.inputs.last.to_subtype.clear
sleep(0.5)
form.inputs.last.to_subtype.set(query)
form.button(type: 'submit').click
end
Phương thức này tìm đến field input tìm kiếm của trang sau khi kiểm tra đã được đăng nhập. Nếu không, thực hiện đăng nhập trước. Đôi khi watir
đã click
quá nhanh và không phải các phần tử đều đã được nhập, sử dụng sleep
để chờ.
def perform(query, options = {})
login unless logged_in
search(query)
browser.link(href: "/search/#{options[:name]}/?q=#{query}&ref=top_filter").click
button = browser.button(class_name: options[:class_name])
button.click if button.exist?
end
Phương thức này dùng để mời một người bạn, like page, vv... Cần truyền một truy vấn, class của nút cần click và tên tab. Nhớ rằng, nút đầu tiên tìm thấy sẽ được click.
def like_page(name)
perform(name, name: 'pages', class_name: 'PageLikeButton')
end
def invite_friend(name)
perform(name, name: 'people', class_name: 'FriendRequestAdd')
end
Để sử dụng phương thức perform
, chỉ cần truyền truy vấn và click vào nút bên phải rồi chuyển sang đúng tab.
Testing
Các phương thức cơ bản đã đầy đủ. Bạn có thể download tại đây.
Chỉ cần clone
, chạy bundle install
và thưởng thức:
$ bundle console
$ scraper = NopioScraper::Facebook.new(‘your_email’',’your password’)
$ scraper.like_page('nopio')
Tất nhiên, ví dụ này thực sự đơn giản. Chẳng may trình duyệt bật popup
hay cảnh báo thì bạn phải sửa lại code của tôi . Mỗi trình duyệt hoạt động một cách khác nhau và thật khó để dự đoán được mong muốn của bạn.
Như đã thấy, web scraping
và simulating
là không giới hạn. Bạn có thể viết một mã mà có thể làm hầu như tất cả mọi thứ.
Tìm hiểu thêm tại đây:
Happy web scraping!
All rights reserved