Phương thức Hook
Các phương thức này hoạt động theo nguyên lý hook. Việc triển khai các phương thức này cho phép kiểm soát hoạt động của công cụ cào dữ liệu ở các giai đoạn khác nhau, từ khởi tạo đến khi hủy đối tượng
Việc triển khai tất cả các phương thức ngoại trừ parse là tùy chọn
async parse(set, results)
Phương thức parse triển khai logic chính để xử lý truy vấn và nhận kết quả cào dữ liệu, các đối số được truyền vào bao gồm:
set- đối tượng chứa thông tin về truy vấn:set.query- chuỗi văn bản của truy vấnset.lvl- cấp độ truy vấn, mặc định là0
results- đối tượng chứa các kết quả cần được điền và trả về từ phương thứcparse()- công cụ cào dữ liệu phải kiểm tra sự tồn tại của mỗi khóa trong đối tượng results và chỉ điền vào khi có mặt, bằng cách này tốc độ được tối ưu hóa và chỉ những dữ liệu được sử dụng để tạo kết quả mới được cào
resultschứa các khóa của các biến flat cần thiết với giá trịnone, theo mặc định điều này có nghĩa là kết quả chưa nhận được, cũng như các khóa của các biến mảng (arrays) với giá trị là một mảng trống, sẵn sàng để điền dữ liệuresults.successphải được thiết lập thành giá trị1khi xử lý truy vấn thành công, mặc định giá trị là0, nghĩa là truy vấn được xử lý có lỗi
Hãy xem ví dụ:
class JS_HTML_Tags extends BaseParser {
static defaultConf = {
results: {
flat: [
['title', 'Title'],
],
arrays: {
h2: ['H2 Headers List', [
['header', 'Header'],
]],
}
},
...
};
async parse(set, results) {
// Lấy nội dung trang HTML có địa chỉ được truyền trong truy vấn
const {success, data, headers} = await this.request('GET', set.query);
// Kiểm tra tính thành công và kiểu của data, khi xử lý chính xác các trang HTML chúng ta sẽ nhận được kiểu 'string', nếu không A-Parser sẽ trả về đối tượng kiểu Buffer
if (success && typeof data == 'string') {
let matches;
// Kiểm tra sự cần thiết của việc thu thập title và lưu giá trị
if (results.title && matches = data.match(/<title[^>]*>(.*?)<\/title>/))
results.title = matches[1];
// Kiểm tra sự cần thiết của việc thu thập h2
if (results.h2) {
let count = 0;
const re = /<h2[^>]*>(.*?)<\/h2>/g;
while(matches = re.exec(data)) {
// Lưu tất cả các thẻ h2 tìm thấy trong vòng lặp
results.h2.push(matches[1]);
}
}
// Thông báo về việc cào dữ liệu thành công
results.success = 1;
}
// Trả về các kết quả đã xử lý
return results;
}
};
Lưu ý rằng bạn có thể tạo các hàm và phương thức riêng để tổ chức mã tốt hơn:
function Answer() {
return 42;
}
class JS_HTML_Tags extends BaseParser {
...
async parse(set, results) {
results = await this.doWork(set, results);
return results;
}
async doWork(set, results) {
results.answer = Answer();
return results;
}
};
async processConf?(conf)
Phương thức này được sử dụng để chuyển đổi cấu hình theo một số quy tắc nhất định, ví dụ khi sử dụng captcha chúng ta luôn cần sử dụng session:
async processConf(conf) {
if (conf.useCaptcha)
conf.useSessions = 1
}
async parse(set, results) {
if (conf.useSessions)
await this.login();
}
Sự tồn tại của phương thức này là do A-Parser hỗ trợ các trường cấu hình động và trong phạm vi một tác vụ, cấu hình có thể có các giá trị khác nhau, kịch bản này có thể xảy ra trong hai trường hợp:
- Sử dụng mẫu (template) trong các trường cấu hình, ví dụ
[% tools.ua.random() %]cho trường User-Agent - Sử dụng
overrideskhi gọi một công cụ cào dữ liệu từ một công cụ khác chothis.parser.request
Phương thức processConf được gọi một lần trước init(). Đối với các trường hợp mô tả ở trên, processConf được gọi bổ sung trước khi xử lý mỗi truy vấn
Các quy tắc chính khi áp dụng processConf:
- Chỉ sử dụng nếu việc chuyển đổi cấu hình có ảnh hưởng đến hiệu suất
- Hãy lưu ý rằng
initđược thực hiện một lần, cònprocessConfcó thể được thực hiện cho mỗi truy vấn, trong trường hợp này logic có thể bị phá vỡ nếuinitphụ thuộc vào các trường cấu hình thay đổi (xem bên dưới)
async init?()
Phương thức init được gọi một lần khi khởi tạo đối tượng cơ sở của công cụ cào dữ liệu, dùng để thực hiện các hành động một lần:
- Khởi chạy trình duyệt
- Khởi tạo trình quản lý session bằng phương thức
this.sessionManager.init() - Kết nối với cơ sở dữ liệu và tạo các bảng trong DB
- Đọc dữ liệu tĩnh
- V.v.
Vì phương thức được gọi một lần, tất cả các trường cấu hình mà init() phụ thuộc vào không thể được sử dụng cùng với các mẫu trường cấu hình hoặc với overrides khi gọi this.parsers.request
async destroy?()
Phương thức destroy được gọi một lần khi kết thúc tác vụ, cần thiết để hủy các tài nguyên đang mở một cách chính xác:
- Đóng trình duyệt
- Đóng kết nối tới DB
- V.v.
async threadInit?()
Phương thức này được chạy khi khởi tạo mỗi luồng, mỗi luồng là một bản sao của đối tượng cơ sở công cụ cào dữ liệu với this.threadId duy nhất của riêng nó, bắt đầu từ 0 và kết thúc tại threads_count - 1
Các trường hợp ứng dụng chính:
- tạo trang (tab) trình duyệt cho mỗi luồng
async threadDestroy?()
Được thực hiện khi kết thúc luồng trong quá trình kết thúc tác vụ, dùng để giải phóng các tài nguyên đã cấp phát cho luồng này
async afterResultsProcessor?(results)
Phương thức này được thực hiện sau khi xử lý kết quả: bằng trình tạo kết quả, lọc và khử trùng lặp. Trường hợp sử dụng chính là thêm truy vấn vào hàng đợi bằng phương thức this.query.add sau khi áp dụng các bộ lọc tùy chỉnh, do đó việc lọc các liên kết để chuyển tiếp (followlinks) cho công cụ cào dữ liệu
HTML::LinkExtractor được thực hiện theo cách này