简述
epsg.io是一个查询EPSG坐标系相关信息的好网站,内容很全。有各种格式的定义可以直接下载,也有坐标系的范围名称等相关信息,所以想抓取这些信息下来,方便对接各个系统。epsg.io
本身是开源的,代码在https://github.com/klokantech/epsg.io上,但是这个我分析出数据来源,应该是在epsg.io/gml/gml.sqlite
文件中,但是我打开这个文件发现没有相关的记录。
抓取说明
抓取的时候使用的是proj4
项目里的nad/epsg
文件中的记录作为索引,找到对应的epsg
代码去拼成对应url
去下载。
下面是代码,用的是libcurl
进行的相关操作。日志记录简单的用了一下glog
,可以去掉,去掉之后就是纯C的代码了。
抓取的结果直接写在程序目录下的epsg.io
目录下,请先创建好这个目录。
保存的html
文件的解析,可以参考HTML解析库Gumbo简单使用记录
抓取好的文件可以在这里epsg.io.7z下载,解压压缩之后会有三百多兆,共5754个文件。
分析后提取的内容,生成了一个超大的JSON文件,可以再这里epsg.io.json.7z下载。
我把抓取的内容处理成json后,又将其导入了MongoDB
数据库。
这里将数据备份后上传在这里https://files.cnblogs.com/files/oloroso/epsg.io.mongodb.7z,这个数据可以直接使用mongorestore
工具恢复到数据库。
导入MongoDB的数据中,wgs84_bound
字段名改为84box
,proj_bound
字段改为projbox
,中心点坐标经过处理,不会有null
出现。
代码
// g++ epsg.spider.cpp -o epsg.spider -lcurl -lglog -lpthread
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <curl/curl.h>
#include <glog/logging.h>
int downpage(int epsgcode)
{
int ret = 0;
char url[1024];
sprintf(url,"./epsg.io/%d.html",epsgcode);
FILE* fp = fopen(url,"wb");
if(fp == NULL){
fprintf(stderr,"\n创建输出文件失败i\n");
ret = -1;
return ret;
}
sprintf(url,"http://epsg.io/%d",epsgcode);
CURL *hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(hnd, CURLOPT_URL, url);
curl_easy_setopt(hnd, CURLOPT_COOKIEFILE, "./epsg.spider.cookie");
//curl_easy_setopt(hnd, CURLOPT_COOKIE, cookie_buffer);
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, fp);
CURLcode res = (CURLcode)curl_easy_perform(hnd);
if(res != CURLE_OK) {
fprintf(stderr,"\n%s curl_easy_perform failed:%s\n",url,curl_easy_strerror(res));
ret = -2;
}
fclose(fp);
curl_easy_cleanup(hnd);
return ret;
}
int main(int c,char** v)
{
// 打开epsg文件
FILE* fp = fopen("epsg","r");
if(fp == NULL){
puts("open epsg fiaild");
return 0;
}
google::InitGoogleLogging(v[0]);
FLAGS_log_dir = ".";
/*
* 这个函数只能用一次,如果这个函数在curl_easy_init函数调用时还没调用,
* 它讲由libcurl库自动调用,所以多线程下最好在主线程中调用一次该函数以防止在线程
* 中curl_easy_init时多次调用
*/
curl_global_init(CURL_GLOBAL_ALL);
char s[4096];
puts("开始下载:");
while(!feof(fp) && limit > 0){
int epsgcode = 0;
static char name[1024];
static char proj[1024];
fgets(s,sizeof s,fp);
if(s[0] == '#' ){
sscanf(s,"# %[^\n]s",name);
}
sscanf(s,"<%d> %[^\n<]s",&epsgcode,proj);
if(epsgcode == 0){
continue;
}
char path[128];
sprintf(path,"./epsg.io/%d.html",epsgcode);
struct stat st;
if(stat(path,&st) == 0) {
if(st.st_size > 1024){
// printf("%5d %s exsits\n",epsgcode,path);
continue;
}
}
printf("\r正在下载:http://epsg.io/%d ",epsgcode);
LOG(INFO) << "begin download http://epsg.io/"<<epsgcode;
if( downpage(epsgcode) != 0){
break;
}
LOG(INFO) << "finish download http://epsg.io/"<<epsgcode;
}
//在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数
curl_global_cleanup();
fclose(fp);
return 0;
}