从 Wiki 中挖掘国与国之间的联系
Wiki是一个众包性质的在线百科全书网站。志愿者们可以在上面编辑自己擅长领域的知识,它的宗旨是"中立的观点"。从某种程度上说,Wiki 和 OpenStreetMap 项目十分类似,只不过OpenStreetMap 项目只是专注于对空间数据的创建和编辑。
正是由于Wiki的众包特点,每个人都可以编辑页面,并且我们可以在页面之间创建链接。在Wiki里,可以通过一个特殊的URL区获得连接到某个页面的所有页面列表,比如,https://en.wikipedia.org/wiki/Special:WhatLinksHere/China 这个页面显示了所有可以链接到中国页面的链接列表。(由于中文维基已经被墙,这里访问的是英文维基)。
能否通过这个特殊的URL来挖掘国与国之间的联系呢?
通常,Wiki中一个国家的页面存在链接到另一国家的页面,说明这两个国家肯定有着一定的联系,比如可能是相邻关系、历史上有渊源、政治、经济或者是军事方面有联系等等。我们可以假设,如果某个国家被链接的次数越多,那么就有越多的国家和它有关系,也说明这个国家也就越重要。当然,这只是笼统地这么一说,国家的重要性是个很宽泛的话题,但是我们不妨先把国与国之间在Wiki上的链接关系找出来并可视化再说。
首先,我们要找到一个全世界所有国家在的列表,然后在Wiki里通过上述的URL去挖掘它们各自的联系。在Wiki里有一个国家ISO代码的页面,我们就从爬取这个页面的所有国家开始。下面的c++代码显示了如何用正则匹配去获得所有国家和地区的ISO代码和名称以及它们在Wiki中的链接地址(完整代码托管在oschina上):
std::string content;
if (!curl_get("https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#IN", content)) {
return false;
}
// regex search
std::regex expression("<td id=\"[A-Z]{2}\"><span style=\"[^\"]*\">[A-Z]{2}</span></td>\n<td><a href=\"[^\"]*\" title=\"[^\"]*\">.*</a></td>");
std::sregex_iterator iter(content.cbegin(), content.cend(), expression);
std::sregex_iterator iter_end;
int count = 0;
for (; iter != iter_end; ++iter) {
std::string searched_string = (*iter)[0].str();
std::string code, url, name;
// country code
code = searched_string.substr(8, 2);
if (!std::isupper(code[0]) || !std::isupper(code[1])) {
std::cout << "code: " << code << " is invalid!\n";
}
// country url
std::regex url_expresion("href=\"[^\"]*\" ");
std::smatch match;
if (std::regex_search (searched_string, match, url_expresion)) {
std::string s = match[0].str();
url = s.substr(6, s.length() - 8);
}
// country name
std::regex name_expresion("title=\"[^\"]*\"");
if (std::regex_search (searched_string, match, name_expresion)) {
std::string s = match[0].str();
name = s.substr(7, s.length() - 8);
}
// construct country
Country country(code, name, url);
this->countries_.push_back(country);
this->url_countries_.emplace(std::make_pair(url, count++));
}
获得国家的列表后,便可以依次寻找每个国家被链接的页面列表:
for (size_t i = 0; i < countries_.size(); ++i) {
Country& country = countries_[i];
// get page with maximal links list
std::string links_url = "https://en.wikipedia.org/wiki/Special:WhatLinksHere/" + country.get_url().substr(5);
std::string links_page;
if (!curl_get(links_url, links_page)) {
continue;
}
// regex search country page
std::regex expression("<li><a href=\"[^\"]*\" title=\"[^\"]*\">.*</a> <span class=");
std::sregex_iterator iter(links_page.cbegin(), links_page.cend(), expression);
std::sregex_iterator iter_end;
for (; iter != iter_end; ++iter) {
std::string searched_string = (*iter)[0].str();
std::regex url_expresion("href=\"[^\"]*\" ");
std::smatch match;
if (std::regex_search(searched_string, match, url_expresion)) {
std::string s = match[0].str();
std::string href = s.substr(6, s.length() - 8);
int index = this->Search(href, URL);
if (index != -1) {
count++;
country.AddLink(index);
}
}
}
}
如果您对程序感兴趣,下载oschina上的代码编译运行,可以得到包含国与国之间联系的shapefile格式的文件,如果您不想运行程序,可以从百度云盘直接下载程序的输出文件。最后,借助 GeoHey 的数据上图,我们可以做出下面的地图出来:
单独看看在Wiki上可以链接到中国的国家:
从上图可以看出,除了周边的国家外,能够链接到中国的其他国家的地理分布还是比较均匀的,从这里可以体现出我国外交所作出的努力。另外,从太平洋的一系列能链接到中国的岛国的位置,依稀可见中国走出太平洋的地理路线。
为了更直观地看每个国家的链接数,采用气泡图的可视化方式:
从图中不难发觉,北美洲、西欧以及一些地理位置优越的岛国被链接次数较多。虽然可以链接到中国的国家不少(123个),但是这个数字基本属于中等偏上一点点。连接数前四甲分别是法国(197),加拿大(193),美国(189)以及英国(183)。
分析到这里,大家可能会怀疑中国的被链接次数为何会如此低。这里面有一个原因是我们访问的是英文的wiki,这些页面基本上都是英语国家创建和编辑的,如果是中文的wiki的话可能会有更多的链接指向中国。但是从另一方面来说,这能使我们摒除自己的偏见,更客观地认识中国与世界的其它国家的联系。
欢迎从GeoHey获取地理和位置相关的数据、知识、服务
访问网站 http://geohey.com
联系我们 contact@geohey.com
长按关注公众号