Ngiêm cấm sử đụng PROXY và VPS vào mục đích trái pháp luật bạn sẽ phải chịu toàn bộ trách nhiệm trước pháp luật khi sử dụng dịch vụ của chúng tôi tks!
SearXNG API JSON nội bộ: bật format, xử lý 403, lọc kết quả

SearXNG API JSON nội bộ: bật format, xử lý 403 và lọc kết quả

Chuyên viên Kỹ thuật ProxyVN 02-13-2026 Đang tính... phút đọc

SearXNG API JSON nội bộ là cách gọi một instance SearXNG do chính nhóm quản lý để nhận kết quả tìm kiếm dạng máy đọc được. Mặc định instance chỉ bật html, nên gọi format=json sẽ nhận 403. ProxyVN đối chiếu mã nguồn SearXNG, rồi chạy client thật trên máy chủ mô phỏng để kiểm tra phần chuẩn hóa, và ghi rõ phần chưa chạy.

SearXNG API JSON nội bộ: mục tiêu và phạm vi không lặp

Phần này chốt bài toán, đầu ra và những gì bài không làm.

Bài toán cần giải

Một nhóm dữ liệu muốn tìm URL theo chủ đề rồi đưa vào hàng đợi crawl. Họ không muốn gắn thẳng vào một dịch vụ tìm kiếm trả phí, nên dựng SearXNG trong mạng nội bộ. Lần gọi đầu nhận 403, cả nhóm nghi tường lửa. Nguyên nhân lại nằm ở một dòng trong settings.yml.

Đầu ra nghiệm thu

Đầu ra gồm ba thứ. Một là cấu hình search.formats có json. Hai là bảng đối chiếu cấu hình với mã trả về. Ba là hàm chuẩn hóa nhận JSON, bỏ URL trùng, bỏ host ngoài danh sách cho phép, rồi giới hạn số URL đưa xuống bước tải.

Ranh giới với bài khác

Bài này chỉ nói về instance tự quản. Dịch vụ search API thu phí như Tavily hay Exa có khóa và hạn mức riêng, nên không nằm trong phạm vi. Bài cũng không giải thích SERP là gì, không so sánh công cụ tìm kiếm, không bày cách gọi instance công cộng của người khác.

Giới hạn của lab

Cần nói thẳng điều này trước. ProxyVN không chạy SearXNG thật trong lab này. Việc clone mã nguồn về chạy bị chặn trên máy lab, nên phần máy chủ là một script Python nhỏ. Script đó chép lại đúng nhánh xử lý format và query của tệp searx/webapp.py, đọc ngày 04/11/2026. Client requests thì chạy thật qua cổng cục bộ.

Hiểu kết quả mô phỏng thế nào

Mã 403 hay 400 trong lab không chứng minh SearXNG thật trả như vậy. Bằng chứng cho hành vi đó là tài liệu và mã nguồn, được dẫn ở phần sau. Lab chỉ chứng minh client và hàm chuẩn hóa của anh em xử lý đúng khi gặp các phản hồi ấy. Phần gọi engine bên ngoài thì chưa chạy chút nào.

Ai nên đọc bài này

Người vận hành pipeline thu thập cần nguồn URL mới. Người vừa dựng SearXNG và gặp 403 khi thêm format=json. Người muốn đưa kết quả tìm kiếm vào công cụ AI nội bộ mà không muốn gửi truy vấn ra dịch vụ bên thứ ba.

Vì sao tự quản instance

Tài liệu SearXNG cảnh báo nhiều instance công cộng đã tắt các format máy đọc. Chủ instance công cộng cũng không muốn bị gọi tự động. Khi cần gọi đều đặn, instance của chính mình là lựa chọn đúng, vì mình kiểm soát cấu hình, tốc độ gọi và nhật ký.

Gọi search API trên SearXNG API JSON nội bộ với format JSON

Phần này tóm tắt tài liệu chính thức trước khi đụng vào cấu hình.

Hai endpoint và hai phương thức

Theo trang Search API của SearXNG, hai endpoint / và /search đều nhận GET và POST. GET nhận tham số trên URL. POST nhận form dạng application/x-www-form-urlencoded. Tài liệu đưa ví dụ curl cho cả hai cách.

curl 'https://searx.example.org/search?q=searxng&format=json'
curl -X POST 'https://searx.example.org/search' -d 'q=searxng&format=csv'
curl -L -X POST -d 'q=searxng&format=json' 'https://searx.example.org/'

Hai dòng đầu là cách dùng thường gặp. Với instance nội bộ, anh em thay searx.example.org bằng địa chỉ trong mạng của mình.

Các tham số hay dùng

Bảng dưới rút từ tài liệu, đủ cho hầu hết tác vụ thu thập URL.

Bảng: Các tham số hay dùng

Tham số

Bắt buộc

Ý nghĩa

q

Có

Chuỗi tìm kiếm, được chuyển cho engine bên ngoài

categories

Không

Danh sách danh mục, cách nhau bằng dấu phẩy

language

Không

Mã ngôn ngữ, mặc định lấy từ mục search

pageno

Không

Số trang, mặc định 1

time_range

Không

day, month hoặc year, chỉ với engine hỗ trợ

format

Không

json, csv hoặc rss, phải được bật trong search

safesearch

Không

0, 1 hoặc 2

Cú pháp truy vấn đi theo từng engine

Tài liệu nêu chuỗi q được chuyển nguyên cho dịch vụ tìm kiếm bên ngoài. Cú pháp site:github.com có tác dụng với engine hiểu nó. Engine không lọc theo cú pháp đó sẽ trả kết quả khác kỳ vọng. Vậy nên đừng tin toán tử tìm kiếm, hãy lọc lại host ở phía mình.

Câu quyết định số phận của request

Tài liệu viết rõ yêu cầu một format chưa được đặt sẽ nhận 403 Forbidden. Đây là dòng nhiều người bỏ qua. Lỗi không liên quan tới khóa API, vì SearXNG không dùng khóa cho endpoint này. Nó cũng không liên quan tới tường lửa, nếu trang html vẫn mở được bình thường.

Mã nguồn xác nhận điều gì

ProxyVN đọc tệp webapp.py trên nhánh master ngày 04/11/2026 để biết thứ tự kiểm tra. Đoạn quan trọng ngắn gọn như sau, chép lại từ mã nguồn.

output_format = sxng_request.form.get('format', 'html')
if output_format not in OUTPUT_FORMATS:
    output_format = 'html'
 
if output_format not in settings['search']['formats']:
    flask.abort(403)

Có hai điều rút ra. Format lạ không báo lỗi mà rơi về html. Kiểm tra format chạy trước kiểm tra query, nên request thiếu q nhưng format bị tắt vẫn nhận 403.

Khi thiếu query

Cũng trong tệp đó, format khác html mà thiếu q sẽ nhận lỗi No query với mã 400. Với format json, phần thân là một đối tượng JSON có trường error. Client nên phân biệt 400 và 403 vì hướng xử lý khác nhau: 400 là lỗi của mã gọi, 403 là lỗi cấu hình instance.

Lỗi tham số và lỗi tìm kiếm

Mã nguồn còn hai nhánh khác. Tham số không hợp lệ trả 400 kèm thông báo. Lỗi trong lúc chạy tìm kiếm trả 500 với thông báo search error. Hai nhánh này ProxyVN chỉ đọc, chưa kích hoạt được trong lab.

Dựng instance được phép và kiểm formats trong SearXNG API JSON nội bộ

Phần này là cấu hình, chỗ gỡ được lỗi 403.

Mục search trong settings.yml

Theo trang cấu hình search, giá trị mẫu của formats chỉ có html. Tài liệu mô tả formats là danh sách định dạng kết quả có sẵn trên web, muốn chặn định dạng nào thì bỏ nó khỏi danh sách, và phải viết chữ thường. Để bật JSON, thêm một dòng.

search:
  safe_search: 0
  formats:
    - html
    - json

Đây là thay đổi duy nhất cần cho lỗi 403. Sau khi sửa phải khởi động lại dịch vụ để cấu hình có hiệu lực.

Chỉ bật đúng thứ cần

Danh sách hợp lệ gồm html, csv, json và rss. Nếu pipeline chỉ đọc JSON thì chỉ thêm json. Bớt một format là bớt một đường ra cần giám sát. Lab thử gọi format=csv khi danh sách chỉ có html và json, kết quả vẫn 403 đúng theo quy tắc.

Mục server cần soát cùng lúc

Theo trang cấu hình server, giá trị mẫu có port 8888, bind_address 127.0.0.1, limiter false và public_instance false. Riêng secret_key mẫu là ultrasecretkey kèm ghi chú phải đổi. Anh em đổi khóa này trước khi cho máy khác gọi vào.

server:
  port: 8888
  bind_address: "127.0.0.1"
  secret_key: "doi-gia-tri-nay"
  limiter: false
  public_instance: false

Khối trên giữ cấu trúc của tài liệu, chỉ thay giá trị khóa.

Bind address và mạng nội bộ

Giá trị 127.0.0.1 nghĩa là chỉ máy đó gọi được. Nếu worker chạy ở máy khác, đừng vội đổi sang lắng nghe mọi địa chỉ. Đặt một reverse proxy có kiểm soát truy cập, hoặc giới hạn trong mạng riêng. Instance đã bật JSON mà lộ ra Internet thì ai cũng dùng được tài nguyên của mình.

Limiter khi gọi tự động

Tài liệu ghi limiter dùng để giới hạn tốc độ và chặn một số bot, và cần cơ sở dữ liệu valkey. Với instance nội bộ, worker của mình có thể bị chính limiter chặn nếu bật mà không cấu hình ngoại lệ. ProxyVN chưa thử limiter trong lab, nên bài không đưa con số giới hạn nào.

Biến môi trường thay cho tệp

Tài liệu nêu một số giá trị có biến môi trường tương ứng, ví dụ SEARXNG_PORT, SEARXNG_BIND_ADDRESS, SEARXNG_SECRET và SEARXNG_LIMITER. Khi chạy bằng container, anh em để bí mật trong biến môi trường, tránh commit secret_key vào kho mã.

Khởi động lại mà không làm rơi việc

Sửa settings.yml xong phải khởi động lại dịch vụ, tức có một khoảng instance không trả lời. Worker gọi đúng lúc đó sẽ gặp lỗi kết nối. Hàm thử lại có giãn thời gian xử lý được chuyện này, miễn là bản ghi truy vấn chưa bị đánh dấu xong. Nếu pipeline chạy theo lịch, cứ chọn giờ không có lượt chạy để đổi cấu hình.

Kiểm tra sau khi sửa

Sau khi khởi động lại, chạy một lệnh curl có format=json và in mã trạng thái. Nếu vẫn 403, đọc lại đúng tệp settings mà tiến trình đang nạp. Lỗi hay gặp là sửa một tệp nhưng dịch vụ đọc tệp ở đường dẫn khác.

Gọi search với query và format=json của SearXNG API JSON nội bộ

Phần này là client và cách máy chủ mô phỏng được dựng.

Máy chủ mô phỏng làm gì

Script dùng http.server của Python, lắng nghe cổng 9471. Nó giữ một biến danh sách formats, ghi lại từng request, và trả bộ kết quả cố định gồm năm mục. Năm mục đó được sắp xếp để có đủ URL trùng, host lạ và scheme lạ. Không có engine thật nào được gọi.

Client gọi thế nào

Client chỉ cần requests và một timeout. Đừng bỏ timeout, vì thời gian trả về phụ thuộc engine chậm nhất mà instance chờ.

import requests
 
BASE = "http://127.0.0.1:9471/search"
 
def search(q, page=1):
    r = requests.get(BASE, params={"q": q, "format": "json", "pageno": page}, timeout=15)
    if r.status_code == 403:
        raise RuntimeError("Instance chua bat json trong search.formats")
    if r.status_code == 400:
        raise ValueError(r.json().get("error"))
    r.raise_for_status()
    return r.json()

Hàm tách 403 và 400 thành hai lỗi riêng. Người trực nhìn thông báo là biết sửa ở đâu.

Các khóa trong phản hồi

Hàm get_json_response trong tệp webutils.py trên nhánh master, đọc ngày 04/11/2026, dựng phản hồi với bảy khóa: query, results, answers, corrections, infoboxes, suggestions và unresponsive_engines. Máy chủ mô phỏng trả đúng bảy khóa này. Anh em vẫn nên in khóa từ instance của mình trước khi viết bộ phân tích, vì mỗi phiên bản có thể khác.

Mỗi mục trong results

Mỗi mục mô phỏng có url, title, content, engine, engines, score và category. Trường engines là danh sách engine cùng trả URL đó. Các trường này ProxyVN dựng theo cách SearXNG thường trả, chưa đối chiếu với instance thật. Mã của anh em nên dùng get với giá trị mặc định, vì mỗi engine cung cấp một bộ trường hơi khác. Mục thiếu content là chuyện thường.

Đừng tìm tổng số kết quả

Một số hướng dẫn cũ nhắc khóa number_of_results. Hàm trên nhánh master hiện không có khóa này. Mã đếm kết quả nên dùng độ dài danh sách results, và phân trang dựa vào việc trang mới có URL mới hay không. Dựa vào một con số tổng từ engine bên ngoài cũng không chắc ăn, vì nhiều engine không báo tổng.

GET hay POST

Với pipeline, cả hai đều chạy. Lab gọi POST bằng form và nhận 200 như GET. POST có một lợi thế nhỏ: chuỗi tìm kiếm không nằm trên URL, nên không lọt vào nhật ký truy cập của reverse proxy. Nếu truy vấn chứa thông tin nội bộ, nên chọn POST.

Phân trang mà không gọi thừa

Tham số pageno cho phép lấy trang tiếp theo, nhưng không phải engine nào cũng có trang sau. Vòng lặp nên dừng ở ba điều kiện: chạm số trang tối đa, trang mới không có URL nào chưa thấy, hoặc results rỗng. Điều kiện thứ hai quan trọng nhất, vì nhiều engine lặp lại kết quả cũ ở trang sau.

def collect(q, max_pages=3):
    seen, out = set(), []
    for page in range(1, max_pages + 1):
        d = search(q, page)
        fresh = [x for x in d["results"] if x["url"] not in seen]
        if not fresh:
            break
        seen.update(x["url"] for x in fresh)
        out += fresh
    return out

Hàm này là ví dụ triển khai, ProxyVN chưa đo nó trên engine thật. Trần max_pages giữ số lượt gọi ra ngoài ở mức biết trước.

Chọn categories thay vì lọc sau

Nếu chỉ cần trang web thông thường, truyền categories để instance không gọi engine hình ảnh hay video. Làm vậy vừa giảm số engine phải gọi, vừa bớt rác ở đầu ra. Tên danh mục tùy instance, nên xem trang Configured Engines của chính mình trước khi viết cứng vào mã.

Lọc theo thời gian

Tham số time_range nhận day, month, year và chỉ có tác dụng với engine hỗ trợ. Engine không hỗ trợ có thể vẫn trả kết quả cũ. Khi cần URL mới thật sự, anh em so ngày trên trang sau khi tải, đừng chỉ dựa vào tham số này.

Tái lập ca format bị tắt của SearXNG API JSON nội bộ

Phần này ghi lại các ca đã chạy và mã nhận được.

Bảng đối chiếu cấu hình với phản hồi

Bảng dưới là kết quả client thật nhận từ máy chủ mô phỏng. Quy tắc trong máy chủ mô phỏng chép từ webapp.py, nên cần kiểm lại trên instance của anh em.

Bảng: Bảng đối chiếu cấu hình với phản hồi

Ca

search.formats

Request

Mã

Content-Type

A1

html

q=proxy, format=json

403

text/html

A2

html

q=proxy, không có format

200

text/html

B1

html, json

q=proxy, format=json

200

application/json

B2

html, json

POST q=proxy, format=json

200

application/json

B3

html, json

q=proxy, format=csv

403

text/html

B4

html, json

q=proxy, format=xml

200

text/html

B5

html, json

format=json, thiếu q

400

application/json

Đọc ca A1

Trang mở được, API bị chặn

Trang mở được, API bị chặn

Ở ca A1, trang tìm kiếm trên trình duyệt vẫn chạy nhưng API thì không. Đây là triệu chứng quen thuộc: người vận hành mở trình duyệt thấy bình thường nên kết luận instance không lỗi. Trang html mở được không nói gì về format json.

Đọc ca B4

Ca B4 nguy hiểm hơn 403. Viết sai format thành xml hay Json, instance trả 200 với html. Client gọi r.json() sẽ vỡ ở bước phân tích, và nhật ký chỉ thấy lỗi giải mã JSON. Vì vậy cần kiểm Content-Type trước khi phân tích.

ctype = r.headers.get("Content-Type", "")
if "json" not in ctype:
    raise RuntimeError(f"Mong doi JSON, nhan {ctype}")

Ba dòng này đổi một lỗi khó hiểu thành một thông báo rõ.

Đọc ca B5

Ca B5 trả về đối tượng có trường error. Mã gọi nên chặn chuỗi rỗng trước khi gửi. Trong pipeline, chuỗi rỗng thường đến từ một dòng trắng trong tệp từ khóa, nên lọc ngay lúc đọc tệp là đủ.

Vì sao không tự thử lại khi 403

403 ở đây là lỗi cấu hình, không phải lỗi tạm thời. Thử lại chỉ sinh thêm request vô ích. Hàng đợi nên đánh dấu lỗi và báo người vận hành. Mã 5xx và lỗi mạng mới là thứ đáng thử lại với thời gian giãn dần.

Kiểm tra sức khỏe sau mỗi lần triển khai

Sau mỗi lần cập nhật instance, chạy lại một truy vấn cố định và so mã trạng thái. Tệp settings có thể bị ghi đè khi triển khai lại, làm mất dòng json. Một kiểm tra nhỏ trong pipeline phát hiện được ngay, trước khi hàng đợi cạn URL mới.

Thử lại đúng chỗ

Hàm dưới chỉ thử lại lỗi mạng và 5xx, thời gian chờ tăng dần, tối đa ba lần. Lỗi 403 và 400 đi thẳng ra ngoài.

import time, requests
 
def search_retry(q, tries=3):
    for i in range(tries):
        try:
            return search(q)
        except requests.exceptions.RequestException:
            if i == tries - 1:
                raise
            time.sleep(2 ** i)

Hàm search ở phần trước gọi raise_for_status, nên 5xx đi vào nhánh except, còn hai lỗi tự định nghĩa thì không.

Phân biệt lỗi của instance và lỗi của engine

Có hai tầng lỗi. Tầng một là instance: 403, 400, 500, không kết nối được. Tầng hai là engine bên trong: một phần kết quả thiếu nhưng mã vẫn 200. Hai tầng cần hai cảnh báo khác nhau. Tầng một cần người sửa ngay, tầng hai chỉ cần theo dõi tỷ lệ.

Chuẩn hóa kết quả có engine, source trong SearXNG API JSON nội bộ

Phần này biến JSON thô thành danh sách URL có thể đưa xuống bước tải.

Vì sao không đưa results thẳng vào hàng đợi

Kết quả từ nhiều engine có URL trùng, tham số theo dõi, host ngoài phạm vi và cả scheme không phải web. Đưa thẳng xuống bước tải là tải trùng và có thể đụng website không được phép. Vì vậy cần một lớp lọc ở giữa.

Hàm chuẩn hóa

Hàm dưới là mã đã chạy trong lab. Nó giữ danh sách host cho phép, bỏ tham số utm, gộp engine của các URL trùng, rồi giới hạn số kết quả.

import urllib.parse as U
 
def norm(d, allow=("fixture.local",), limit=10):
    seen, rej = {}, []
    for x in d["results"]:
        u = U.urlsplit(x["url"])
        if u.scheme not in ("http", "https"):
            rej.append((x["url"], "scheme"))
            continue
        if u.hostname not in allow:
            rej.append((x["url"], "host"))
            continue
        qs = [(k, v) for k, v in U.parse_qsl(u.query) if not k.startswith("utm_")]
        key = U.urlunsplit((u.scheme, u.hostname, u.path, U.urlencode(qs), ""))
        e = seen.setdefault(key, {"url": key, "title": x["title"], "engines": set(), "best": 0})
        e["engines"].update(x.get("engines") or [x["engine"]])
        e["best"] = max(e["best"], x.get("score", 0))
    out = sorted(seen.values(), key=lambda e: -e["best"])[:limit]
    for e in out:
        e["engines"] = sorted(e["engines"])
    return out, rej

Danh sách rej được giữ lại để biết vì sao một URL bị loại. Không có nó, người đọc nhật ký chỉ thấy số lượng giảm mà không hiểu lý do.

Kết quả chạy

Lọc kết quả

Lọc kết quả

Từ năm mục đầu vào, hàm giữ hai URL và loại hai mục. Hai mục đầu là cùng một trang, chỉ khác tham số utm_source, nên được gộp làm một với engines là e1 và e2.

Bảng: Kết quả chạy

URL gốc

Xử lý

Lý do

fixture.local/a?utm_source=x

Giữ, gộp

Bỏ tham số utm

fixture.local/a

Gộp vào mục trên

Cùng khóa sau chuẩn hóa

fixture.local/b

Giữ

Host được phép

blocked.local/c

Loại

Host ngoài danh sách

ftp://fixture.local/d

Loại

Scheme không phải web

Giữ lại nguồn gốc

Trường engines cho biết URL đến từ đâu. Khi một engine bắt đầu trả rác, anh em lọc theo trường này để khoanh vùng. Hãy lưu kèm truy vấn, số trang và thời điểm gọi. Sau vài tuần, câu hỏi hay gặp nhất là URL này từ truy vấn nào ra.

Đọc unresponsive_engines

Rỗng thật hay engine lỗi

Rỗng thật hay engine lỗi

Khóa này liệt kê engine không trả lời cùng lý do. Lab mô phỏng hai ca. Ca một trả 200 với hai kết quả và một engine timeout. Ca hai trả 200 với không kết quả và cả hai engine lỗi. Mã 200 trong ca hai không có nghĩa là truy vấn hết kết quả.

d = search("proxy")
if not d["results"] and d.get("unresponsive_engines"):
    raise RuntimeError(f"Engine loi: {d['unresponsive_engines']}")

Rỗng vì engine lỗi khác với rỗng vì không có kết quả. Nhầm hai thứ này, pipeline sẽ đánh dấu từ khóa đã hết trong khi nó chỉ gặp sự cố tạm thời.

Giới hạn gọi xuống phía sau

Tham số limit không chỉ để gọn. Mỗi URL giữ lại sẽ thành một lượt tải. Nếu mỗi truy vấn trả vài chục URL và có hàng nghìn từ khóa, số lượt tải tăng rất nhanh. Đặt trần cho từng truy vấn và từng host, rồi mới đưa vào hàng đợi.

Khi nào proxy xuất hiện trong chuyện này

Proxy không sửa được lỗi 403 của instance. Có hai chỗ proxy liên quan. Một là SearXNG có mục outgoing để cấu hình đường ra cho engine, ProxyVN chưa thử mục này. Hai là bước tải trang sau đó, phần được giải thích ở bài Web Scraping proxy là gì.

Tôn trọng dịch vụ phía sau

Instance của anh em vẫn gọi các công cụ tìm kiếm bên ngoài. Điều khoản của họ vẫn áp dụng, và họ có thể chặn IP máy chủ. Tài liệu SearXNG có cả trang hướng dẫn trả lời CAPTCHA từ IP máy chủ, cho thấy tình huống này có thật. Gọi vừa phải, cache kết quả, đừng dùng instance để cào hàng loạt.

Bộ nhớ đệm phía client

Cùng một truy vấn gọi lại trong vài phút hiếm khi có kết quả mới. Lưu phản hồi theo khóa q, pageno và language với thời hạn ngắn. Lab không đo hiệu quả của cache, nhưng nó giảm số lần instance phải gọi ra ngoài, tức giảm nguy cơ bị chặn.

Chuẩn hóa URL cẩn thận tới đâu

Hàm trong lab chỉ bỏ tham số utm và phần fragment. Website thật còn có tham số phiên, tham số sắp xếp, dấu gạch chéo cuối đường dẫn. Đừng bỏ mọi tham số, vì nhiều trang dùng query để phân biệt nội dung. Danh sách tham số cần bỏ nên đặt theo từng host, viết thành cấu hình.

Lưu kết quả thành bản ghi có cấu trúc

Mỗi URL giữ lại nên thành một bản ghi JSON Lines, kèm truy vấn và thời điểm gọi. Định dạng này dễ nối thêm, dễ đọc lại bằng script và dễ đối soát.

{"url": "http://fixture.local/a", "engines": ["e1", "e2"], "query": "proxy", "pageno": 1, "fetched_at": "2026-11-04T08:00:00Z"}

Bản ghi trên là mẫu đầu ra của lab. Cột fetched_at giúp biết kết quả cũ tới đâu, vì cùng truy vấn sau một tuần có thể ra URL khác.

Khóa trùng giữa nhiều truy vấn

Hàm norm chỉ khử trùng trong một phản hồi. Khi chạy hàng trăm từ khóa, cùng một URL sẽ quay lại nhiều lần. Bảng URL đã thấy nên nằm ở kho dữ liệu của pipeline, dùng khóa URL đã chuẩn hóa. Như vậy URL mới mới đi xuống hàng đợi, URL cũ chỉ cập nhật thời điểm thấy lại.

Đầu ra nghiệm thu của SearXNG API JSON nội bộ

Phần này gom các tiêu chí để biết công việc đã xong.

Danh sách kiểm tra

Một lần triển khai đạt khi qua hết các dòng dưới đây.

  • search.formats có json và chỉ có những format thật sự dùng.
  • secret_key đã đổi, bind_address đúng mạng cần phục vụ.
  • Gọi format=json trả 200 với Content-Type là JSON.
  • Client tách riêng 403, 400, 5xx và lỗi Content-Type.
  • Hàm chuẩn hóa có danh sách host cho phép và trả về lý do loại.
  • Pipeline phân biệt rỗng thật với rỗng do engine lỗi.
  • Có trần số URL theo truy vấn và theo host.

Bảng lỗi thường gặp

Bảng lỗi nhanh

Bảng lỗi nhanh

Bảng này giúp người trực xử lý nhanh mà không phải đọc lại toàn bài.

Bảng: Bảng lỗi thường gặp

Triệu chứng

Nguyên nhân khả dĩ

Việc cần làm

403 khi format=json

json chưa có trong formats

Sửa settings.yml, khởi động lại

200 nhưng lỗi giải mã JSON

Sai tên format, rơi về html

Kiểm tra tham số và Content-Type

400 No query

q rỗng

Lọc dòng trắng trong tệp từ khóa

200, results rỗng

Engine lỗi hoặc hết kết quả

Đọc unresponsive_engines

Lỗi kết nối từ máy khác

bind_address là 127.0.0.1

Dùng reverse proxy nội bộ

Những gì lab chưa chạy

Danh sách này quan trọng ngang kết quả. Chưa chạy SearXNG thật, chưa gọi engine nào, chưa thử limiter với valkey, chưa thử mục outgoing, chưa đo độ trễ. Bộ khóa JSON chưa đối chiếu với instance thật. Trước khi dùng, anh em chạy lại bảng đối chiếu trên instance của mình.

Cách tái lập trên instance thật

Khi có instance, chỉ cần đổi biến BASE trong client. Chạy lần lượt bảy ca ở bảng đối chiếu, ghi mã và Content-Type vào một tệp. So với bảng trong bài, chỗ nào khác thì tin kết quả của instance, vì phiên bản SearXNG đổi liên tục.

Ghi nhật ký tối thiểu

Mỗi lần gọi nên ghi truy vấn, mã trạng thái, số kết quả, danh sách engine lỗi và thời gian phản hồi. Bộ năm trường này đủ để trả lời hầu hết câu hỏi vận hành. Đừng ghi cả phản hồi vào nhật ký, vì nó phình rất nhanh.

Bước tiếp theo sau khi có URL

URL sạch đi vào hàng đợi crawl, nơi có giới hạn tốc độ riêng. Với website được phép thu thập, có lúc cần IP tại Việt Nam để nhận đúng nội dung trong nước. Khi đó anh em có thể mua proxy Việt Nam tại trang chủ ProxyVN. Proxy không làm SearXNG trả kết quả tốt hơn, nó chỉ thuộc về bước tải trang. Cách ghi thông tin proxy vào cấu hình worker có ở bài định dạng proxy.

SearXNG API JSON nội bộ: câu hỏi thường gặp

Các câu dưới đây gom những điểm anh em hay hỏi khi triển khai.

Vì sao gọi format=json nhận 403?

Vì json chưa có trong search.formats của settings.yml. Tài liệu ghi rõ yêu cầu một format chưa đặt sẽ nhận 403 Forbidden. Thêm json vào danh sách rồi khởi động lại dịch vụ.

SearXNG có cần khóa API không?

Endpoint /search trong tài liệu không có tham số khóa. Việc kiểm soát ai được gọi nằm ở mạng và reverse proxy. Vì thế instance bật JSON không nên mở ra Internet nếu không có lớp chặn phía trước.

Có nên dùng instance công cộng cho pipeline không?

Không nên. Tài liệu cảnh báo nhiều instance công cộng đã tắt các format này, và chủ instance không dựng máy để phục vụ gọi tự động của người khác. Tự dựng một instance là cách làm đàng hoàng hơn.

Bài này đã chạy trên SearXNG thật chưa?

Chưa. Máy chủ trong lab là mô phỏng theo webapp.py, chỉ client và hàm chuẩn hóa chạy thật. Hành vi 403 có trong tài liệu chính thức, còn lại anh em nên kiểm trên instance của mình.

Tại sao results rỗng mà mã vẫn 200?

Vì request đã được xử lý xong. Có thể truy vấn không có kết quả, cũng có thể mọi engine đều lỗi. Đọc unresponsive_engines để phân biệt, đừng kết luận chỉ từ mã trạng thái.

Proxy có sửa được lỗi 403 không?

Không. Lỗi này do cấu hình instance. Đổi IP không thay đổi danh sách formats, nên đừng tốn thời gian thử.

Instance có lưu truy vấn không?

Lab không kiểm tra điều này. Với instance tự quản, nhật ký của reverse proxy là nơi dễ lộ truy vấn nhất. Dùng POST và rà lại cấu hình ghi log nếu truy vấn có thông tin nhạy cảm.

Nên bật csv hay rss không?

Chỉ khi có người dùng thật. Pipeline đọc JSON thì giữ danh sách formats ngắn. Lab cho thấy format chưa bật sẽ bị từ chối, nên thêm sau cũng chỉ mất một dòng cấu hình.

SearXNG API JSON nội bộ và những điều cần nhớ

SearXNG API JSON nội bộ chỉ chạy khi json nằm trong search.formats, thiếu dòng đó sẽ nhận 403 dù trang web vẫn mở được. Client cần tách 403, 400 và lỗi Content-Type, còn kết quả phải qua lọc host trước khi tải. Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam sẽ cập nhật khi chạy được trên instance thật của SearXNG API JSON nội bộ.

TIN TỨC LIÊN QUAN