Tôi đã cào dữ liệu 20 năm của ketqua.net bằng Google AppScript như thế nào.
google appscript
2
White

Anh NC viết ngày 27/05/2019

Nguồn gốc

Từ việc thiếu thốn dữ liệu của các nhà số học xung quanh mình. Buộc tôi phải tìm cách giúp họ. Nhưng với đôi tay trắng này, giúp sao đây. Tiền đâu mà mua server cắm bot cả ngày, máy mình cũng có trâu chó gì đâu :( mà cắm cả ngày cào dữ liệu cho nó. Rồi ngồi cào data thế này có ngày result.net block IP thì làm sao mà học toán được nữa.

Tiến hóa

Chợt nhớ đến Google AppScript có cái Url Fetch, phê rồi đây...IP Bot của Google, các anh mà block có khi cách anh lại bị biến mất khỏi Google Search :D

Screenshot from 2019-05-12 12-48-19.png

Ý tưởng

Tiến hành thôi, tạo một SpreadSheets ( tương đương Excel của M$) để lưu data, sau đó viết script cào dữ liệu result.net lên đó. Có 2 công việc phải làm, là phải cào dữ liệu từ trước đến thời điểm hiện tại và hiện tại (1.1.2000 đến nay, gần 20 năm :| )

Thực nghiệm

Khởi tạo

Tạo 2 sheet: Data, Config

Để map source bên script.google.com với file SpreadSheets, chọn Trình chỉnh sửa tập lệnh

Chuyển sang code script

Để bóc tách được dữ liệu html, tôi sử dụng một thư viện giống jquery (cheerio) để xử lý DOM cho ngon nghẻ.

ID thư viện : 1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0

alt text

Chỉ việc thêm id thư viện này vào Tài nguyên > Thư viện là dùng được.

Phương thức

Input :

  • Url: /xo-so-truyen-thong.php?ngay=dd-mm-yyyy
  • Date: date

Xây dựng các function format lại dữ liệu truyền vào.

Date.prototype.fTime = function() {
    // dd-mm-yyyy;
    return this.getDate() + "-" + (this.getMonth() + 1) + "-" + this.getYear();
}

Xây dựng func crawl: Fetch source về và bóc tách dữ liệu lấy 8 giải chính, sau đó lưu vào SpreadSheets,
có 2 options lưu dữ liệu, bao gồm:

  • Lưu các ngày trước ngày hiện tại với job cào ngược
  • Lưu các này hiện tại với job cào xuôi

Được phân định bằng biến isBack.

var $;

function getGS(pos) {
    var root = $("#result_tab_mb");
    return "'" + root.find("[id*=rs_" + pos + "_]").map(function(i, v) {
        return $(this).text();
    }).get().join(",");
}

function crawl(date, isBack) {
    var content = UrlFetchApp.fetch('http://ketqua.net/xo-so-truyen-thong.php?ngay=' + date.fTime());
    var html = content.getContentText();
    if (html) {

        $ = Cheerio.load(html);

        const root = $("#result_tab_mb");

        if (root) {

            var gs = {
                "g0": getGS(0),
                "g1": getGS(1),
                "g2": getGS(2),
                "g3": getGS(3),
                "g4": getGS(4),
                "g5": getGS(5),
                "g6": getGS(6),
                "g7": getGS(7)
            }

            // save
            var excel = SpreadsheetApp.getActive();
            var sheet = excel.getSheets()[0];

            var time = root.find("#result_date").text();
            var dayName = time.split("ngày")[0];
            var timeStr = time.split("ngày")[1];

            var rowContent = [(dayName || "--").toString().trim(), (timeStr || date.fTime()).toString().trim(), gs.g0.toString(), gs.g1, gs.g2, gs.g3, gs.g4, gs.g5, gs.g6, gs.g7];

            if (isBack) {
                sheet.appendRow(rowContent);
            } else {
                sheet.insertRowBefore(1).getRange("a1:j1").setValues([rowContent]); // chen len tren
            }

        }
    }
}

Tạo các job


function daily() {
    crawl(new Date(), false);
}

function jobCrawBack() {
    var excel = SpreadsheetApp.getActive();
    var sheet = excel.getSheets()[0];
    var sheetCf = excel.getSheets()[1];

    var rowEnd = sheet.getLastRow();

    // Lấy dữ liệu ngày của hàng cuối cùng
    var lastDate = sheet.getRange(rowEnd, 2).getValue();

    var now = new Date();

    // Tính ngày tiếp theo
    var _lastDate = new Date(lastDate);
    _lastDate.setDate(_lastDate.getDate() - 1);

    crawl(_lastDate, true);

    // Thống kê số ngày lấy được
    spaceDay = Math.floor((now.getTime() - _lastDate.getTime()) / 86400000);
    sheetCf.getRange("b1").setValue(spaceDay);
}

Triển khai

Chọn trigger menu (hình đồng hồ) alt text

Đặt thời gian thực hiện các function để công việc trở thành tự động.

  • Set time cho function daily là theo ngày ( đặt tầm 1 giờ sáng hàng ngày )
  • Set time cho function jobCrawBack là mỗi phút 1 lần (*), sau khi lấy đủ dữ liệu thì xóa bỏ job này.

alt text

alt text

Kết quả
Sau 0.7day bot đã cào xong dữ liệu của 20 năm, hiện tại nó vẫn lấy dữ liệu đều đặn hàng ngày.

Output:
https://docs.google.com/spreadsheets/d/1JmZy2XrE7qGeYjS_hrWFiFwph5QLQqDneYu3btnHihQ/edit?usp=sharing

(*) Với 1 phút thì 1 lần lấy thì max chậm, tiến hành đệ quy chính nó và đổi thời gian lên thành 5 phút, vì sau 5 phút nếu function vẫn chạy thì Trình kích hoạt sẽ tự động kill job này. Vả từ 1 record / 1 min nó đã tăng lên 39 record / 5 phút.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Anh NC

3 bài viết.
44 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
50 13
Hoài niệm Ngồi một góc nhỏ cafe, lại nhớ về một chút kỷ niệm gì của quá khứ. Một người bạn của quá khứ hay đôi khi là những tin nhắn sến sẩm với b...
Anh NC viết 4 tháng trước
50 13
White
9 0
insecam.org là website lưu trữ dữ liệu về các IPCam bị public (The world biggest directory of online surveillance security cameras.) Để bản đồ hóa...
Anh NC viết 4 tháng trước
9 0
Bài viết liên quan
White
9 0
insecam.org là website lưu trữ dữ liệu về các IPCam bị public (The world biggest directory of online surveillance security cameras.) Để bản đồ hóa...
Anh NC viết 4 tháng trước
9 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
3 bài viết.
44 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!