标签:
在各种WEB应用中,会填写个人或者企业的地址信息,如下图所示,是京东上填写收货地址的页面截图。
小弟最近也碰到了类似的问题,需要得到所有省份,每个省份下属的市区,没事市区下属的县、乡镇、村这些数据。这方面的数据最权威的莫过于国家统计局(http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/index.html)给出的统计,目前国家统计局给出的最新数据是截止到2013年8月13日的数据,没有香港、澳门特别行政区,没有钓鱼岛,没有三沙市,也没有台湾,如果需要可以单独加上,如下图所示:
小弟借助simple_html_dom.php(可在https://github.com/samacs/simple_html_dom下载)这个库完成页面的抓取和解析,在这里,将代码和大家来分享一下。
<?php include_once (‘./simple_html_dom.php‘); /* 市、县、镇、村这些页面类似,页面中的样式有所区别,这里给出这些差异 */ define(‘CITY_CLASS‘, ‘citytr‘); define(‘COUNTY_CLASS‘, ‘countytr‘); define(‘TOWN_CLASS‘, ‘towntr‘); define(‘VILLAGE_CLASS‘, ‘villagetr‘); /* 国家统计局行政区域统计的首页 */ $rootUrl = ‘http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/index.html‘; /* * 从rootUrl中获取前缀信息,去掉最后面的index.html * * @param null * @access public * @return string */ function getRootUrlPrefix() { global $rootUrl; return preg_replace(‘/^(http:.*)index(\.html)$/‘, "$1", $rootUrl); } /* * 根据rootUrl获取省份/直辖市代码 * * @param null * @access public * @return array 各个省份的code */ function getProvinceCode() { global $rootUrl; $replaceEreg = ‘/^([0-9]{2,})\.html$/‘; $province = array(); $provinceIdx = 0; $html = file_get_html($rootUrl); /* 如果抓取页面失败,则10秒后尝试重新抓取 */ while (($html = file_get_html($rootUrl)) == false) { sleep(10); } foreach($html->find(‘a‘) as $ele) { /* 匹配html文档中每个省份对应的URL */ if (!preg_match($replaceEreg, $ele->href)) { continue; } /* 获取每个省份的名称 */ $name = preg_replace(‘/^(.*)<br.*$/‘, "$1", $ele->innertext); /* 每个省份的超链接为: 省份代码+.html, 从链接中去掉.html, 得到省份代码 */ if ($code = preg_replace($replaceEreg, "$1", $ele->href)) { $province[$provinceIdx][‘code‘] = $code; $province[$provinceIdx][‘name‘] = iconv(‘GB2312‘, ‘UTF-8‘, $name); $province[$provinceIdx][‘href‘] = $ele->href; ++$provinceIdx; } /* 根据省份代码和rootUrl改造该省份/直辖市的页面url */ } $html->clear(); unset($html); return $province; } /* * 获取某个省份的市、县、镇、村代码 * * @param string 省份/直辖市代码 * @param string 市、县、镇、村的页面样式,该变量为citytr,对于县,该变量为countytr,即为文件开头定义的几个宏 * @param int 省份代码,获取区县以及区县以下级别的行政区域code时,需要设置省份代码(用于构造页面的URL) * @param int 市代码,获取乡镇以及乡镇以下的行政区域code时,需要设置省份代码(用于构造页面的URL) * @access public * @return array 该省份各个市区的代码 */ function getAreaCode($url, $trClass, $provinceCode = ‘./‘, $cityCode = ‘./‘) { $area = array(); $areaIdx = 0; $code = -1; /* 构造获取城市代码的url */ $areaUrl = getRootUrlPrefix() . $provinceCode . ‘/‘ . $cityCode . ‘/‘ . $url; /* 如果抓取页面失败,则10秒后尝试重新抓取 */ while (($html = file_get_html($areaUrl)) == false) { sleep(10); } /* 根据页面特点解析出我们要的信息 */ foreach($html->find("tr[class=$trClass] > td") as $td) { /* td中包含a */ if ($a = $td->find(‘a‘)) { foreach ($a as $aa) { if (preg_match(‘/^[0-9]{12}$/‘, $aa->innertext)) { $code = $aa->innertext; ++$areaIdx; } else { $area[$areaIdx][‘code‘] = $code; $area[$areaIdx][‘name‘] = iconv(‘GB2312‘, ‘UTF-8‘, $aa->innertext); $area[$areaIdx][‘href‘] = $aa->href; } } } else /* td中不包含a */ { if (preg_match(‘/^[0-9]{12}$/‘, $td->innertext)) { $code = $td->innertext; ++$areaIdx; } else { $area[$areaIdx][‘code‘] = $code; $area[$areaIdx][‘name‘] = iconv(‘GB2312‘, ‘UTF-8‘, $td->innertext); } } } $html->clear(); unset($html); return $area; }将上面的代码保存为areaCode.php文件, 然后我们可以通过如下代码遍历获取到省市县镇村这些信息,如下所示。
<?php include_once (‘./areaCode.php‘); define(‘LEVEL_PROVINCE‘, 1); define(‘LEVEL_CITY‘, 2); define(‘LEVEL_COUNTY‘, 3); define(‘LEVEL_TOWN‘, 4); define(‘LEVEL_VILLAGE‘, 5); /* 控制获取的区域级别,根据需要进行设置,如果需要获取到村这个级别,可进行如下设置 */ $getLevel = LEVEL_VILLAGE; /* 获取省份信息 */ $provinces = getProvinceCode(); //printArray($provinces); /* 遍历每个省,获取下属的市 */ foreach ($provinces as $provinceKey => $province) { //做你想做的事情 if (!isset($province[‘href‘])) { continue; } if ($getLevel < CITY_CLASS) { continue; } /* 市 */ $citys = getAreaCode($province[‘href‘], CITY_CLASS); //printArray($citys); foreach ($citys as $cityKey => $city) { //做你想做的事情 if (!isset($city[‘href‘])) { continue; } if ($getLevel < LEVEL_COUNTY) { continue; } /* 区县 */ $countys = getAreaCode($city[‘href‘], COUNTY_CLASS); //printArray($countys); foreach ($countys as $countyKey => $county) { //做你想做的事情 if (!isset($county[‘href‘])) { continue; } if ($getLevel < LEVEL_TOWN) { continue; } $towns = getAreaCode($county[‘href‘], TOWN_CLASS, sprintf("%02d", $province[‘code‘])); //printArray($towns); foreach ($towns as $townKey => $town) { //做你想做的事情 if (!isset($town[‘href‘])) { continue; } if ($getLevel < LEVEL_VILLAGE) { continue; } $villages = getAreaCode($town[‘href‘], VILLAGE_CLASS, sprintf("%02d", $province[‘code‘]), substr($city[‘code‘], 2, 2)); //printArray($villages);exit; foreach ($villages as $villageKey => $village) { //做你想做的事情 } } } } }
执行该脚本需要的时间比较长,需要采用命令行的形式执行,如果获取到镇这一级别,差不多需要40分钟(和具体的电脑配置及其网络也有关系),我没有完整的获取过村这个级别的数据。
在遍历的过程中可以将数据写到文件、数据等一系列操作,这个按照个人需要增加即可。
标签:
原文地址:http://my.oschina.net/ricky716/blog/470228