我需要使用 openstreet 地图或谷歌地图从特定国家/地区检索所有城市名称。有可用的 API 吗?
或者有没有其他方法可以获得这个世界地理数据?
我需要使用 openstreet 地图或谷歌地图从特定国家/地区检索所有城市名称。有可用的 API 吗?
或者有没有其他方法可以获得这个世界地理数据?
您绝对应该检查 GeoNames。他们在一个标准化的数据库中拥有整个世界。您可以下载它或使用他们的API。
我下载美国数据库并使用我在 C# 中创建的连接器在我的数据库中插入州、城市、城镇和邮政编码。
public static class GeoNamesConnector
{
#region GeoName Constants
private static readonly string GeoNamesPath = HttpContext.Current.Server.MapPath("~/App_Data/GeoNames/US.txt");
const int GeoNameIdColumn = 0;
const int NameColumn = 1;
const int LatitudeColumn = 4;
const int LongitudeColumn = 5;
const int FeatureCodeColumn = 7;
const int CountryCodeColumn = 8;
const int Admin1CodeColumn = 10;
const int Admin2CodeColumn = 11;
#endregion
#region AlternateName Constants
private static readonly string AlternateNamesPath = HttpContext.Current.Server.MapPath("~/App_Data/GeoNames/alternateNames.txt");
const int AlternateNameIdColumn = 0;
const int AltNameGeoNameIdColumn = 1;
const int IsoLanguageColumn = 2;
const int AlternateNameColumn = 3;
#endregion
public static void AddAllEntities(GeoNamesEntities entities)
{
//Remember to turn off Intellitrace
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var geoNamesSortedList = AddGeoNames(entities);
Trace.WriteLine(String.Format("Added GeoNames: {0}", stopwatch.Elapsed));
stopwatch.Restart();
SetupGeoNameChildRelationships(geoNamesSortedList, entities);
Trace.WriteLine(String.Format("Setup GeoName parent/child relationships: {0}", stopwatch.Elapsed));
stopwatch.Restart();
AddPostalCodeAlternateNames(geoNamesSortedList, entities);
Trace.WriteLine(String.Format("Added postal codes and relationships with parent GeoNames: {0}", stopwatch.Elapsed));
}
private static SortedList<int, GeoName> AddGeoNames(GeoNamesEntities entities)
{
var lineReader = File.ReadLines(GeoNamesPath);
var geoNames = from line in lineReader.AsParallel()
let fields = line.Split(new char[] { '\t' })
let fieldCount = fields.Length
where fieldCount >= 9
let featureCode = fields[FeatureCodeColumn]
where featureCode == "ADM1" || featureCode == "ADM2" || featureCode == "PPL"
let name = fields[NameColumn]
let id = string.IsNullOrEmpty(fields[GeoNameIdColumn]) ? 0 : int.Parse(fields[GeoNameIdColumn])
orderby id
select new GeoName
{
Id = Guid.NewGuid(),
GeoNameId = id,
Name = fields[NameColumn],
Latitude = string.IsNullOrEmpty(fields[LatitudeColumn]) ? 0 : Convert.ToDecimal(fields[LatitudeColumn]),
Longitude = string.IsNullOrEmpty(fields[LongitudeColumn]) ? 0 : Convert.ToDecimal(fields[LongitudeColumn]),
FeatureCode = featureCode,
CountryCode = fields[CountryCodeColumn],
Admin1Code = fieldCount < 11 ? "" : fields[Admin1CodeColumn],
Admin2Code = fieldCount < 12 ? "" : fields[Admin2CodeColumn]
};
var sortedList = new SortedList<int, GeoName>();
int i = 1;
foreach (var geoname in geoNames)
{
sortedList.Add(geoname.GeoNameId, geoname);
entities.GeographicAreas.AddObject(geoname);
if (i++ % 20000 == 0)
entities.SaveChanges();
}
entities.SaveChanges();
return sortedList;
}
private static void SetupGeoNameChildRelationships(SortedList<int, GeoName> geoNamesSortedList, GeoNamesEntities entities)
{
foreach (var geoName in geoNamesSortedList.Where(g => g.Value.FeatureCode == "ADM2" || g.Value.FeatureCode == "ADM1"))
{
//Setup parent child relationship
IEnumerable<KeyValuePair<int, GeoName>> children = null;
switch (geoName.Value.FeatureCode)
{
case "ADM1":
children =
geoNamesSortedList.Where(
g =>
g.Value.FeatureCode == "ADM2" &&
g.Value.Admin1Code == geoName.Value.Admin1Code);
break;
case "ADM2":
children =
geoNamesSortedList.Where(
g =>
g.Value.FeatureCode == "PPL" &&
g.Value.Admin1Code == geoName.Value.Admin1Code &&
g.Value.Admin2Code == geoName.Value.Admin2Code);
break;
}
if (children != null)
{
foreach (var child in children)
geoName.Value.Children.Add(child.Value);
}
entities.SaveChanges();
}
}
private static void AddPostalCodeAlternateNames(SortedList<int, GeoName> geoNamesSortedList, GeoNamesEntities entities)
{
var lineReader = File.ReadLines(AlternateNamesPath);
var alternativeNames = from line in lineReader.AsParallel()
let fields = line.Split(new char[] { '\t' })
let fieldCount = fields.Length
where fieldCount >= 4 && fields[IsoLanguageColumn] == "post"
let geoNameId = int.Parse(fields[AltNameGeoNameIdColumn])
orderby geoNameId
select new AlternateName
{
Id = Guid.NewGuid(),
AlternateNameId = int.Parse(fields[AlternateNameIdColumn]),
ParentGeoNameId = geoNameId,
Name = fields[AlternateNameColumn],
IsoLanguage = fields[IsoLanguageColumn]
};
//Iterate through to convert from lazy (AsParallel) so it is ready for use
foreach (var alternateName in alternativeNames)
{
int key = alternateName.ParentGeoNameId;
if (geoNamesSortedList.ContainsKey(key))
{
entities.GeographicAreas.AddObject(alternateName);
alternateName.Parent = geoNamesSortedList[key];
}
}
entities.SaveChanges();
}
}
您还可以下载或使用其API的 Open Street Maps 。
我不建议雅虎的新 API 他们左右切割产品,你永远不知道它会存在多久。此外,您目前无法下载整个转储。
2013 年 1 月 29 日更新:我创建了一个包含世界上所有城市和人口稠密地区的 CSV 数据集,以及纬度/经度区域质心,并放入公共领域。我结合了美国的 USGS GNIS 服务器和所有其他国家的 NGA GNS 服务器的数据。以下是 CSV 文件布局的元数据和数据集的链接:
http://www.opengeocode.org/download.php#cities
第 1 列:ISO 3166-1 alpha-2 国家代码。
第 2 列:美国 FIPS 5-2 一级行政区划代码(例如,州/省)。
第 3 列:NGA GNS 功能描述 (DSG) 代码。
第 4 列:NGA GNS 唯一特征标识符 (UFI)。
第 5 列:与功能名称相对应的语言的 ISO 639-1 alpha-2/3 代码。
第 6 列:与特征名称对应的语言文字(例如,拉丁语、阿拉伯语、中文等)。
第 7 列:功能名称。
第 8 列:区域质心的纬度坐标。
第 9 列:区域质心的经度坐标。
我查看了 Jonperl 的解决方案。它可以使用一些评论。首先,我相信 geonames.org 从 USGS GNIS 服务器获取美国城市数据。可以直接从他们那里获得下载文件。
http://geonames.usgs.gov/domestic/download_data.htm
有人应该知道的几点: ADM1 代表一级行政区划。对于美国,这些是 50 个州、哥伦比亚特区、5 个美国领土和 4 个自由联合州。
ADM2代表二级行政区划。对于美国,这些是阿拉斯加的县、自治市镇和人口普查指定区域,路易斯安那州的教区,波多黎各的市政厅,维尔京群岛、马绍尔群岛、美国外围小岛屿、美属萨摩亚的地区和北马里亚纳群岛的市镇.
PPL 是人口稠密的地方。我不确定 geonames.org 是如何对这些进行分类的,但这个类别包括城市:大型分区、未合并区域和大型拖车公园。Thney还包括一些历史名胜。
我可以回答很多这样的问题。我是 OpenGeoCode.Org 的公共领域地理空间团队的一员
安德鲁
我不知道您是否仅限于使用谷歌地图或openstreet 地图,但您可能会发现看看雅虎的woeid 很有趣。
http://developer.yahoo.com/geo/geoplanet/
我玩过这个,它非常强大。