Hướng dẫn - Thu thập dữ liệu tự động sử dụng NodeJS và Selenium | VN-Zoom | Cộng đồng Chia Sẻ Kiến Thức Công Nghệ và Phần Mềm Máy Tính

Hướng dẫn Thu thập dữ liệu tự động sử dụng NodeJS và Selenium

Huỳnh Phúc Huy

Búa Đá Đôi
Trong bài viết này mình sẽ hướng dẫn các bạn thu thập dữ liệu của một website bất kỳ. Với việc tự động hóa các tác vụ như tự động điều hướng, tự động điền vào input hay click các button ... chúng ta sẽ thu thập được khối lượng dữ liệu khổng lồ cho các mục đích khác nhau. Các bạn chỉ cần treo máy rồi đi ra ngoài làm cốc cafe, quay trở vào là sẽ có hàng ngàn records được lưu trữ trong nháy mắt.

Trước khi bắt đầu, các bạn cần chuẩn bị các công cụ, thư viện hay bản cài đặt của các ngôn ngữ lập trình & CSDL sau:
- ChromeDriver (https://sites.google.com/a/chromium.org/chromedriver/)
- NodeJS (https://nodejs.org/en/download/)
- MongoDB (https://www.mongodb.com/download-center)
- RoboMongo (https://robomongo.org/download)

Cài đặt NodeJS

Các bạn tải và cài đặt phiển bản NodeJS mới nhất, trong bản cài đặt sẽ có sẵn Node package Manager (NPM) là một công cụ quản lý, cài đặt các package cần thiết cho NodeJS

node-js-development-brillmindz.jpg

Cài đặt Selenium, MongoDB package và một số package khác

Các bạn tạo một thư mục chứa project, mở command promt và gọi npm để install các package sau:
  • npm install selenium-webdriver
  • npm install mongodb
  • npm install colors

Sau đó copy ChromeDriver vừa tải về vào thư mục mới tạo là bạn đã hoàn tất các bước chuẩn bị ban đầu, giờ chúng ta bắt tay vào code thôi {brick}

Mã nguồn và ví dụ mẫu

Site mà mình dùng để demo thu thập dữ liệu là site: https://tamsudev.com. mình sẽ tiến hành thu thập danh sách tất cả công ty CNTT trên site này.

>> Require các Package cần thiết
Mã:
var webdriver = require('selenium-webdriver'),
    chrome = require('selenium-webdriver/chrome'),
    By = webdriver.By,
    until = webdriver.until;
var MongoClient = require('mongodb').MongoClient;
var ObjectId = require('mongodb').ObjectID;
var mongoUrl = 'mongodb://localhost:27017/tamsudev';
var colors = require('colors/safe');


>> Thiết lập các options cần thiết để chạy Chrome cho nuột {biggrin}
Mã:
var options = new chrome.Options();
         
options.setUserPreferences({
    'profile.default_content_setting_values.notifications' : 2,
    'profile.managed_default_content_settings.images' : 2,
    'profile.managed_default_content_settings.media_stream' : 2,
    'profile.managed_default_content_settings.popups' : 2,
});

options.addArguments('--headless');

var capabilities = options.toCapabilities();


>> Khởi tạo driver, redirect tới trang và thực hiện các tác vụ tự động với các DOM element trên trang (các thao tác của Selenium với DOM element hoàn toàn tương tự với javascript)
Mã:
var driver = new webdriver.Builder()
    .withCapabilities(capabilities)
    .forBrowser('chrome')
    .build();
var counter = 0;

driver.get('https://tamsudev.com');
crawlCompanies();

function crawlCompanies() {
    console.log(colors.red('>>> Callback...'));
    driver.findElements(webdriver.By.className('detail')).then(function(details) {
        details.forEach(function(detail) {
            detail.findElement(webdriver.By.tagName('h4')).then(function(h4) {
                h4.getAttribute("innerText").then(function(name) {
                    h4.findElement(webdriver.By.tagName('a')).then(function(a){
                        a.getAttribute("href").then(function(url) {
                            var slug = url.replace('https://tamsudev.com/','');
                            counter++;
                            console.log(counter + '.' + colors.green(name + " (" + slug + ")"));
                            driver.executeScript('arguments[0].parentElement.innerHTML="";', detail);
                            MongoClient.connect(mongoUrl, function (err, db) {
                                var collection = db.collection('company');
                                collection.findOne({'slug':slug}).then(function(doc) {
                                    if(!doc) {
                                        collection.insertOne({
                                            name: name,
                                            slug: slug
                                        });
                                    }
                                });                          
                            });
                        });
                    });          
                });
            });
        });
        driver.executeScript("document.getElementById('loadMoreBtn').click()").then(function() {
            crawlCompanies();
        });
    }, function (err) {
        driver.executeScript("document.getElementById('loadMoreBtn').click()").then(function() {
            crawlCompanies();
        });
    });
}

>> Đóng driver sau khi sử dụng
Mã:
console.log(colors.red('>>> Finished...'));
driver.quit();

Các bạn tạo một file trong folder đã tạo ở trên lưu với tên tamsudev.js và copy tất cả các code bên trên để test thử (mở cmd tại đường dẫn thư mục và gõ lệnh: node tamsudev.js

>> Kết quả

Kết quả sau khi chạy thử ví dụ mẫu trên :

1Uuj0XP.png

Log xuất ra ở màn hình console

Lwsykp9.png

Data được lưu trong CSDL MongoDB
Nhắn nhủ

Ngoài khả năng thu thập dữ liệu một cách nhanh chóng thì thư viện Selenium này còn có thể giúp các bạn thực hiện các tác vụ khác như tự động nhập liệu, đăng nhập đăng xuất, tự động đăng bài ... và rất tiện lợi cho các bạn tester sử dụng cho automation testing

Cảm ơn các bạn đã đọc hết bài viết này, nếu các bạn có thắc mắc gì thì hãy để lại bình luận bên dưới bài viết, mình sẽ cố gắng trả lời các bạn trong thời gian sớm nhất {sexy_girl}
 
Sửa lần cuối:

rikyulin

Gà con
Cảm ơn bác. Selenium dùng dòng lệnh hay có giao diện cụ thể ko bác? Mình đang dùng Python với Scrapy cũng khá tốt nhưng k chuyên về code nên hơi mệt.
 

xxxiiimmm

Gà con
Bài viết rất hay.

Và ngoài Selenium thì còn có Puppeteer thằng này tuy không bằng Selenium, nhưng mình cảm thấy phục vụ cho việc crawle dữ liệu thì Puppeteer đã quá đủ, dễ sử dụng nữa.

Link thư viện Puppeteer: https://github.com/GoogleChrome/puppeteer

Bên trên là ý kiến cá nhân của mình, mọi người dùng cho phản hổi thế nào nhé.
 

tiengdonhoarira

Búa Gỗ
Mã:
var mongoUrl = 'mongodb://localhost:27019';
var dbName = 'tamsudev';

JavaScript:
async function crawlCompanies() {
    console.log(colors.red('>>> Callback...'));
    driver.findElements(webdriver.By.className('detail')).then(function(details) {
        details.forEach(function(detail) {
            detail.findElement(webdriver.By.tagName('h4')).then(function(h4) {
                h4.getAttribute("innerText").then(function(name) {
                    h4.findElement(webdriver.By.tagName('a')).then(function(a){
                        a.getAttribute("href").then(function(url) {
                            var slug = url.replace('https://tamsudev.com/','');
                            counter++;
                            console.log(counter + '.' + colors.green(name + " (" + slug + ")"));
                            driver.executeScript('arguments[0].parentElement.innerHTML="";', detail);
                            MongoClient.connect(mongoUrl, { useUnifiedTopology: true }, async function (err, client) {
                                if (err){throw err}
                                var db = client.db(dbName);
                                var collection = db.collection('company');
                                var doc = await collection.findOne({'slug':slug});
                                if(!doc) {
                                    collection.insertOne({
                                                            name: name,
                                                            slug: slug
                                    });
                                }
                                client.close();
                            });
                        });
                    });
                });
            });
        });
        driver.executeScript("document.getElementById('loadMoreBtn').click()").then(function() {
           crawlCompanies();
        });
    }, function (err) {
        driver.executeScript("document.getElementById('loadMoreBtn').click()").then(function() {
           crawlCompanies();
        });
    });
}

cái function mình chỉnh thành như trên mới hoạt động

mongodb v3.5.6
node v10.15.2
 
Top