代码之家  ›  专栏  ›  技术社区  ›  RameshVel

如何从开放街道地图或谷歌地图中提取地理数据

  •  5
  • RameshVel  · 技术社区  · 14 年前

    我需要使用OpenStreet地图或谷歌地图从特定国家检索所有城市名称。有可用的API吗?

    还是有其他方法来获取世界地理数据?

    4 回复  |  直到 10 年前
        1
  •  5
  •   jonperl    13 年前

    你一定要检查地名。他们在一个标准化的数据库中拥有整个世界。你可以 download it 或使用它们 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();
        }
    
    }
    

    还有一些开放的街道地图,你可以 download 或使用它们 API .

    我不建议雅虎的新API,他们正在左右切割产品,你永远不知道它会持续多久。另外,您当前无法下载整个转储。

        2
  •  3
  •   Andrew - OpenGeoCode    10 年前

    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代码。
    第六栏:功能名称对应的语言文字(如拉丁文、阿拉伯语、中文等)。
    第7列:功能名称。
    第8列:区域质心的纬度坐标。
    第9列:区域质心的经度坐标。


    我看了Jonperl的解决方案。它可以使用一些注释。首先,我相信geonames.org从USGS GNIS服务器获取美国城市数据。你可以直接从他们那里得到一个下载文件。

    http://geonames.usgs.gov/domestic/download_data.htm

    有人应该知道的几点: ADM1代表一级行政区划。对于美国来说,这是50个州、哥伦比亚特区、5个美国领土和4个自由联系的州。

    ADM2代表二级行政区划。对于美国来说,这些地区包括阿拉斯加的县、自治区和人口普查指定地区、路易斯安那州的教区、波多黎各的市政区、维尔京群岛的岛屿、马绍尔群岛、美国边远小岛、美属萨摩亚地区和北马里亚纳群岛的市。

    PPL是人口密集的地方。我不知道geonames.org是如何分类的,但这个分类包括城市:大分区、单一企业区和大型拖车停车场。这里还包括一些历史古迹。

    我能回答很多这样的问题。我是Opengeocode.org公共领域地理空间团队的一员。

    安得烈

        3
  •  2
  •   Tom Clarkson    14 年前
        4
  •  1
  •   azp74    14 年前

    我不知道你是被限制在谷歌地图还是OpenStreet地图,但你可能会发现看看雅虎的糟糕有趣。

    http://developer.yahoo.com/geo/geoplanet/

    我一直在玩这个,它非常强大。