GeoNames API địa danh: feature code, hierarchy và ca trùng tên
GeoNames API địa danh là cách chuẩn hóa tên xã, huyện, thành phố về một mã số ổn định kèm loại đối tượng. Bài này viết cho người có cột địa danh lộn xộn cần ghép với bảng khác. ProxyVN gọi API thật nhưng tài khoản demo đã hết lượt, nên lab đọc bản dump công khai của Việt Nam ngày 05/11/2026 với 67146 địa danh và đếm các ca trùng tên.
GeoNames API địa danh: 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à điểm khác với các bài địa lý còn lại.
Bài toán cần giải
Một nhóm dữ liệu có cột "địa điểm" do người dùng gõ, gồm cả tên tỉnh, tên quận, tên xã, có dấu và không dấu. Họ cần gom về một mã để đếm theo tỉnh. Tên "Tân Bình" xuất hiện rất nhiều, và họ ghép thẳng vào quận Tân Bình ở TP.HCM. Kết quả là số liệu của một xã ở Đắk Lắk bị tính cho thành phố khác.
Đầu ra nghiệm thu
Đầu ra là bảng mapping gồm tên gốc, geonameId, featureClass, featureCode, mã admin, tên đơn vị cấp trên và trạng thái ghép. Bảng phải có nhóm riêng cho ca nhiều ứng viên và ca không đủ thông tin. Một dòng chưa chắc thì để trống mã, không đoán.
Ranh giới với geocoding địa chỉ và geo IP
Bài Nominatim trong cụm này đổi một địa chỉ chi tiết thành tọa độ. Bài IP geolocation suy vị trí từ địa chỉ IP. Bài này không làm hai việc đó. Nó dùng loại đối tượng và cấp hành chính để phân biệt các tên địa danh, không cần số nhà và không cần IP.
Giới hạn của lab
Lab gọi searchJSON với tài khoản demo và nhận thông báo đã vượt hạn mức ngày. Lab không đăng ký tài khoản. Vì vậy các đoạn gọi API trong bài là ví dụ theo tài liệu, lab chưa nhận được response thành công. Số liệu thật đến từ bản dump chính thức tại download.geonames.org, cùng nguồn dữ liệu với API.
Ai nên đọc
Bài hợp với người làm sạch dữ liệu khách hàng, nhóm phân tích theo địa bàn, sinh viên làm đề tài có cột địa danh. Người làm việc với nhiều quốc gia nên đọc kỹ phần trùng tên quốc tế. Người chỉ cần 34 tỉnh thành Việt Nam có thể dùng một bảng tự dựng nhỏ thay vì gọi API.
Những gì bài không làm
Bài không xác nhận ranh giới hành chính nào là chính thức. Danh mục đơn vị hành chính Việt Nam do cơ quan nhà nước công bố, GeoNames là cơ sở dữ liệu cộng đồng. Bài cũng không vẽ bản đồ.
Thuật ngữ dùng trong bài
GeonameId là mã số của một địa danh. Feature class là nhóm lớn một ký tự, như P cho khu dân cư, A cho đơn vị hành chính. Feature code là loại chi tiết, như PPL, PPLC, ADM1. Admin code là mã cấp hành chính gắn trên từng dòng. Hierarchy là quan hệ cha con giữa các địa danh.
Chuẩn hóa địa danh với feature code và hierarchy GeoNames API địa danh
Phần này đi từ lời gọi API tới bản dump, vì cả hai đều cần nếu anh em làm nghiêm túc.
Nguồn tài liệu đã đọc
Lab đọc danh sách web service của GeoNames, trang tham số search, trang mã lỗi và readme của bản dump. Readme ghi dữ liệu theo giấy phép Creative Commons Attribution 4.0, nên phải ghi nguồn GeoNames khi dùng.
Ba kết quả khi gọi không đúng tài khoản
Lab gọi ba biến thể của cùng một truy vấn. Không có username thì nhận HTTP 401 với lời nhắc thêm username cho mỗi lời gọi. Username không tồn tại thì nhận HTTP 401 và thông báo user does not exist, value 10. Username demo thì nhận HTTP 200 kèm khối status báo vượt 20000 credit ngày của demo.
HTTP 200 vẫn có thể là lỗi
Ca demo là ca cần chú ý nhất. HTTP trả 200, nhưng thân JSON có khối status thay vì geonames. Script chỉ kiểm mã HTTP sẽ đọc khóa geonames, nhận KeyError hoặc hiểu là không có kết quả. Hàm đọc phải kiểm status trước.
import os, requests
U = os.environ["GEONAMES_USER"]
def gn(path, **p):
p["username"] = U
r = requests.get("https://secure.geonames.org/" + path, params=p, timeout=30)
j = r.json()
if "status" in j:
raise RuntimeError((j["status"].get("value"), j["status"].get("message")))
return j
Đoạn này là ví dụ theo tài liệu, chưa chạy thành công vì thiếu tài khoản. Trang mã lỗi liệt kê các giá trị status. Anh em nên ghi value vào log để phân biệt lỗi tài khoản với lỗi hạn mức.
Username và hạn mức
Trang export ghi hạn mức ngày 10000 credit cho mỗi ứng dụng, xác định bằng tham số username, và hạn mức giờ 1000 credit. Trang tài liệu nói demo không dành cho ứng dụng. Anh em tạo tài khoản riêng, bật web service trong trang tài khoản, rồi đọc tên từ biến môi trường. Một lời gọi có thể tốn hơn một credit tùy dịch vụ.
Dump dùng khi nào
Bản dump theo quốc gia không cần tài khoản và không tốn credit. VN.zip của lab chỉ gần 2 MB, chứa 67146 dòng và 19 cột. Với bài toán chuẩn hóa một danh sách tên trong nước, tìm trong dump cục bộ nhanh hơn và không lộ dữ liệu ra ngoài. API hợp khi cần tra lẻ từ ứng dụng hoặc cần dữ liệu mới theo ngày.
import zipfile
z = zipfile.ZipFile("VN.zip")
R = [l.split("\t") for l in z.read("VN.txt").decode().splitlines()]
print(len(R), len(R[0]))
print(R[0][:3])
Output thật là 67146, 19 và dòng đầu 1559966, Ia Zouei, Ia Zouei. Các cột quan trọng theo chỉ số gồm 0 geonameid, 1 name, 2 asciiname, 3 alternatenames, 6 feature class, 7 feature code, 10 admin1, 11 admin2, 14 population, 17 timezone, 18 modification date.
Tệp đi kèm
Readme mô tả admin1CodesASCII.txt, admin2Codes.txt, featureCodes_en.txt và hierarchy.zip. Lab tải cả bốn tệp, đều có Last-Modified trong sáng 05/11/2026 giờ UTC, tức bản dump được dựng theo ngày. Tệp modifications theo ngày giúp đồng bộ mà không tải lại toàn bộ.
Giấy phép và ghi nguồn
CC BY 4.0 cho phép dùng lại kèm ghi công. Bảng công bố cần có tên GeoNames và đường dẫn. Bảng cũng nên ghi ngày của bản dump, vì tên và mã có thể đổi sau đó.
Chọn webservice, username và feature class, code cho GeoNames API địa danh
Feature code là phần mà tên gọi không làm được. Mục này cho thấy dữ liệu Việt Nam thật sự gồm những gì.
Bức tranh dữ liệu Việt Nam

Feature code lọc ứng viên
Lab đếm cột class và code. Mười loại lớn nhất chiếm phần lớn bảng. Con số dưới đây là của bản dump ngày lab tải.
Code |
Nghĩa |
Số dòng |
|---|---|---|
P.PPL |
Khu dân cư |
40540 |
A.ADM3 |
Đơn vị cấp 3 |
10579 |
H.STM |
Sông suối |
4310 |
T.MT |
Núi |
3373 |
S.HTL |
Khách sạn |
1178 |
H.CNL |
Kênh |
854 |
T.HLL |
Đồi |
837 |
A.ADM2 |
Đơn vị cấp 2 |
723 |
P.PPLA2 |
Thủ phủ cấp 2 |
545 |
T.ISL |
Đảo |
478 |
Đọc bảng để chọn bộ lọc
Một phần đáng kể của bảng là sông, núi, khách sạn. Tên "Hoàng Liên" có thể là núi, tên "Sông Cầu" có thể là suối. Nếu cột của anh em là nơi ở, chỉ giữ class P và A. Bộ lọc này loại rất nhiều ứng viên vô nghĩa ngay từ đầu.
Cấp hành chính hiện hành và lịch sử
Bản dump có 34 dòng ADM1 và 54 dòng ADM1H. Hậu tố H nghĩa là đơn vị lịch sử, không còn hiệu lực. Long An nằm trong nhóm ADM1H với mã x24, cùng Bình Dương, Bà Rịa-Vũng Tàu và các tỉnh đã sáp nhập khác. Dữ liệu cũ ghi tên tỉnh trước sáp nhập vẫn tìm được, nhưng nó trả về một đơn vị lịch sử.
Mã admin1 không phải mã cũ của anh em
Trong bản dump, Hà Nội có admin1 là 01, Đà Nẵng 48, TP.HCM 79. Các mã lịch sử có tiền tố x, như x24 hay x20. Tổng cộng 52 dòng có mã x và 16 dòng không có admin1. Không ghép mã này với mã tỉnh của Tổng cục Thống kê hoặc mã nội bộ khi chưa có bảng đối chiếu.
Tham số search cần dùng
Trang tham số mô tả q tìm trên mọi thuộc tính, name chỉ tìm trong tên, name_equals tìm tên khớp đúng. Tham số featureClass và featureCode lặp được nhiều lần. Tham số country giới hạn quốc gia. Tham số fuzzy từ 0 tới 1 nới độ khớp, mặc định 1. Tham số isNameRequired yêu cầu ít nhất một từ nằm trong tên.
j = gn("searchJSON", name_equals="Tân Bình", country="VN",
featureClass=["P", "A"], maxRows=30, style="FULL")
for g in j["geonames"]:
print(g["geonameId"], g["name"], g["fcode"], g.get("adminName1"))
Requests tự lặp tham số khi giá trị là danh sách, khớp cách tài liệu mô tả. Đoạn này chưa chạy được, anh em chạy thử khi có username.
Vì sao tránh q cho chuẩn hóa
Tham số q tìm trên cả tên quốc gia, châu lục, mã admin. Tài liệu minh họa: tìm Berlin bằng tìm kiếm thường sẽ trả mọi nơi trong bang Berlin. Với chuẩn hóa tên, name_equals hoặc name kèm isNameRequired an toàn hơn. Càng chặt thì càng ít kết quả rác cần duyệt.
Múi giờ trong dữ liệu Việt Nam
Cột timezone cho một bất ngờ nhỏ. Có 38520 dòng ghi Asia/Bangkok và 28591 dòng ghi Asia/Ho_Chi_Minh, cùng vài dòng múi giờ nước khác và 28 dòng rỗng. Asia/Bangkok và Asia/Ho_Chi_Minh hiện cùng UTC+7, nên giờ không sai, nhưng đừng dùng cột này để suy ra quốc gia. Đây là ví dụ cho thấy cơ sở dữ liệu cộng đồng có những trường không đồng nhất.
Dân số chỉ là chỉ báo yếu
Có 41416 dòng class P có population bằng 0. Giá trị 0 ở đây là chưa có số, không phải không có người. Dùng dân số để xếp hạng ứng viên chỉ có tác dụng với các đô thị lớn. Với xã và thôn, dân số gần như không phân biệt được gì.
Tìm địa danh theo quốc gia hoặc hierarchy với GeoNames API địa danh
Phần này dùng cấp trên để thu hẹp ứng viên, cách làm đáng tin hơn đoán theo tên.
Thu hẹp bằng admin1

Lọc theo cấp trên
Khi địa chỉ có tên tỉnh, anh em đổi tỉnh sang admin1 rồi lọc. Lab thử Thanh Hóa với admin1 38 và còn đúng hai ứng viên: tỉnh ADM1 và thành phố PPLA. Không lọc thì tên Thanh Hoa có 22 dòng theo asciiname trên toàn quốc. Một cột tỉnh giảm việc duyệt đi rất nhiều.
Hàm tìm của lab
Hàm dưới bỏ dấu, tìm trong asciiname và alternatenames, chỉ giữ class P và A. Đây là cách tìm trên dump, không gọi mạng.
import unicodedata
def strip(s):
s = s.replace("đ", "d").replace("Đ", "D")
t = unicodedata.normalize("NFD", s)
return "".join(x for x in t if not unicodedata.combining(x)).lower()
def find(name, admin1=None, cls=("P", "A")):
q = strip(name)
m = [r for r in R if r[6] in cls and
(strip(r[2]) == q or q in [strip(x) for x in r[3].split(",")])]
if admin1:
m = [r for r in m if r[10] == admin1]
return m
Chữ đ phải đổi tay vì NFD không tách được ký tự này. Thiếu bước đó thì "Đà Nẵng" không khớp "Da Nang". Lỗi này rất hay gặp với dữ liệu tiếng Việt.
Kết quả mười đầu vào
Bảng dưới là output thật của hàm find trên bản dump, số ứng viên và ứng viên đứng đầu theo thứ tự cấp hành chính rồi dân số.
Đầu vào |
Số ứng viên |
Loại |
Ứng viên đầu |
|---|---|---|---|
Hoàn Kiếm |
2 |
ADM2, PPLA2 |
1905127 Quận Hoàn Kiếm |
Hà Nội |
3 |
ADM1, PPLC, PPL |
1581130 Hanoi, PPLC |
Tân Bình |
26 |
PPL 25, PPLX 1 |
1567039, Đắk Lắk |
Tân Bình, admin1 20 |
0 |
không có |
không có |
Long An |
6 |
PPL 5, ADM1H 1 |
1575789, Đồng Tháp |
Phú Thọ |
38 |
PPL 34, ADM1H, ADM3, PPLA2 |
13494345 ADM1 |
Thanh Hóa, admin1 38 |
2 |
ADM1, PPLA |
1566165 tỉnh |
Sài Gòn |
3 |
PPL 2, ADM2 |
8336104 Phường Sài Gòn |
Thủ Đức |
2 |
PPLA2, PPL |
1565019, TP.HCM |
Xã Không Có |
0 |
không có |
không có |
Xếp hạng tự động dễ sai
Lab xếp ứng viên theo cấp rồi dân số để minh họa. Với "Sài Gòn", ứng viên đầu là Phường Sài Gòn, không phải thành phố. Với "Long An", ứng viên đầu là một làng ở Đồng Tháp, trong khi người nhập nhiều khả năng đang nói tới tỉnh cũ. Với "Tân Bình", ứng viên đầu ở Đắk Lắk. Thứ tự này chỉ để gợi ý, không được dùng làm kết quả cuối.
Hai đối tượng cho cùng một nơi
Hoàn Kiếm có ADM2 1905127 và PPLA2 8616124, cùng dân số 135618. Hà Nội có ADM1 1581129 và PPLC 1581130. Một bên là đơn vị hành chính, một bên là khu dân cư. Dự án phải chốt mình cần loại nào, rồi dùng nhất quán. Đếm theo tỉnh dùng ADM1, đặt ghim thành phố dùng PPLC.
Hierarchy trong API
Dịch vụ hierarchyJSON nhận geonameId và trả chuỗi từ Trái Đất xuống địa danh. Dịch vụ childrenJSON trả các đơn vị con. Khi có tài khoản, đây là cách đọc cấp trên gọn nhất. Hai dịch vụ này có trong danh sách web service, lab chưa gọi được.
Hierarchy trong dump thưa hơn nghĩ
Tệp hierarchy.zip có 506606 dòng toàn cầu. Readme nói quan hệ giữa địa danh thường và cấp hành chính không nằm trong tệp, phải dựng từ admin code. Lab xác nhận: Hoàn Kiếm 8616124 không có cha trong tệp. Với Việt Nam, 7795 dòng có cha, gồm 7497 đơn vị hành chính trên tổng 11434.
Dựng cấp trên từ admin code
Vì vậy lab đọc cấp trên từ cột admin1 và admin2 rồi tra tệp mã. Cách này không cần tệp hierarchy. Khóa tra admin1 là VN.01, khóa admin2 là VN.01.002. Hoàn Kiếm 8616124 có admin1 01, admin2 002, tra ra Hà Nội.
A1 = {}
for l in open("admin1CodesASCII.txt", encoding="utf-8").read().splitlines():
k, n, a, g = l.split("\t")
A1[k] = {"name": n, "ascii": a, "geonameId": g}
r = next(x for x in R if x[0] == "8616124")
print(r[1], r[7], A1["VN." + r[10]]["name"])
Đoạn trên chạy trên tệp thật, in ra Hoàn Kiếm, PPLA2, Hanoi. Tệp admin1 có 34 khóa VN, không có khóa cho mã x, nên đơn vị lịch sử cần một nhánh xử lý riêng.
Phân biệt kết quả cùng tên nhưng khác cấp hành chính trong GeoNames API địa danh
Dữ liệu cho thấy trùng tên không phải ngoại lệ mà là chuyện bình thường.
Trùng tên trong nước

Tên trùng là bình thường
Trong class P có 41977 dòng và 26736 tên khác nhau theo asciiname. Có 5118 tên xuất hiện từ hai lần trở lên, chiếm 20359 dòng. Nghĩa là gần một nửa số khu dân cư mang một tên trùng với nơi khác. Tên phổ biến nhất là Ấp Một 144 lần, Ấp Hai 142 lần, Ấp Ba 142 lần, Thôn Hai 109 lần, Thôn Một 104 lần.
Trùng tên giữa các cấp
Tên Phú Thọ có 38 ứng viên qua hàm find: 34 PPL, một PPLA2, một ADM3, một ADM1H, cùng ADM1 Phu Tho mới. Người nhập "Phú Thọ" có thể đang chỉ tỉnh mới, tỉnh cũ, thị xã cũ hay một xã. Chỉ có ngữ cảnh mới phân biệt được. Không có ngữ cảnh thì dòng đó đúng là không đủ thông tin.
Trùng tên khác quốc gia
Lab đọc cities15000, bản gồm 34204 thành phố có dân số từ 15000 trở lên trên thế giới. Tên San Jose có 9 kết quả tại Philippines, Costa Rica, Guatemala, Mỹ, Uruguay, Venezuela. Georgetown có 8 kết quả, Cambridge 6, Valencia 6, Tripoli 3 tại Hy Lạp, Lebanon, Libya.
Tên |
Số kết quả |
Quốc gia |
Lớn nhất theo dân số |
|---|---|---|---|
San Jose |
9 |
PH 3, CR 2, GT, US, UY, VE |
5392171, US, 997368 |
Georgetown |
8 |
US 3, CA, GD, GY, KY, MY |
3378644, GY, PPLC |
Cambridge |
6 |
US 2, CA, GB, NZ, UA |
2653941, GB |
Valencia |
6 |
EC, ES, FR, PH, US, VE |
3625549, VE |
Tripoli |
3 |
GR, LB, LY |
2210247, LY, PPLC |
Dân số lớn nhất không phải câu trả lời
San Jose thủ đô Costa Rica có 335007 người theo cột population, San Jose ở Mỹ có 997368. Nếu bảng là về Trung Mỹ, chọn theo dân số sẽ sai nước. Valencia ở Venezuela lớn hơn Valencia ở Tây Ban Nha trong dữ liệu, nhưng khách du lịch châu Âu gần như nói về bên kia. Luôn lọc quốc gia trước khi xếp hạng.
Tên thay thế cứu được gì
Cột alternatenames cho phép "Saigon" và "Thanh Pho Ho Chi Minh" đều trỏ về 1566083 Ho Chi Minh City. Đây là giá trị lớn của GeoNames với dữ liệu người dùng gõ. Nhưng tên thay thế cũng làm tăng ứng viên: tìm Paris trong cities15000 ra cả Parys ở Nam Phi.
Trường hợp TP.HCM là PPL
Dòng 1566083 có feature code PPL, không phải PPLA hay PPLC, dù dân số ghi 14002598. Bộ lọc chỉ giữ PPLA và PPLC sẽ bỏ sót thành phố lớn nhất nước. Đừng suy cấp bậc của một đô thị chỉ từ feature code. Với các thành phố lớn, nên có danh sách ghim thủ công.
Quy tắc ra quyết định
Lab chia ba trạng thái. Không có ứng viên thì ghi khong_co. Một ứng viên sau khi lọc đủ quốc gia, tỉnh và loại thì ghi mot. Nhiều ứng viên thì ghi nhieu và chuyển người duyệt. Tân Bình không có tỉnh rơi vào nhieu, và đó là kết quả đúng của quy trình.
def decide(name, country_ok=True, admin1=None, want=("P", "A")):
m = find(name, admin1, want)
if not m:
return "khong_co", None
if len(m) == 1:
return "mot", m[0][0]
return "nhieu", [x[0] for x in m[:10]]
Kết quả nhieu mang theo tối đa mười geonameId để người duyệt xem. Số mười là tự đặt để bảng tính dễ đọc.
Xã không tìm thấy trong tỉnh đã cho
Tân Bình với admin1 20 trả 0 ứng viên. Có thể tỉnh nhập sai, có thể địa danh không có trong dữ liệu, có thể mã admin đã đổi sau sáp nhập. Lab không tự nới bộ lọc. Dòng này vào nhóm cần xem lại, để con người quyết định.
Xuất mapping geonameId và ca không đủ thông tin để ghép trong GeoNames API địa danh
Phần này biến quy trình thành bảng dùng được, kèm cách giữ ổn định qua thời gian.
Cột của bảng mapping
Bảng giữ tên gốc y nguyên, tên đã bỏ dấu, tỉnh gốc nếu có, geonameId đã chọn, feature code, admin1, tên cấp trên, trạng thái và ai chọn. Dòng chưa đủ thông tin để geonameId trống. Thà có 10 phần trăm dòng trống còn hơn 10 phần trăm dòng sai không ai biết.
Ghi người chọn
Cột chosen_by có hai giá trị: luat hoặc nguoi. Dòng do người chọn không bị ghi đè khi chạy lại. Kết quả duyệt là tài sản của dự án, nên lưu trong tệp riêng và nạp sau bước tự động. Cách này giữ công sức duyệt qua các lần cập nhật dump.
Theo dõi thay đổi của dump
Cột modification date cho biết 64576 dòng được sửa trong năm 2025 và 476 dòng trong năm 2026. Nhóm 2025 trải đều trên mọi loại đối tượng, kể cả núi và sông, nên có vẻ là một đợt cập nhật hàng loạt. Nhóm 2026 có 154 PPL, 109 PPLA2, 53 ADM1H và 51 PPLA. Lab không biết lý do của từng lần sửa. Sau mỗi lần tải dump mới, anh em so feature code và admin1 của các geonameId đã chọn. Dòng đổi được đưa lại vào hàng duyệt.
Khi geonameId bị xóa
Readme có tệp deletes theo ngày. Một mã đã chọn có thể biến mất nếu bị gộp với bản ghi khác. Phép kiểm đơn giản là mọi geonameId trong bảng mapping phải còn trong dump mới. Lab chưa gặp ca này vì chỉ dùng một ngày dữ liệu.
Chuẩn bị cột đầu vào
Trước khi ghép, anh em làm sạch cột gốc ở mức tối thiểu. Bỏ tiền tố như "Xã", "Phường", "TP.", "Tỉnh" vào một cột riêng thay vì xóa, vì tiền tố đó cho biết cấp. Chuỗi "Phường Tân Bình" gợi ý cấp xã phường, còn "Quận Tân Bình" gợi ý cấp huyện. Cột cấp gợi ý này giúp lọc ứng viên theo feature code.
Gom trước rồi mới tra
Một cột trăm nghìn dòng thường chỉ có vài nghìn giá trị khác nhau. Anh em gom giá trị duy nhất, tra một lần, rồi ghép ngược vào bảng lớn. Với API, cách này tiết kiệm credit rất nhiều. Với dump, nó giảm số dòng người phải duyệt.
Đo chất lượng ghép
Sau mỗi lần chạy, anh em ghi số dòng theo từng trạng thái, tính theo cả giá trị duy nhất và theo số dòng gốc. Một tên chưa ghép có thể chiếm rất nhiều dòng, nên ưu tiên duyệt theo tần suất. Lấy mẫu vài chục dòng trạng thái mot rồi kiểm tay để biết luật có đang chọn nhầm hay không. Con số đó nên nằm trong báo cáo đi kèm bảng.
Dữ liệu ngoài danh mục
Thôn, ấp, khu phố thường không đủ trong GeoNames, và tên như Ấp Một lặp rất nhiều. Với cấp này, mã xã là mức chi tiết thực tế có thể đạt được. Anh em nên dừng ở cấp cao hơn thay vì ép ghép vào một ứng viên ngẫu nhiên.
Ghi lại quyết định bỏ qua
Dòng cố ý không ghép cần lý do ngắn trong cột ghi chú, ví dụ thiếu tỉnh hoặc tên quá chung, để người sau không làm lại từ đầu.
Tải bằng script
Tải dump không cần tài khoản, chỉ cần một GET cho mỗi tệp và nên kiểm Last-Modified trước. Bản toàn cầu lớn, còn bản theo quốc gia rất nhẹ. Lab tải sáu tệp, tổng khoảng 10 MB.
Proxy có cần không
Với dump thì không. Với API, hạn mức gắn theo username, nên đổi IP không tạo thêm credit, và dùng nhiều tài khoản để lách là trái ý nhà cung cấp. Cách đặt nhịp có ở bài rate limit API khi dùng proxy. Nhu cầu lớn thì tài liệu có gói premium.
Khi mạng buộc đi qua cổng ra
Nếu mạng công ty bắt buộc, anh em khai báo ở session, chuỗi theo định dạng proxy. Bài toán chuẩn hóa tên chạy offline nên không liên quan tới proxy. Phân biệt vai trò các lớp mạng có ở bài Web Scraping proxy là gì.
Tác vụ khác cần IP Việt Nam thì anh em có thể mua proxy tốc độ cao tại trang chủ ProxyVN.
Khóa phiên bản
Lab chạy Python 3.12.10 với thư viện chuẩn cho phần dump, dữ liệu ngày 05/11/2026. Mapping phải ghi ngày dump, vì cùng một tên có thể đổi cấp sau mỗi đợt sắp xếp đơn vị hành chính. Lưu VN.zip của ngày chốt cùng dự án để tái lập.
Đầu ra nghiệm thu mapping tên địa danh, geonameId, featureCode và ca trùng tên của GeoNames API địa danh
Mục này chốt bảng và danh sách kiểm.
Schema của bảng

Nghiệm thu mapping
Cột |
Ví dụ thật |
Ghi chú |
|---|---|---|
name_raw |
Hoàn Kiếm |
Không sửa |
name_norm |
hoan kiem |
Bỏ dấu, đ thành d |
admin1_hint |
01 |
Từ cột tỉnh nếu có |
geonameId |
1905127 |
Có thể trống |
feature_code |
ADM2 |
Dự án chốt loại cần |
parent_admin1 |
Hanoi |
Tra từ admin1 |
status |
nhieu |
khong_co, mot, nhieu |
chosen_by |
nguoi |
luat hoặc nguoi |
dump_date |
2026-11-05 |
Ngày dữ liệu |
Danh sách kiểm
- Lọc class: chỉ giữ P và A khi cột là nơi ở.
- Quốc gia: lọc trước khi xếp hạng.
- Lịch sử: phân biệt ADM1 với ADM1H.
- Loại đối tượng: chốt dùng ADM hay PPL cho từng mục đích.
- Không đoán: nhiều ứng viên thì chuyển người duyệt.
- Nguồn: có GeoNames, CC BY 4.0, ngày dump.
Câu kết luận được phép viết
Từ lab có thể viết rằng gần một nửa số khu dân cư trong dump mang tên trùng nơi khác. Tên tỉnh cũ trả về đơn vị lịch sử. Hierarchy trong dump không đủ cho mọi địa danh. Không nên viết rằng dữ liệu GeoNames phản ánh đúng đơn vị hành chính hiện hành, vì lab không đối chiếu văn bản nhà nước.
Những gì lab chưa chạy
Lab chưa nhận được response thành công từ API. Tên trường trong JSON của API như fcode, adminName1 lấy từ tài liệu và cần kiểm lại. Lab chưa thử hierarchyJSON, childrenJSON, chưa so API với dump, chưa dùng alternateNamesV2. Anh em có username nên chạy lại ba đoạn code API trước khi tin vào chi tiết.
Tên địa danh trùng nhau là chuyện bình thường. Khóa đúng là geonameId, còn dòng chưa đủ thông tin thì để trống thay vì đoán.
GeoNames API địa danh: câu hỏi thường gặp
Các câu dưới đây gom những điểm hay bị hỏi.
Dùng username demo được không?
Không nên. Lab nhận thông báo demo đã vượt hạn mức ngày, và tài liệu dặn không dùng cho ứng dụng.
Lỗi hạn mức có trả 429 không?
Trong lab, demo hết hạn mức trả HTTP 200 kèm khối status. Script phải đọc khối đó.
Nên dùng API hay dump?
Danh sách tên trong một nước thì dump nhanh và riêng tư hơn. Tra lẻ trong ứng dụng thì API tiện hơn.
Long An ra ADM1H nghĩa là gì?
Đó là đơn vị lịch sử trong dữ liệu. Tên cũ vẫn tìm được, nhưng không phải cấp tỉnh hiện hành của bản dump.
Population bằng 0 có nghĩa gì?
Với class P, gần như nghĩa là chưa có số. Không dùng để kết luận nơi đó không có người.
Vì sao "Đà Nẵng" không khớp sau khi bỏ dấu?
Vì NFD không tách chữ đ. Phải đổi đ thành d trước.
Có nên chọn ứng viên dân số lớn nhất không?
Không nên làm mặc định. Lọc quốc gia và tỉnh trước, nhiều ứng viên thì để người duyệt.
GeonameId có đổi không?
Mã thường ổn định, nhưng bản ghi có thể bị xóa hoặc gộp. Kiểm mapping sau mỗi lần tải dump.
GeoNames API địa danh và những điều cần nhớ
GeoNames API địa danh hữu ích khi anh em lọc theo quốc gia và cấp trên, phân biệt ADM với PPL, tách đơn vị lịch sử và để trống dòng chưa đủ thông tin. Tên trùng là chuyện bình thường. Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam khuyên anh em ghi ngày dump khi dùng GeoNames API địa danh.