Những Ưu và Nhược Điểm của vòng lặp (loop) với n8n

Bài đăng này sẽ đề cập đến ba cách tiếp cận khả thi để tạo vòng lặp (loop) trong n8n bằng cách xây dựng một workflow web scraping có hỗ trợ phân trang. Với ba ví dụ này trong tay, bạn sẽ hiểu rõ hơn cách vòng lặp có thể được sử dụng để tận dụng lợi thế khi giải quyết các vấn đề lặp đi lặp lại trong n8n.
Chúng tôi cũng sẽ đề cập một chút về nội bộ của n8n mà có thể hữu ích trong bất kỳ workflow n8n nào, có vòng lặp hay không.
Nếu bạn là nhà phát triển và đã nắm vững về vòng lặp, hy vọng đoạn văn này sẽ giúp bạn liên kết kiến thức lập trình hiện có của mình với các khái niệm trong n8n.
Vòng lặp là gì, khi nào và cách sử dụng?
Trước khi bạn bắt chuyện với chatbot AI yêu thích của mình với cùng câu hỏi đó, hãy làm rõ ở đây chúng ta xem vòng lặp trong ngữ cảnh workflow n8n là gì và một số trường hợp sử dụng để có thể tận dụng được cơ chế này.
Vòng lặp trong n8n là cách tạo workflow để dòng dữ liệu (được thể hiện qua các dòng kết nối trong n8n) đi qua một hoặc nhiều node nhiều lần. Mỗi lần thực thi vòng lặp được gọi là lần lặp hoặc một bước, vì vậy chúng ta sẽ sử dụng hai thuật ngữ này thay thế cho nhau trong suốt bài viết này.
Trong hành trình trở thành một anh hùng n8n của bạn, rất dễ dàng để nghĩ rằng các workflow như các luồng dữ liệu theo một chiều, chuyển dữ liệu đầu vào của chúng ta, xử lý và xuất ra kết quả. Nhưng hãy tưởng tượng một tình huống khi chúng ta cần sử dụng một tập hợp các node để thực hiện một nhiệm vụ nhất định nhiều lần. Nếu chỉ có vài node cần chạy vài lần, phản ứng đầu tiên của chúng ta có thể là sao chép chúng sau set ban đầu và xong. Tuy nhiên, sao chép và dán cùng 15 node hàng chục lần có thể không phải là cách hiệu quả nhất để xây dựng workflow (chưa kể trường hợp bạn không thể biết số lần lặp trước).
Đó là lý do tại sao vòng lặp ra đời.
Tạo vòng lặp trong workflow cho phép chúng ta tái sử dụng một bộ các node nhiều lần với dữ liệu đầu vào khác nhau mỗi lần thực thi. Trước khi đi vào lý thuyết, nếu bạn vẫn chưa có hình dung rõ ràng trong đầu, đây là cách một vòng lặp đơn giản (một node) trông như thế nào trong workflow n8n:
Dưới đây là một số ví dụ về các workflow mà vòng lặp là công cụ phù hợp nhất cho nhiệm vụ được giao:

- Web scraping các trang web sử dụng phân trang để hiển thị tất cả các mục,
- Thực hiện một quá trình có tối đa số lần thử lại (như đăng nhập người dùng hoặc kiểm tra xem một API server có trực tuyến không),
- Tạo mẫu hoặc chuỗi (ví dụ, gửi tin nhắn Slack tùy chỉnh cho từng người dùng trong Google Sheet),
- Tìm kiếm một phần tử cụ thể (như email có chủ đề đặc biệt) trong danh sách (hộp thư đến).
Như đã đề cập trong phần giới thiệu, chúng tôi sẽ giải quyết vấn đề scraping một trang web có phân trang trong bài này, nhưng trước khi bắt đầu thử nghiệm, hãy cùng xem cấu trúc của một vòng lặp:

Bức ảnh phía trên cho thấy những bước quan trọng nhất trong mỗi vòng lặp, nhưng như sẽ được trình bày trong việc thực hiện scraping, thứ tự và hiệu suất của từng bước đó có thể khác nhau dựa trên từng trường hợp sử dụng.
Dù sao đi nữa, đây là các thành phần chính của một vòng lặp:
- Dữ liệu đầu vào: Chúng ta có thể xem mỗi vòng lặp như một quy trình nhỏ riêng biệt với các đầu vào và đầu ra. Điểm khác biệt chính ở đây là vòng lặp thường cung cấp lại thông tin đã chỉnh sửa về đầu của vòng lặp, khiến mỗi lần lặp làm việc với dữ liệu khác nhau. Phần cuối cùng này chính là nơi xảy ra điều kỳ diệu của vòng lặp vì việc duyệt qua cùng một tập các nút với cùng một đầu vào mỗi lần hiếm khi hữu ích.
- Logic của vòng lặp: Đây là tập hợp các nút thực hiện các nhiệm vụ trong từng lần lặp.
- Điều kiện vòng lặp: Khi tạo một luồng lặp, chúng ta phải quyết định quy tắc nào sẽ xác định xem vòng lặp của chúng ta bắt đầu một bước mới hay dừng lại và tiếp tục với phần còn lại của quy trình làm việc. Chúng ta phải kiểm tra những điều kiện này trong mỗi lần lặp để tránh vòng lặp vô tận, khiến quy trình của chúng ta chạy mãi và có khả năng gây sập instance n8n của chúng ta.
Miêu tả công việc: xây dựng quy trình web scraping có hỗ trợ phân trang
Quy trình web scraping của chúng ta sẽ sử dụng một trang ví dụ từ www.webscraper.io như một sân chơi an toàn để trình diễn.
Bằng cách nhìn vào trang đầu tiên của cửa hàng trực tuyến này, chúng ta có thể thấy rằng nó chỉ hiển thị một phần của tất cả các sản phẩm, vì vậy để lấy tất cả chúng, quy trình của chúng ta cần phải scrape dữ liệu từ từng trang, từng cái một. Vì tất cả các trang có cấu trúc giống nhau, chúng ta có thể sử dụng cùng một tập các nút n8n để trích xuất dữ liệu và tạo ra một vòng lặp chạy bộ set đó cho từng trang sản phẩm.
Hiện tại, chỉ có hai trang trong cửa hàng, nhưng vì chúng ta không thể dựa vào điều đó luôn đúng (sản phẩm luôn lên xuống trong các webshops liên tục), quy trình của chúng ta cũng cần phát hiện xem còn trang nào nữa để scrape trước khi bắt đầu một vòng lặp mới. Chúng ta sẽ thảo luận chi tiết hơn về từng vấn đề đó khi xây dựng quy trình của mình và chuyển sang làm việc với n8n.
Nếu bạn muốn phát triển trải nghiệm này và bắt đầu scraping dữ liệu từ một trang web thực tế, hãy đảm bảo rằng các tác giả trang web đó cho phép việc scraping và đọc bài viết về các phương pháp scraping tốt nhất trên blog của chúng tôi.
Phần Không Đẹp: Sử dụng các nút để triển khai vòng lặp
Trong cách tiếp cận đầu tiên với web scraping dùng n8n, chúng ta sẽ xây dựng và duy trì thủ công toàn bộ logic vòng lặp của mình bằng các nút Set. Trước khi phân tích từng nút một, đây là toàn bộ quy trình làm việc trông như thế nào:

Quy trình của chúng ta bắt đầu bằng một nút Manual Trigger theo sau đó là một nút Set thiết lập số trang thành 1. Con số này sẽ được sử dụng làm đầu vào cho nút HTTP và sẽ thay đổi khi chúng ta tiến qua các trang tiếp theo.

Chất lượng chính của quá trình này là lấy dữ liệu và xử lý (quét) từng trang, việc này được thực hiện bằng cách sử dụng Yêu cầu HTTP và các nút HTML. Để lấy trang sản phẩm đầu tiên, chúng ta cần thêm một nút Yêu cầu HTTP được cấu hình gửi yêu cầu GET tới URL sau (nhớ sử dụng chế độ biểu thức khi xác định URL để đảm bảo số trang chính xác được sử dụng thay vì biến):
https://webscraper.io/test-sites/e-commerce/static/phones/touch?page={{ $json.page }}

Sau đó, chúng ta có thể thêm một nút HTML và thiết lập để trích xuất (vì vậy hãy chọn Extract HTML Content làm hành động khi thêm nút này) các dữ liệu sau từ trang web:
- Thông tin chi tiết của từng sản phẩm. Để đơn giản, chúng ta sẽ chỉ trích xuất tên sản phẩm,
- Trang hiện tại. Chúng ta sẽ sử dụng để di chuyển tới trang hiện tại trong cửa hàng.
Chúng ta có thể cấu hình nút này để trả về dữ liệu trong các thuộc tính products và currentPage, lần lượt, bằng cách thiết lập theo cách sau:
Với điều này, chúng ta đã có dữ liệu và logic vòng lặp, đã đến lúc thêm điều kiện trước khi tạo kết nối vòng lặp thực sự.

Khi xem xét từng trang sản phẩm, chúng ta nhận thấy danh sách đầy đủ hiển thị chính xác sáu sản phẩm, trong khi sản phẩm cuối cùng ít hơn. Chúng ta có thể sử dụng kiến thức này để kiểm tra xem có phải chúng ta đang ở trang cuối cùng hay không bằng cách kiểm tra số lượng sản phẩm đã lấy được trên từng trang. Giả định của chúng ta là trang đầu tiên có ít hơn sáu sản phẩm chính là trang cuối cùng trong cửa hàng. Có những cách mạnh mẽ hơn để phát hiện trang cuối cùng, nhưng phương pháp này sẽ giúp chúng ta thực hiện phân trang mà không phải xử lý quá nhiều dữ liệu trong các nút bổ sung.
Chúng ta sẽ áp dụng điều kiện vòng lặp bằng cách thêm một nút IF trước khi vòng lặp kết nối trở lại đầu vào của nút Yêu cầu HTTP. Nút IF này có một điều kiện Số kiểm tra xem {{ $json.products.length }} nhỏ hơn số 6 hay không:

Nếu không phải, chúng ta cần tiếp tục quét trang tiếp theo, bằng cách kết nối nhánh xuất false của nút IF vào một nút Set mới, tăng số trang lên một và vòng trở lại nút Yêu cầu HTTP.
Set mới và các giá trị tham số của nó:

Chúc mừng! Bạn vừa tạo thành công một vòng lặp trong n8n!
Bây giờ, nhiệm vụ của workflow này kết thúc khi điều kiện từ nút IF của chúng ta được giải quyết là đúng. Chúng ta sẽ không đi vào chi tiết điều đó xảy ra như thế nào, nhưng bạn sẽ nhận thấy workflow hoàn chỉnh có một nút Code ở cuối, giúp lấy danh sách tất cả các sản phẩm đã quét (còn phần đó sẽ được đề cập đến chút nữa cuối bài).
Điều không tốt: Sử dụng dữ liệu tĩnh của workflow
Vòng lặp được thực hiện trong ví dụ này rất giống với ví dụ trước, với hai điểm khác biệt đáng kể:
- Thay vì phân tích số trang hiện tại từ trang web đã thu thập, chúng ta sẽ lưu trữ nó trong dữ liệu tĩnh của quy trình làm việc. Bạn có thể nghĩ dữ liệu tĩnh của quy trình làm việc như một kho bí mật bên trong mỗi quy trình, có thể truy cập từ bên trong các nút Code và các biểu thức của bạn, và nó cho phép chúng ta lưu trữ, đọc, và cập nhật các giá trị (số, chuỗi, ngày tháng, v.v.) mà chúng quan tâm cho quy trình làm việc hiện tại. Điều này sẽ cung cấp quyền truy cập trực tiếp đến dữ liệu đã lưu trong các nút cần thiết thay vì truyền giá trị một cách không cần thiết qua toàn bộ quy trình.
- Chúng ta sẽ sử dụng các phần tử HTML phân trang để xác định số trang cần thu thập và kiểm tra xem chúng ta đã đến trang cuối cùng chưa. Điều này sẽ đảm bảo thuật toán thu thập dữ liệu hoạt động chính xác trong trường hợp trang cuối cùng chứa số lượng sản phẩm giống như các trang trước.
Dưới đây là giao diện của quy trình làm việc này sau khi mọi thứ đã được kết hợp:

Một nhược điểm có thể là nó dựa nhiều vào lập trình hơn so với ví dụ trước, nhưng, như sẽ được trình bày, nó chỉ cần vài dòng mã JavaScript để mọi thứ hoạt động. Hầu hết các nút đều giống như trong ví dụ đầu tiên, vì vậy chúng ta sẽ không đi quá sâu vào chi tiết của phương pháp này.
Chúng ta bắt đầu quy trình làm việc của mình bằng một Code node, được thiết lập để chạy một lần cho tất cả các mục và chứa đoạn mã sau (đừng quên thêm một trigger node như bước đầu tiên!):
const workflowStaticData = $getWorkflowStaticData('global');
let currentPage = workflowStaticData.currentPage;
if (currentPage) {
currentPage = currentPage + 1;
} else {
currentPage = 1;
}
return { json: { page: currentPage, } }
Nếu bạn không quen thuộc với JavaScript, đây là bản dịch: nó cố gắng lấy giá trị pageNumber từ kho dữ liệu tĩnh của quy trình làm việc global, và nếu tìm thấy, nó sẽ tăng nó lên một đơn vị (để chuyển sang thu thập trang sản phẩm tiếp theo). Nếu không có giá trị đó, tức là lần chạy đầu tiên của quy trình, nó sẽ đặt giá trị này là 1.
Bước tiếp theo là lấy trang sản phẩm hiện tại bằng cách sử dụng nút HTTP Request. Chúng ta có thể thực hiện điều này bằng cách cài đặt nút chính xác như đã làm trong ví dụ đầu tiên:

Tiếp theo, chúng ta lại cần nút HTML để trích xuất dữ liệu cần thiết từ mỗi trang sản phẩm. Như đã đề cập, chúng ta muốn phân tích trang hiện tại, tổng số trang, và dữ liệu từng sản phẩm. Vì vậy, trong trường hợp này, nút HTML của chúng ta được cấu hình như sau:

Sau khi xử lý xong trang sản phẩm, đã đến lúc quyết định xem có cần lặp lại quá trình cho trang tiếp theo hay không hoặc đã đến trang cuối cùng chưa. Lần này, chúng ta có cả số trang hiện tại và tổng số trang, do đó, việc này chỉ đơn giản là thêm một nút IF so sánh hai giá trị này:

Chú ý rằng chúng ta đang trừ đi số 2 từ số lượng phần tử phân trang vì các phần tử phân trang đầu tiên và cuối cùng được dùng để nhảy đến đầu và cuối danh sách và không phải là liên kết trang riêng lẻ. Sau đó, nếu chúng ta vẫn chưa ở trang cuối cùng, chúng ta sẽ lưu số trang hiện tại vào kho dữ liệu tĩnh của quy trình làm việc bằng cách sử dụng Code mới:
const workflowStaticData = $getWorkflowStaticData('global');
workflowStaticData.currentPage = parseInt($input.first().json.currentPage);
return {}
Và cuối cùng, đã đến lúc kết nối Code mới này trở lại node ban đầu chúng ta đã tạo, điều này sẽ tăng số đã lưu và bắt đầu quá trình quét dữ liệu cho trang tiếp theo.
Điểm mạnh: Tận dụng dữ liệu runtime để theo dõi số lần lặp
Còn ở đó chứ? Tốt.
Đã đến lúc áp dụng cách tiếp cận cuối cùng và tối ưu nhất để thực hiện vòng lặp trong n8n. Ở đây, chúng ta sẽ lợi dụng một cơ chế nội bộ nhỏ của n8n để theo dõi trang sản phẩm hiện tại mà chúng ta đang ở.
Như thường lệ, toàn bộ quy trình làm việc được hiển thị dưới đây, nơi bạn có thể thấy vòng lặp rõ ràng và sạch sẽ mà nó tạo ra:

Khi quan sát các quy trình làm việc khi chúng chạy, bạn có thể đã nhận thấy một số nhỏ xuất hiện ở góc dưới bên phải của mỗi node khi chúng hoạt động. Số đó gọi là chỉ số chạy của node và đếm số lần node thực thi trong lần thực hiện quy trình làm việc hiện tại. Chính xác là những gì chúng ta cần để đếm trang!
Hơn nữa, chỉ số chạy còn khả dụng để sử dụng trong biểu thức với từ khóa đặc biệt $runIndex. Với điều này, chúng ta có thể xây dựng một quy trình khá giống với ví dụ trước, nhưng bây giờ chúng ta có thể dùng chỉ số chạy làm số trang hiện tại và loại bỏ cả 2 node Code.
Bước đầu tiên, chúng ta sẽ dùng một node Set xuất ra một giá trị duy nhất (gọi là page) là một chỉ số chạy cộng thêm một (điều này cần thiết vì chỉ số chạy bắt đầu từ zero trong n8n):

Sau đó, HTTP Request và HTML nodes sẽ giống như ví dụ trước, với điểm khác biệt là chúng ta không cần quét dữ liệu của trang hiện tại trong node HTML (chỉ lấy sản phẩm và các phần tử phân trang):

Sau node HTML, chúng ta sẽ thêm node IF đáng tin cậy của mình để kiểm tra xem có phải chúng ta đang ở trang cuối cùng hay không. Chúng ta sẽ kiểm tra xem số trang hiện tại ($runIndex) có nhỏ hơn tổng số trang sản phẩm ($json.pagination.length – 2) hay không. Nếu đúng, chúng ta sẽ tạo vòng lặp bằng cách kết nối nhánh xuất true của node IF trở lại input của node Set. Thế là xong. Không cần node trung gian nào khác!

Và một thủ thuật cuối cùng cho phần kết. Bây giờ bạn đã xử lý tất cả các trang, chúng ta chỉ có thể xem dữ liệu từ trang cuối trong đầu vào của quy trình làm việc của mình. Nhưng đừng lo; điều hay về n8n là chúng ta có thể truy cập dữ liệu của từng nút từ mỗi vòng lặp nó chạy. Đây chính xác là những gì nút Liệt kê tất cả sản phẩm mà bạn đã thấy trong các quy trình làm việc hoàn chỉnh đang làm. Dưới đây là mã code nó chứa:
let pageCount = $node['Scrape data from the page'].runIndex;
let allProducts = [];
for (let index = 0; index <= pageCount; index++) {
allProducts = allProducts.concat($items('Scrape data from the page', 0, index));
};
return allProducts;
Kết luận
Trong bài viết này, chúng ta đã đề cập đến ba cách tạo vòng lặp trong quy trình n8n để thu thập dữ liệu từ một trang web:
- Thông qua việc tạo và duy trì dữ liệu vòng lặp bằng cách sử dụng các nút Set,
- Thông qua việc sử dụng dữ liệu tĩnh của quy trình làm việc và
- Thông qua việc tận dụng chỉ số chạy của nút để theo dõi các vòng lặp.
Đây không phải là những phương pháp duy nhất để tạo vòng lặp trong n8n nhưng sẽ là những hướng dẫn tốt để giải quyết các vấn đề tự động hóa tương lai của bạn yêu cầu lặp lại. Ngoài ra, chúng ta đã xem xét một số kỹ thuật nâng cao và nội bộ của n8n mà, hy vọng, sẽ hữu ích trong hành trình n8n sắp tới của bạn.
Đăng ký tài khoản n8n của bạn trên nền tảng đám mây và bắt đầu tự động hóa miễn phí. Bạn cũng có thể chạy n8n trên máy chủ của mình hoặc tải xuống trên máy tính, hãy đọc bài hướng dẫn tại đây để biết thêm