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é.
<form>
element, một <input>
và <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./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!item
của <input>
trong slot đó/account/market
với form data là {item: <giá trị item>}
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ả
}
<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()
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()
// 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)
# 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}!")
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)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!
\n\n
, sau đó tách từng dòng ra thành dạng <chữ>: <số>
bằng đoạn string ' – '
«»
ra khỏi mọi key
bằng re.sub()
numbers_text = {re.sub('«|»', '', key): value for key, value in numbers_text.items()}
key
chứa ' or '
ra thành nhiều key
riêng biệtfor new_key in key.split(' or '):
numbers_text[new_key] = value
del numbers_text[key]
<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 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é.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]
}
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ó.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
}
>>> 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
}
.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!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()
}
}
if (has_captcha()) {
solve_captcha()
} else {
buy_stuff()
}
// ==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ờ
}()
!function() { ... }()
đó thì tiếp tục thực hiện những bước sauCreate a new script...
Ctrl - S
/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!k hiểu gì thì cũng có thể coi để biết coder phải khổ như thế nào/làm coder dễ như nàoKhông hiểu chi hết luôn
Không hiểu chi hết luôn
Cố mà hiểu bác à .Em cũng đang mò mà chưa hiểu nắm ha haKhông hiểu chi hết luôn
Thật ra là tiết kiệm được vài trăm nghìn thôi nhưng mà máu coder nên cứ code thành công là thích bác ạCũng ko hiểu chủ thớt làm gì, nhưng nếu nó giúp chủ thớt kiếm đc nhiều tiền thì chủ thớt quá giỏi.
Video khó quá nên qua viết cho dễ mà bạn :v nhưng mình sẽ để ý vụ này hơncó video hướng dẫn tốt, nhìn chữ mà muốn móc 2 con mắt. Dài thoòng loòng ra hic
Mình chỉ sợ bị đánh dấu quảng cáo :v link website đây: https://blogs.transparent.com/russian/russian-numbers-1-100/