Tutorial (Chi tiết) Cách mình tiết kiệm 50% vốn đầu tư siêu lợi nhuận forest-berries

Bài viết dài nhưng chi tiết hay ngắn để khỏi phải đọc?

  • Dài ngoằng nhưng đọc xong hiểu (gần) hết

  • Ngắn 1 khúc rồi thắc mắc gì comment hỏi sau


Results are only viewable after voting.
C
Created
Status
Complete

cover-png.180705


Cách mà mình (và có thể nhiều người khác) đã tiết kiệm đến 50% vốn đầu tư mà vẫn lời như thường từ forest-berries. Cùng tìm hiểu làm sao, làm như thế nào và hơn nữa, làm sao để bạn có thể tự làm được như vậy mà không cần bỏ tiền thuê người nhé.
Last edited:

khanhne

Senior
Joined
Nov 18, 2019
Messages
494
Reactions
435
MR
36.846
Call me! Call me! Chat with me via Yahoo Messenger Follow me on Facebook
Nhận được MR từ @animax1991 (1)

cover.png

Câu chuyện


Forest-berries là một trang đầu tư của Nga. Bên cạnh những tính năng đầu tư bình thường, site này có một tính năng mới so với những site khác là Chợ đen. Trong đó, người chơi 5 slot với mức giá từ 15-90 xu. Người chơi có thể mua slot trống/slot của người khác và nâng mức giá của slot đó lên 25%. Người chơi có thể mua qua lại liên tục cho đến khi gặp:
  1. Cướp
    1628328834437.png
    : người chơi mất slot mà không nhận được thêm xu nào
  2. Thanh tra
    1628328781097.png
    : người chơi mất slot mà chỉ nhận được 75% giá trị
  3. Thợ săn
    1628328804531.png
    : người chơi bán được slot với giá lời 50%
Sau khi "trade" ở Chợ đen được một lúc, mình bắt đầu nhận ra việc mua vào liên tục cũng có thể tạo ra lợi nhuận. Sau vài tiếng trade mình đã từ số vốn 2k xu có được 10k xu để mua thú, đầu tư. Để nhận 10k xu đó, mình chỉ cần nạp vào 5k xu, nghĩa là mình đã tiết kiệm được 50% tiền túi chỉ bằng việc trade liên tục. Dù vậy, với vai trò một Coder, mình không thể đủ kiên nhẫn trade hoài vậy được :D vì vậy bài viết này ra đời.



Là sao???


Công việc trade khá đơn giản, người chơi chỉ cần click vào slot muốn mua, page sẽ tự mua và reload lại trạng thái mới. Ô nào không click được thì có nghĩa là không thể mua. Chúng ta sẽ auto những công việc nhàm chán này cùng nhau ngay sau đây chỉ trong "một nốt nhạc"
1628344193344.png

Bắt tay vào làm thôi! Bước đầu tiên mình sẽ kiểm tra xem khi người chơi click vào slot mua, chuyện gì sẽ xảy ra. Dùng F12 (Developer Tools), mình phát hiện ra mỗi slot là 1 button.

1628328984549.png
1628329050988.png


Gần đó có 1 <form> element, một <input><button> này lại có thuộc tính type="submit", bản năng mình nghĩ đến ngay việc có 1 HTTP request với method POST đến link hiện tại (/account/market) sẽ được gửi đi khi click vào nút này (để ý đoạn name="item" value="98411" nhé). Vì thế, mình tiếp tục kiểm chứng xem dự đoán đó liệu đúng hay không bằng cách sang tab Network của DevTools để bắt request xem sao.

1628329866703.png


Kết quả cho thấy bấm nút đó thật sự gửi request đến /account/market thật. Mình còn thấy rằng giá trị item ở đây trùng với giá trị của <input>. Vậy nên mình kết luận được ngay rằng việc click vào button đó gửi 1 request dạng POST đến /account/market với form data gồm có item: <giá trị ô input>. Vậy là xong phần điều tra!



Bắt tay vào code


Bước 1. Mua slot


Tóm tắt lại, để mua 1 slot, ta cần:
  1. Tìm ra giá trị item của <input> trong slot đó
  2. Gửi POST đến /account/market với form data là {item: <giá trị item>}
  3. Reload trang để xem kết quả
Để chạy đoạn code này, cách "cùi mía" nhất đó là viết code, paste vào DevTools (tab Console) rồi ấn Enter để chạy. Ta sẽ thử cách đó trước để chắc chắn code hoạt động trước khi đến tiếp theo. Để bài viết ngắn gọn hơn mình sẽ đưa code luôn.

JavaScript:
function buy_stuff() {
    let requested = 0
    for (let inp of document.querySelectorAll('.tdata3 [name=item]')) {  // Chọn các input có name là "item"
        const form = new FormData(document.forms[0])  // Tạo form data để submit
        form.set('item', inp.value)  // Đặt item thành giá trị của input

        // Submit form
        $.ajax({
            url: form.action,
            data: form,
            processData: false,
            contentType: false,
            type: 'POST',
            success: function(){}
        })
        requested += 1
    }
    document.querySelector('.blokkur5k').scrollIntoView()  // Scroll đến bảng slot để dễ nhìn
    setTimeout(() => window.location.reload(), requested * 1000)  // Reload trang để xem kết quả
}

Đoạn code trên sẽ tự mua tất cả slot (bao gồm slot đã sở hữu, phần này có thể tối ưu thêm nhưng với test thực tế thì không ảnh hưởng nên mình để vậy cho gọn), sau đó tự reload sau <số slot đã mua> * 1000 miligiây. Để chạy thử đoạn code, bạn paste vào DevTools và chạy lệnh buy_stuff()

1628343688087.png


Bạn sẽ thấy mọi slot sẽ được mua ngay (nếu không ai mua trước khi chạy code này :D). Thế là tốt! Chúng ta sẽ đến với bước tiếp theo!

Bước 2. Tự động hoá đoạn code mua slot


"Ơ, gọi hàm buy_stuff() là xong chứ còn gì mà tự động hoá nữa?" Nhưng thực chất có một số thứ cần rào trước để đảm bảo đoạn code của chúng ta được 100% tự động. Lí do là đôi lúc VPS kết nối đến site lỗi, VPS lag,... nên nhiều lúc sẽ có trục trặc dẫn đến code tự dừng lúc nào không hay. Vì thế ta sẽ thêm đoạn code sau vào trước đoạn gọi hàm buy_stuff()

JavaScript:
// Tự reload trong trường hợp code chính không reload được vì gặp lỗi (ưu tiên)
setTimeout(() => window.location.reload(), 10000)
// Reload bằng cách chuyển đến link hiện tại (dự phòng). Sở dĩ cách này
// chỉ là dự phòng vì làm thế liên tục sẽ làm browser lag hơn khi lịch sử
// sẽ tràn ngập /account/market, /account/market,...
setTimeout(() => window.location.replace(window.location.href), 15000)

Thế là xong bước 2! Đơn giản chưa!

Bước 3. Giải captcha


Sau một thôi một hồi chạy auto, 96,69% kiểu gì bạn cũng sẽ được gặp cô cảnh sát xinh đẹp này.

1628346926205.png


Quả captcha này có tiền cũng chưa chắc giải được như đám reCaptcha, captcha ảnh,... đâu :D khoai đấy. Nhưng đọc được đến đây thì các bạn gặp may rồi. Áp dụng kĩ thuật AI, học máy, kết hợp với Big Data và điện toán đám mây, mình đã tìm ra cách giải cho loại captcha này. Phân tích kĩ thì bạn sẽ thấy đoạn text đó là tiếng Nga và cần giải một phương trình toán học đơn giản (phép cộng). Ta sẽ điều tra thử xem dòng chữ đó nghĩa là gì.

1628346625623.png


Google dịch không cho ra kết quả gì khả quan mấy, có vẻ như dòng chữ này không hẳn là tiếng Nga (hoặc nó sai ngữ pháp). Mình dạo vòng quanh Google thì thấy có một trang list ra từ 0-100 bằng tiếng Nga. Tò mò bấm vào xem thì mình thấy có vẻ như chữ trong captcha hơi hơi giống một số chữ trong bảng số này. Hình sau là một bằng chứng.

1628347117437.png


Vậy ra là captcha là chữ Nga nhưng bị thay đổi, xoá đi, thêm thắt một vài kí tự. Kiểu captcha này dám cá bạn mới gặp lần đầu (nhưng nếu sai thì mình xin lỗi, được chưaaa!). Vậy việc giải captcha này cũng không quá khó, chỉ cần xem thử chữ nào giống với chữ trong captcha nhất, lấy ra giá trị số của nó, cộng 2 số vào là xong! Đó chính xác là những gì mình đã làm. Vậy ta đến với bước tiếp theo.

Bước 3.1. Chuyển dữ liệu trong website thành dạng dữ liệu dễ xử lí


Đến đây mình sẽ đổi sang Python để dễ dàng xử lí đống dữ liệu này hơn. Mình viết đoạn code này cho Python 3.9.6, nên nếu mọi người muốn test thì mình khuyên là cài bản 3.9.6 để test tránh gặp lỗi vì xung đột phiên bản nhé.

Python:
# Paste dữ liệu từ website
text = '''...'''
print("1. Đoạn dữ liệu gốc:\t\t", shorten(repr(text), 100))

# Tách giá trị thành kiểu <chữ>:<số>
numbers_text = dict([line.split(' – ')[::-1] for line in text.split('\n\n')])
numbers_text = {key: int(value) for key, value in numbers_text.items()}
print("2. Phân loại chữ theo giá trị:\t", shorten(repr(numbers_text), 100))

# Bỏ '«»'
numbers_text = {re.sub('«|»', '', key): value for key, value in numbers_text.items()}
print("3. Bỏ '«»':\t\t\t", shorten(repr(numbers_text), 100))

# Tách ' or ' ra
for key, value in list(numbers_text.items()):
    if ' or ' in key:
        for new_key in key.split(' or '):
            numbers_text[new_key] = value
        del numbers_text[key]
numbers_text = sorted_dict(numbers_text)
print("3. Tách ' or ':\t\t\t", shorten(repr(numbers_text), 100))

# Tách '/' ra
print("4. Tách '/':")
test_value = 21
for key, value in numbers_text.items():
    if value == test_value:
        print("\t4.1. Trước khi tách:\t", f"'{key}': {value}")
        break
for key, value in list(numbers_text.items()):
    if '/' in key:
        first, last = key.split()
        for last_i in last.split('/'):
            numbers_text[f"{first} {last_i}"] = value
        del numbers_text[key]
numbers_text = sorted_dict(numbers_text)
print("\t4.2. Sau khi tách:\t", end=' ')
for key, value in numbers_text.items():
    if value == test_value:
        print(f"'{key}': {value}", end=' ')
print()

# Xuất JSON
filename = 'data.json'
json.dump(numbers_text, open(filename, 'w+', encoding='utf-8'))
print(f"Đã xuất ra {filename}!")

(Hàm sorted_dict là hàm mình tự code ra, mục đích để sắp xếp Dictionary cho vào theo giá trị số. Các bước numbers_text = sorted_dict(numbers_text) chỉ dành cho mục đích dễ nhìn output hơn)

Code Python mà, ngắn gọn, súc tích, dễ hiểu thôi. Mình cũng cố gắng viết đơn giản, clean code nhất có thể để mọi người đọc hiểu được. Nếu có thắc mắc gì mọi người đừng ngại comment bên dưới mình sẽ giải đáp chi tiết hơn nhé. Đoạn code trên output ra như sau.

Code:
1. Đoạn dữ liệu gốc:               '0 – «нуль» or «ноль»\n\n1 – «один» or «одна» or «одно» or «одни»\n\n2 – «два» or «две»\n\n3 – [...]
2. Phân loại chữ theo giá trị:     {'«нуль» or «ноль»': 0, '«один» or «одна» or «одно» or «одни»': 1, '«два» or «две»': 2, [...]
3. Bỏ '«»':                        {'нуль or ноль': 0, 'один or одна or одно or одни': 1, 'два or две': 2, 'три': 3, 'четыре': 4, [...]
3. Tách ' or ':                    {'нуль': 0, 'ноль': 0, 'один': 1, 'одна': 1, 'одно': 1, 'одни': 1, 'два': 2, 'две': 2, 'три': [...]
4. Tách '/':
    4.1. Trước khi tách:           'двадцать один/одна/одно': 21
    4.2. Sau khi tách:             'двадцать один': 21 'двадцать одна': 21 'двадцать одно': 21
Đã xuất ra data.json!

Giải thích tường tận thì chúng ta có 4 bước chính như sau:
  1. Paste dữ liệu copy từ website thành dạng string
  2. Tách các dòng chữ ra bằng \n\n, sau đó tách từng dòng ra thành dạng <chữ>: <số> bằng đoạn string ' – '
  3. Bỏ 2 dấu «» ra khỏi mọi key bằng re.sub()
    Python:
    numbers_text = {re.sub('«|»', '', key): value for key, value in numbers_text.items()}
  4. Tách các key chứa ' or ' ra thành nhiều key riêng biệt
    Python:
    for new_key in key.split(' or '):
        numbers_text[new_key] = value
    del numbers_text[key]
  5. Xuất ra file JSON để lưu và thực hiện bước tiếp theo
Khá oằn tà là vằn, nhưng cuối cùng cũng xong! Chúng ta tiếp tục sử dụng dữ liệu này cho bước kế tiếp.

Bước 3.2. Viết thuật toán so sánh chuỗi​


Sau khi chúng ta có dạng dữ liệu <key>: <number> rồi thì bước tiếp theo sẽ là làm sao biết được chữ trong captcha giống với key nào nhất trong đống key kia. Mình đã thử nhiều cách đơn giản nhưng không thành công, vì vậy mạn phép lấy background Computer Science của mình ra múa vài đường :D ai có cách hay hơn, ngắn gọn hơn thì comment bên dưới cùng học hỏi nhé.

JavaScript:
function range(a, b=-1) {
    if (b == -1) {
        return [...Array(a)].map((_, index) => index)
    } else {
        return [...Array(b-a)].map((_, index) => index + a)
    }
}

function match_percent(input, source) {
    const dp = [
        [...Array(input.length)].map((_, index) => input[index] == source[0] ? 1 : 0)
    ]

    for (let source_ind of range(1, source.length)) {
        dp.push([...Array(input.length)].map(n => n || 0))
        if (input[0] == source[source_ind] || dp[source_ind-1][0] == 1) {
            dp[source_ind][0] = 1
        } else {
            dp[source_ind][0] = 0
        }
    }

    for (let source_ind of range(1, source.length)) {
        for (let input_ind of range(1, input.length)) {
            dp[source_ind][input_ind] = input[input_ind] == source[source_ind] ? 1 : 0
            dp[source_ind][input_ind] += Math.max(...dp[source_ind-1].slice(0, input_ind))
        }
    }

    return dp[source.length-1][input.length-1]
}

Hàm này sẽ so sánh chuỗi input với chuỗi gốc source để tìm ra số kí tự trùng nhau giữa 2 chuỗi. Để ngắn gọn thì đây là thuật toán Quy hoạch động, trong đó dùng mảng 2 chiều là dp[<input length>][<source length>], trong đó phần tử sau có giá trị bằng <số kí tự trùng nhau nhiều nhất trước đó> + <1 (nếu kí tự hiện tại của input trùng với kí tự hiện tại của source) hoặc 0>. Sau đó đi so sánh tất cả key với chuỗi từ captcha, ta sẽ có được giá trị số của nó.

JavaScript:
const data = {...}  // Dữ liệu JSON xuất ra ở bước 3.1.

function get_value(input) {
    let max_length = -1, match_number = -1, match_russian = ''

    for (let [russian, number] of Object.entries(data)) {
        let current_match_length = match_percent(input, russian)

        // Lưu lại <chữ tiếng Nga>, <số kí tự trùng nhau với input>
        // nếu <số kí tự trùng nhau với input> > <số kí tự trùng nhau tối đa hiện tại>
        if (current_match_length > max_length) {
            max_length = current_match_length
            match_number = number
            match_russian = russian
        }
    }
    // Hiển thị nhìn cho zui
    console.log({input, match_russian, match_number, max_length})
    return match_number
}

Test thử nha!

JavaScript:
>>> console.log(get_value("тридьать с~мь"))
{
  input: 'тридьать с~мь',
  match_russian: 'тридцать семь',
  match_number: 37,
  max_length: 11
}
>>> console.log(get_value("дуиадцать оыаин"))
{
  input: 'дуиадцать оыаин',
  match_russian: 'двадцать один',
  match_number: 21,
  max_length: 11
}

Kết quả đúng như mình mong đợi. Đoạn code tìm ra được rằng 2 chuỗi đó chính là 37 21, tương ứng với những gì mình đã show ở trên Google Dịch.

Bước 3.3. Viết code auto giải captcha​


Khi từng phần đã ổn với nhau, chúng ta sẽ lắp ráp chúng vào thành một đoạn code hoàn chỉnh. Đầu tiên chúng ta kiểm tra xem làm sao lấy ra được captcha text và làm sao submit được đáp án lên server bằng công cụ F12 thần thánh.

1628356204731.png


1628356342053.png
1628356357279.png



Từ thông tin đó, chúng ta xây dựng được selector để lấy ra element chứa đoạn captcha cần giải là .cl-right > div > center span span, còn form thì khá quen thuộc, ta cần lấy ra form element, điền đáp án captcha vào key n99 và submit đến /account/market là xong. Vậy thì ta bắt tay vào code đc rồi!

JavaScript:
function solve(text) {
    const [a, b] = text.split(' + ')
    return get_value(a) + get_value(b)
}

function has_captcha() {
    // Phát hiện captcha dựa trên hình ảnh cô cảnh sát xinh đẹp
    return document.querySelector('img[src*="polic.png"]') !== null
}

function solve_captcha() {
    // Lấy nội dung captcha
    const captcha_text = document.querySelector('.cl-right > div > center span span').textContent.split(' = ')[0]
    // Giải captcha
    const captcha_solution = solve(captcha_text)
    if (document.forms.length < 3) {
        // Nếu không có form thì có nghĩa là captcha đang bị khoá
        // và phải đợi để được giải captcha
        window.location.reload()
    } else {
        // Nhập dữ liệu đáp án captcha vào field n99 và submit (tự reload)
        document.forms[2].n99.value = captcha_solution
        document.forms[2].submit()
    }
}

Và gắn cùng với đoạn code mua slot để ra được file code hoàn chỉnh.

Bước 4. Code hoàn chỉnh​


Paste tất cả đoạn code Javascript trên vào lại với nhau và viết thêm 4 dòng nữa, ta đã có file code hoàn chỉnh.

JavaScript:
if (has_captcha()) {
    solve_captcha()
} else {
    buy_stuff()
}

Thế là xong phần code.



Cài đặt code và tận hưởng​


Để chạy đoạn code này mỗi khi page load, chúng ta sẽ sử dụng tiện ích mở rộng TamperMonkey (link tải: Chrome, Firefox). Chúng ta sẽ cần sửa code 1 chút để ăn khớp với TamperMonkey trong lúc đợi browser cài đặt.

JavaScript:
// ==UserScript==
// @name         Auto buy forest-berries
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  try to take over the world!
// @author       KhanhhNe
// @match        https://forest-berries.biz/account/market
// @icon         https://www.google.com/s2/favicons?domain=forest-berries.biz
// @grant        none
// ==/UserScript==

!function () {
    ... // Code nãy giờ
}()

Sau khi gói code vào trong đoạn !function() { ... }() đó thì tiếp tục thực hiện những bước sau
  1. Vào icon TamperMonkey ở thanh địa chỉ của browser, bấm Create a new script...
    1628358916291.png
  2. Paste đoạn code vừa chỉnh xong vào giao diện Editor và ấn Ctrl - S
    1628359068159.png
  3. Mở forest-berries, đăng nhập và vào /account/market (Chợ đen). Reload trang, đợi vài giây, nếu trang tự reload và tốt hơn nữa là có slot được mua auto có nghĩa là code đã hoạt động thành công!
  4. Rung đùi đợi tiền về đầu tư

Update 9/8/2021:

Giờ đây bạn có thể cài đặt code này từ OpenUserJS tại link: https://openuserjs.org/scripts/KhanhhNe/Auto_buy_forest-berries
Hướng dẫn chi tiết (hơn 1 xíu) tại comment: https://mmo4me.com/threads/chi-tiet-cach-minh-tiet-kiem-50-von-dau-tu-sieu-loi-nhuan-forest-berries.430251/post-7438464



Lời kết​


Vậy là xong! Qua bài viết dài hơi chữ là chữ, code dài ngoằng này hy vọng các bạn đã biết thêm điều gì đó bổ ích. Để viết ra bài viết này mình đã dành cả 1 ngày trời nghiên cứu, viết auto, nửa ngày viết giải captcha và nguyên 1 ngày viết topic, vì thế hy vọng các bạn thấy topic này hay :D

Đừng tiếc gì 1 like và/hoặc 1 comment để thương cho đôi tay mỏi nhừ của mình. Mình đã cố gắng nói rõ những phần quan trọng và lược đi một số thứ râu ria/cơ bản, nhưng nếu có vấn đề, thắc mắc gì các bạn cứ comment/inbox mình hỏi, mình sẽ trả lời nhiệt tình (khuyến khích comment để nhiều người cùng được đọc)

Tìm hiểu thêm​


Python: https://docs.python.org/3/
Javascript: https://www.w3schools.com/js/
Tampermonkey: https://www.tampermonkey.net/
Link source code full không che: https://github.com/KhanhhNe/CodeBanana-Tutorials/tree/main/forest-berries-market
Link OpenUserJS (tổng hợp code TamperMonkey): https://openuserjs.org/users/KhanhhNe

Ủng hộ mình và những bài viết chất lượng thế này: 1 like, 1 comment là đủ lắm rồi :D nhưng mà nếu bạn có lòng donate thì mình cũng xin nhận hehe
Cảm ơn mọi người vì đã đọc đến cuối bài viết dài ngoằng chữ là chữ này. Chúc mọi người một ngày tốt lành và thành công, kiếm được nhiều tiền để bài viết này và những bài viết sau của mình có nhiều donate hơn nhé :popo_smile:

1628362430587.png
 

Attachments

  • 1628329739307.png
    1628329739307.png
    119.3 KB · Views: 123
  • 1628353710275.png
    1628353710275.png
    24.8 KB · Views: 126
Last edited:

animax1991

Staff member
Super Moderator
MMO4ME United
Trusted Max
Joined
Aug 30, 2011
Messages
9,072
Solutions
6
Reactions
14,401
MR
1,287.098
$1,610.00
Call me! Call me! Chat with me via Yahoo Messenger Follow me on Facebook Chat with me via Skype
Nhờ bài viết của bạn mà đc mở rộng tầm mắt. Bạn dành 1 ngày để viết, nhưng chắc mình cần nhiều thời gian hơn con số 1 ngày để thẩm thấu những chia sẻ của bạn :popo_sweet_kiss:
 
Mình cũng sợ nhiều bạn đọc xong bài này sợ code luôn :D nên mọi người đọc xong có thể dành ra vài giây để vote ở đây

1628432343926.png


Và những bài viết sau mình sẽ rút kinh nghiệm nha. Chúc mọi người một ngày tốt lành!
 

Announcements

Today's birthdays

Forum statistics

Threads
424,889
Messages
7,152,219
Members
177,463
Latest member
tqk1102

Most discussed of week

Most discussed of week

Back
Top Bottom