Cung cấp Tìm kiếm Web Trực tiếp LLM Địa phương với Ollama + Scrapeless
Senior Web Scraping Engineer
Một mô hình chạy trên máy của bạn không biết gì ngoài mốc thời gian đào tạo của nó. Hãy hỏi một Llama, Qwen hoặc Mistral địa phương về một tiêu đề từ tuần này và nó sẽ hoặc từ chối hoặc, tệ hơn, phát biểu điều gì đó hợp lý nhưng sai. Hồ sơ rủi ro AI sinh tạo của NIST có một cái tên cho chế độ thất bại thứ hai: confabulation, được định nghĩa là một hệ thống "tạo ra và tự tin trình bày nội dung sai hoặc không chính xác để phản hồi lại các yêu cầu." Một mô hình không có con đường đến dữ liệu hiện tại không thể tránh khỏi điều đó khi câu hỏi liên quan đến hôm nay.
Giải pháp không phải là một mô hình lớn hơn. Đó là một công cụ tìm kiếm mà mô hình có thể gọi, được kết nối với một API tìm kiếm trả về kết quả thực, với các kết quả được đưa vào cùng một cuộc trò chuyện trước khi mô hình đưa ra câu trả lời cuối cùng. Hướng dẫn này kết nối mẫu đó từ đầu đến cuối: Ollama chạy một mô hình gọi công cụ hoàn toàn trên phần cứng của chính bạn, và Scrapeless Deep SerpApi là backend tìm kiếm mà mô hình truy cập. Mỗi yêu cầu và phản hồi được hiển thị bên dưới là một thực thi thực tế ghi lại, không phải là bản sao mô phỏng.
Những gì tích hợp này cho phép
Một mô hình địa phương với một công cụ tìm kiếm gắn liền có thể trả lời các câu hỏi mà trọng số của nó một mình không thể:
- Sự kiện và giá cả hiện tại. Một mô hình được đào tạo từ nhiều tháng trước không thể biết số liệu của quý này; một cuộc gọi tìm kiếm trực tiếp có thể.
- Kiểm tra sự thật so với nhớ lại của chính nó. Mô hình đưa ra câu trả lời, sau đó một cuộc gọi tìm kiếm xác nhận hoặc sửa chữa nó trước khi phản hồi cuối cùng được gửi đi.
- Các tác nhân offline-first với một phụ thuộc mạng hẹp. Tất cả - trọng số, lập luận, logic lựa chọn công cụ - đều chạy trên máy cục bộ. Cuộc gọi ra ngoài duy nhất là yêu cầu tìm kiếm chính nó, được giới hạn chính xác vào truy vấn mà mô hình đã chọn để hỏi.
- Các mô hình nhỏ hoạt động vượt xa dữ liệu đào tạo của chúng. Mô hình trong hướng dẫn này có 0,5 tỷ tham số. Nó không cần biết gì về các nhiệm vụ sao Hỏa; nó cần nhận ra rằng câu hỏi yêu cầu một tìm kiếm và đặt ra một truy vấn hợp lý.
Tại sao chọn Deep SerpApi cho công cụ tìm kiếm
Ollama cung cấp tính năng tìm kiếm được lưu trữ riêng của nó (ollama.com/api/web_search), và đây là mặc định hợp lý cho một prototype nhanh chóng. Nó cũng yêu cầu một tài khoản Ollama, một OLLAMA_API_KEY, và định tuyến mọi truy vấn thông qua dịch vụ đám mây của riêng Ollama - mô hình vẫn ở cục bộ, nhưng bước tìm kiếm không giữ ngoài hạ tầng của Ollama hơn bất kỳ nhà cung cấp tìm kiếm được lưu trữ nào khác. Giới hạn mặc định được tài liệu hóa của nó là 5 kết quả mỗi cuộc gọi, tối đa 10.
Deep SerpApi là một điểm đầu cuối tìm kiếm cấu trúc dành riêng: một POST xác thực trả về các kết quả hữu cơ của Google, các tìm kiếm liên quan, phân trang, và (tùy thuộc vào truy vấn) dữ liệu video và bảng kiến thức được phân tích dưới dạng JSON - không phải là tóm tắt rút gọn. Trang sản phẩm của Scrapeless liệt kê phạm vi trên "20+ kịch bản SERP của Google và các công cụ tìm kiếm chính" (Tìm kiếm, Tin tức, Bản đồ, Mua sắm, Xu hướng, và nhiều hơn nữa), thời gian phản hồi "1-2 giây", và một cấp độ miễn phí của "2.000 cuộc gọi API miễn phí" mà không cần thẻ. Việc sử dụng trả phí chỉ từ "1,05 USD/1K truy vấn." Nếu một dự án đã phụ thuộc vào Scrapeless cho các công việc thu thập dữ liệu khác, hoặc cần toàn bộ lược đồ kết quả hữu cơ thay vì một tóm tắt câu trả lời ngắn, việc kết nối khóa Deep SerpApi của cùng một tài khoản vào vòng gọi công cụ giúp giữ một nhà cung cấp và một hóa đơn thay vì hai.
Nhận miễn phí khóa API bằng cách đăng ký - không cần thẻ: app.scrapeless.com.
Điều kiện tiên quyết
- Một máy tính Linux, macOS, hoặc WSL2 với ít nhất 2 GB RAM miễn phí (mô hình trong hướng dẫn này sử dụng chưa tới 1 GB sau khi tải; một GPU là tùy chọn và chỉ tăng tốc độ suy diễn).
curlvà Python 3.9 trở lên.- Một tài khoản Scrapeless và khóa API từ trang Quản lý Khóa API trên bảng điều khiển.
- Không có tài khoản Ollama và không có
OLLAMA_API_KEY- con đường này không bao giờ gọi dịch vụ lưu trữ của Ollama.
Cài đặt và chạy một mô hình gọi công cụ cục bộ
Cài đặt Ollama:
bash
curl -fsSL https://raw.githubusercontent.com/ollama/ollama/main/scripts/install.sh | sh
Trên một máy chủ Linux được quản lý bởi systemd (bao gồm WSL2 với systemd đã bật), trình cài đặt sẽ đăng ký và khởi động dịch vụ ollama tự động, lắng nghe trên 127.0.0.1:11434. Xác nhận nhị phân và dịch vụ:
bash
ollama --version
# phiên bản ollama là 0.31.2
Kéo một mô hình có khả năng gọi công cụ nhỏ. Các checkpoint tinh chỉnh hướng dẫn của Qwen2.5 hỗ trợ gọi hàm xuống kích thước 0,5 tỷ tham số, giữ cho tải xuống và dung lượng bộ nhớ nhỏ:
bash
ollama pull qwen2.5:0.5b
ollama list sau đó xác nhận mô hình là địa phương: một mục 397 MB có tên qwen2.5:0.5b, sẵn sàng phục vụ mà không cần truy cập mạng thêm.
Không phải mô hình nào chạy tại chỗ cũng hỗ trợ gọi công cụ — hãy kiểm tra trang của mô hình trên thư viện của Ollama để tìm thẻ "Công cụ" trước khi xây dựng vòng lặp tác nhân quanh nó. Các điểm kiểm tra lớn hơn như Qwen2.5, Llama 3.1 và Mistral cũng mang cùng một thẻ nếu 0.5B là quá nhỏ cho một nhiệm vụ nhất định.
Nhận một chìa khóa API Scrapeless miễn phí trong khi mô hình đang tải xuống — không cần thẻ: app.scrapeless.com.
Xác minh Điểm Kết Nối Deep SerpApi
Deep SerpApi có một hình thức cho mỗi kịch bản: tên actor cộng với một đối tượng input, được tài liệu hóa tại docs.scrapeless.com. Kịch bản Tìm kiếm Google sử dụng diễn viên scraper.google.search:
bash
curl -s -X POST "https://api.scrapeless.com/api/v1/scraper/request" \
-H "x-api-token: $SCRAPELESS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"actor": "scraper.google.search",
"input": {"q": "tin tức mới nhất về nhiệm vụ Trả mẫu sao Hỏa", "gl": "us", "hl": "en"}
}'
Một cuộc gọi trực tiếp cho truy vấn đó trả về HTTP 200 với một phần thân JSON mang các trường cấp cao này: organic_results, pagination, related_searches, search_information, inline_videos, video_results, và metadata. Mỗi mục trong organic_results mang theo position, title, link, redirect_link, favicon, snippet, snippet_highlighted_words, và source. Phản hồi là JSON đơn giản JSON — không có streaming, không có phiên để giữ mở, một yêu cầu vào và một tài liệu ra. Một yêu cầu chưa hoàn tất ở phía máy chủ trả về HTTP 201 với một taskId; trường hợp thông thường cho truy vấn Tìm kiếm Google là đồng bộ 200 như trên.
Định nghĩa và Gắn Kết Công Cụ Tìm Kiếm
Điểm kết nối /api/chat của Ollama chấp nhận một mảng tools được cấu trúc như định nghĩa hàm JSON Schema. Định nghĩa một công cụ, web_search, và truyền nó cùng với cuộc trò chuyện:
python
TOOLS = [
{
"type": "function",
"function": {
"name": "web_search",
"description": "Tìm kiếm thông tin hiện tại trên web và trả về kết quả hữu cơ hàng đầu với tiêu đề, liên kết và đoạn trích.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Truy vấn tìm kiếm"}
},
"required": ["query"],
},
},
}
]
Gắn TOOLS vào mọi yêu cầu /api/chat để mô hình luôn biết công cụ tồn tại:
python
import json
import urllib.request
OLLAMA_URL = "http://127.0.0.1:11434/api/chat"
MODEL = "qwen2.5:0.5b"
def ollama_chat(messages):
body = json.dumps({"model": MODEL, "stream": False, "messages": messages, "tools": TOOLS}).encode()
req = urllib.request.Request(OLLAMA_URL, data=body, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=180) as resp:
return json.load(resp)
Mô hình không bao giờ tự gọi Deep SerpApi — nó chỉ phát ra một mục tool_calls có tên web_search với các tham số mà nó đã chọn. Một hàm Python mỏng thực hiện công việc HTTP thực tế và trả lại kết quả đã định hình:
python
import os
def web_search(query: str) -> str:
body = json.dumps({
"actor": "scraper.google.search",
"input": {"q": query, "gl": "us", "hl": "en"},
}).encode()
req = urllib.request.Request(
"https://api.scrapeless.com/api/v1/scraper/request",
data=body,
headers={
"x-api-token": os.environ["SCRAPELESS_API_KEY"],
"Content-Type": "application/json",
},
)
with urllib.request.urlopen(req, timeout=60) as resp:
data = json.load(resp)
results = data.get("organic_results", [])[:3]
shaped = [
{"title": r.get("title"), "link": r.get("link"), "snippet": r.get("snippet")}
for r in results
]
return json.dumps(shaped)
Cắt ngắn đến ba kết quả hàng đầu trước khi trả lại đầu ra công cụ để giữ cho cuộc gọi thứ hai đến /api/chat nhỏ — một mô hình 0.5 tỷ tham số có một cửa sổ ngữ cảnh hạn chế, và toàn bộ phản hồi mang theo các liên kết phân trang, biểu tượng yêu thích, và các khối tìm kiếm liên quan mà mô hình không cần để trả lời câu hỏi.
Sử Dụng Dựa Trên Gợi Ý: Theo Dõi Mô Hình Quyết Định
Kết hợp các phần lại với nhau: gửi một gợi ý cần thông tin hiện tại, để mô hình yêu cầu công cụ, thực hiện yêu cầu đó chống lại Deep SerpApi, và gửi kết quả trở lại để có một câu trả lời cuối cùng có cơ sở.
python
import json
import os
import urllib.request
OLLAMA_URL = "http://127.0.0.1:11434/api/chat"
vi
SCRAPELESS_URL = "https://api.scrapeless.com/api/v1/scraper/request"
MODEL = "qwen2.5:0.5b"
TOOLS = [
{
"type": "function",
"function": {
"name": "web_search",
"description": "Tìm kiếm trên web trực tiếp để có thông tin hiện tại và trả về các kết quả tự nhiên hàng đầu với tiêu đề, liên kết và các đoạn trích dẫn.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Câu truy vấn tìm kiếm"}
},
"required": ["query"],
},
},
}
]
def ollama_chat(messages):
body = json.dumps({"model": MODEL, "stream": False, "messages": messages, "tools": TOOLS}).encode()
req = urllib.request.Request(OLLAMA_URL, data=body, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=180) as resp:
return json.load(resp)
def web_search(query: str) -> str:
body = json.dumps({
"actor": "scraper.google.search",
"input": {"q": query, "gl": "us", "hl": "en"},
}).encode()
req = urllib.request.Request(
SCRAPELESS_URL,
data=body,
headers={"x-api-token": os.environ["SCRAPELESS_API_KEY"], "Content-Type": "application/json"},
)
with urllib.request.urlopen(req, timeout=60) as resp:
data = json.load(resp)
results = data.get("organic_results", [])[:3]
return json.dumps([
{"title": r.get("title"), "link": r.get("link"), "snippet": r.get("snippet")}
for r in results
])
messages = [{"role": "user", "content":
"Những tiêu đề mới nhất về nhiệm vụ Trả mẫu từ sao Hỏa hôm nay là gì? "
"Sử dụng công cụ tìm kiếm nếu bạn cần thông tin hiện tại."}]
first_turn = ollama_chat(messages)
print(json.dumps(first_turn["message"], indent=2))
tool_call = first_turn["message"]["tool_calls"][0]
query = tool_call["function"]["arguments"]["query"]
result = web_search(query)
messages.append(first_turn["message"])
messages.append({"role": "tool", "content": result, "tool_name": "web_search"})
second_turn = ollama_chat(messages)
print(json.dumps(second_turn["message"], indent=2))
Một lần chạy sống chống lại qwen2.5:0.5b in ra điều này cho lần đầu tiên — chưa có câu trả lời cuối cùng, chỉ là một yêu cầu công cụ:
json
{
"role": "assistant",
"content": "",
"tool_calls": [
{
"id": "call_dwndere1",
"function": {
"index": 0,
"name": "web_search",
"arguments": {
"query": "Những tiêu đề mới nhất về Nhiệm vụ Trả mẫu từ sao Hỏa"
}
}
}
]
}
Mô hình đã đọc lời nhắc, nhận ra rằng cần thông tin hiện tại, và chọn truy vấn tìm kiếm của riêng nó — cách diễn đạt của lần chạy này đến từ mô hình, không phải là bản sao của câu của người dùng. Mã gọi thực hiện web_search(query="Những tiêu đề mới nhất về Nhiệm vụ Trả mẫu từ sao Hỏa") chống lại Deep SerpApi, nhận về ba kết quả đã định hình, và bổ sung chúng như một tin nhắn role: "tool" trước khi gửi cuộc trò chuyện đến /api/chat lần thứ hai.
Điều bạn nhận được
Câu lệnh print thứ hai là câu trả lời thực tế của mô hình, dựa trên những gì cuộc gọi tìm kiếm đã trả về:
json
{
"role": "assistant",
"content": "Dưới đây là một số tiêu đề mới nhất về nhiệm vụ Trả mẫu từ sao Hỏa:\n\n- [Trả mẫu từ sao Hỏa - Các nhiệm vụ sao Hỏa](https://www.jpl.nasa.gov/missions/mars-sample-return-msr/)\n - Liên kết này dẫn bạn đến trang web của NASA có thông tin về chương trình Trả mẫu từ sao Hỏa.\n- [NASA-ESA Trả mẫu từ sao Hỏa](https://en.wikipedia.org/wiki/NASA-ESA_Mars_Sample_Return)\n - Trang Wikipedia về dự án cũng có sẵn, cung cấp thông tin chi tiết hơn về nhiệm vụ và chi phí của nó.\n\nDưới đây là một số liên kết đến các bài viết liên quan đến nhiệm vụ Trả mẫu từ sao Hỏa:\n\n1. [NASA's Mars Sample Return Is Dead, Paving The Way For China](https://www.universetoday.com/articles/nasas-mars-sample-return-is-dead-paving-the-way-for-china/)\n - Bài viết này cung cấp thêm thông tin về tình trạng hiện tại của nhiệm vụ Trả mẫu từ sao Hỏa.\n\nTôi hy vọng điều này giúp ích! Hãy cho tôi biết nếu bạn cần bất kỳ bài viết hoặc cập nhật nào khác."
}
Mỗi liên kết trong câu trả lời đó trở lại một trong ba kết quả mà web_search thực sự trả về — mô hình đã tóm tắt và tổ chức chúng thành danh sách riêng của nó thay vì tưởng tượng điều gì đó mới trong lần này. Điều này không phải là bảo đảm: một mô hình 0.5 tỷ tham số vẫn có thể sản xuất một chi tiết có vẻ hợp lý mà không bao giờ xuất hiện trong kết quả công cụ, ngay cả với các kết quả tìm kiếm thực hiện trong ngữ cảnh của nó. Căn cứ giảm thiểu xác suất xảy ra điều đó; nó không loại bỏ chúng hoàn toàn, và một hệ thống sản xuất kéo các liên kết ra từ câu trả lời của mô hình nên kiểm tra từng cái so với đầu ra của công cụ trước khi coi đó là sự thật. Mô hình quyết định khi nào nên tìm kiếm, cuộc gọi công cụ là chuyến đi mạng duy nhất mà trọng số của mô hình không sở hữu, và lần hoàn thành thứ hai sẽ không chạy cho đến khi kết quả công cụ có trong cuộc trò chuyện.
Kết luận
Việc kết nối một mô hình cục bộ với Deep SerpApi chỉ cần một định nghĩa công cụ, một hàm HTTP và hai cuộc gọi /api/chat — mô hình xử lý lý luận về khi nào nên tìm kiếm và nên hỏi gì, tương tự như một khung tác nhân mô hình được lưu trữ, nhưng mọi token tạo ra đều ở lại trên máy chạy mô hình. Mô hình này có thể mở rộng vượt qua ví dụ này: thay đổi prompt, thay đổi mô hình, hoặc mở rộng TOOLS với nhiều chức năng hơn, và vòng lặp yêu cầu-gọi-công cụ-phản hồi vẫn giữ nguyên.
Bắt đầu miễn phí — không cần thẻ: app.scrapeless.com. Tham khảo đầy đủ tham số tại docs.scrapeless.com, và giá cho mỗi truy vấn hiện tại tại scrapeless.com/en/pricing. Để biết sự khác biệt giữa một điểm cuối SERP như thế này và các tác nhân của Scrapeless mà thu thập các câu trả lời của nền tảng AI được lưu trữ, xem so sánh SERP-API-với-LLM-scraper.
Câu hỏi thường gặp
Q: Những mô hình cục bộ nào hỗ trợ gọi công cụ?
Bất kỳ mô hình nào được gán nhãn "Tools" trong thư viện mô hình của Ollama đều hoạt động với mô hình này. Qwen2.5 (xuống đến 0.5B), Llama 3.1 và 3.2, Mistral, và IBM Granite đều cung cấp các điểm kiểm tra có khả năng gọi công cụ. Một mô hình không có nhãn đó có thể vẫn phát ra JSON hình dạng tool_calls dưới dạng văn bản đơn giản, mà mã gọi phải phân tích thủ công thay vì đọc một trường có cấu trúc — hãy kiểm tra nhãn trước khi xây dựng xung quanh một mô hình nhất định.
Q: Có cần kết nối internet cho mô hình không?
Không. Mô hình, prompt và lý luận đều chạy trên máy cục bộ. Request duy nhất ra ngoài là cuộc gọi công cụ web_search đến Deep SerpApi, chỉ ở đúng truy vấn mà mô hình đã tạo — không có gì khác về quá trình này ảnh hưởng đến mạng.
Q: Tại sao không sử dụng tìm kiếm web tích hợp sẵn của Ollama thay vì khóa API riêng?
Tìm kiếm được lưu trữ của Ollama (ollama.com/api/web_search) là một lựa chọn hợp lý cho một nguyên mẫu nhanh, và nó không cần tài khoản nhà cung cấp riêng ngoài tài khoản Ollama. Nó yêu cầu một OLLAMA_API_KEY liên kết với tài khoản miễn phí của Ollama, giới hạn kết quả ở 10 mỗi cuộc gọi, và trả về danh sách kết quả chung chung thay vì sơ đồ kết quả tự nhiên đầy đủ của Google (vị trí, tìm kiếm liên quan, phân trang, các lĩnh vực). Deep SerpApi là sự lựa chọn tốt hơn khi một dự án cần sơ đồ đầy đủ hơn, các trường hợp không phải tìm kiếm Google, hoặc đã chạy các công việc khác thông qua tài khoản Scrapeless.
Q: Điều gì xảy ra nếu cuộc gọi tìm kiếm thất bại?
Một yêu cầu không hợp lệ trả về HTTP 400; khóa API không hợp lệ hoặc bị thiếu trả về lỗi xác thực; một truy vấn mà chưa hoàn tất phía máy chủ trả về HTTP 201 với taskId thay vì thân kết quả. Kiểm tra mã trạng thái trước khi giả định rằng organic_results tồn tại trong phản hồi, giống như bất kỳ máy khách HTTP nào kiểm tra phản hồi trước khi phân tích thân của nó.
Q: Tôi có thể nhắm mục tiêu một quốc gia hoặc ngôn ngữ khác ngoài tiếng Anh không?
Có — gl đặt mã quốc gia Google và hl đặt ngôn ngữ giao diện cho mọi yêu cầu scraper.google.search; cả hai đều là các trường chuỗi thông thường trong đối tượng input, được thiết lập cho mỗi cuộc gọi.
Q: Mô hình có bao giờ gọi trực tiếp đến Deep SerpApi không?
Không. Mô hình chỉ phát ra một mục tool_calls mô tả chức năng nào sẽ chạy và với các tham số gì — nó không có quyền truy cập mạng của riêng mình. Mã Python gọi sở hữu yêu cầu HTTP thực tế, cũng là điều giữ khóa API ra ngoài bối cảnh của mô hình hoàn toàn.
Q: Liệu có an toàn khi nhắm vào việc thu thập kết quả tìm kiếm thay vì một API không?
Deep SerpApi trả về dữ liệu Google đã được phân tích qua một điểm cuối xác thực, vì vậy không có mối quan tâm về robots.txt hoặc giới hạn tần suất ở phía người gọi — công việc hạ tầng đó diễn ra ở phía Scrapeless. Bất kỳ ai xây dựng tương đương bằng cách thu thập các trang kết quả của Google trực tiếp nên đọc Giao thức loại trừ Robots và điều khoản của mục tiêu đó trước; một điểm cuối tìm kiếm được quản lý tồn tại đặc biệt để tránh loại vấn đề đó.
Q: Thực sự điều gì xảy ra khi mô hình "quyết định" tìm kiếm?
Đây là mô hình lấy thông tin rồi sinh nội dung được mô tả trong nghiên cứu tăng cường lấy thông tin: một mô hình điều kiện hóa đầu ra cuối cùng của nó dựa trên các tài liệu được lấy trong thời gian suy diễn thay vì chỉ dựa vào những gì đã được gắn liền với trọng số của nó. Việc gọi công cụ là cơ chế mà các mô hình tinh chỉnh trò chuyện hiện đại sử dụng để tự kích hoạt việc lấy thông tin này, trong cuộc trò chuyện, thay vì một bước lấy thông tin cố định diễn ra trước mỗi truy vấn.
Q: Việc căn cứ có ngăn cản hoàn toàn mô hình tạo ra những điều không đúng không?
Không. Nó làm giảm sự hư cấu về các thực tế cụ thể mà kết quả tìm kiếm thực sự đề cập, nhưng một mô hình nhỏ vẫn có thể gán nhầm, tóm tắt quá mức, hoặc thêm một chi tiết không có trong đầu ra của công cụ. Hãy xem phần trả lời thứ hai như một bản nháp được thông báo bởi dữ liệu thực, không phải là một trích dẫn có thẩm quyền — đối với bất kỳ thông tin nào có tính chất trọng yếu, hãy so sánh các tuyên bố của mô hình với tải trọng organic_results mà nó thực sự được cung cấp trước khi tin tưởng vào chúng.
Tại Scrapless, chúng tôi chỉ truy cập dữ liệu có sẵn công khai trong khi tuân thủ nghiêm ngặt các luật, quy định và chính sách bảo mật trang web hiện hành. Nội dung trong blog này chỉ nhằm mục đích trình diễn và không liên quan đến bất kỳ hoạt động bất hợp pháp hoặc vi phạm nào. Chúng tôi không đảm bảo và từ chối mọi trách nhiệm đối với việc sử dụng thông tin từ blog này hoặc các liên kết của bên thứ ba. Trước khi tham gia vào bất kỳ hoạt động cạo nào, hãy tham khảo ý kiến cố vấn pháp lý của bạn và xem xét các điều khoản dịch vụ của trang web mục tiêu hoặc có được các quyền cần thiết.



