├── etc
└── china.png
├── .gitignore
├── .editorconfig
├── tests
├── TestCase.php
├── ChinaTest.php
├── Holiday
│ ├── HolidayServiceTest.php
│ ├── DateTest.php
│ ├── HolidayLoaderTest.php
│ └── HolidayTest.php
├── Nationality
│ ├── NationalityTest.php
│ ├── NationalityServiceTest.php
│ └── NationalityLoaderTest.php
├── Region
│ ├── AddressFactoryTest.php
│ ├── Location
│ │ └── AddressTest.php
│ ├── RegionCollectionTest.php
│ └── RegionServiceTest.php
└── IDCard
│ └── IDCardTest.php
├── bin
└── china
├── .travis.yml
├── src
├── Common
│ ├── ResourceFile.php
│ ├── Utils.php
│ ├── FilesystemAwareInterface.php
│ ├── ResourceLoader
│ │ ├── ResourceLoaderInterface.php
│ │ └── LazyLoader.php
│ └── FilesystemAwareTrait.php
├── Region
│ ├── RegionCollection.php
│ ├── Location
│ │ ├── City.php
│ │ ├── District.php
│ │ ├── Province.php
│ │ ├── AddressInterface.php
│ │ └── Address.php
│ ├── RegionCollectionInterface.php
│ ├── RegionLoader.php
│ ├── AddressFinderTrait.php
│ ├── RegionServiceInterface.php
│ └── RegionService.php
├── Nationality
│ ├── NationalityLoader.php
│ ├── NationalityInterface.php
│ ├── NationalityServiceInterface.php
│ ├── NationalityService.php
│ └── Nationality.php
├── Holiday
│ ├── HolidayLoader.php
│ ├── DateInterface.php
│ ├── HolidayInterface.php
│ ├── Holiday.php
│ ├── HolidayServiceInterface.php
│ ├── HolidayService.php
│ └── Date.php
├── IDCard
│ ├── IDCardInterface.php
│ ├── IDCard.php
│ └── IDCardUtils.php
├── Command
│ ├── DashboardCommand.php
│ ├── CrawlCommand.php
│ ├── ShowNationalityCommand.php
│ ├── Application.php
│ ├── ShowRegionCommand.php
│ ├── CrawlHolidayCommand.php
│ ├── ShowHolidayCommand.php
│ ├── CrawlNationalityCommand.php
│ └── CrawlRegionCommand.php
└── China.php
├── doc
├── 4-nationality.md
├── 3-holiday.md
├── 0-index.md
├── 1-basic.md
└── 2-region.md
├── phpunit.xml.dist
├── composer.json
├── LICENSE
├── .github
└── workflows
│ └── test.yml
├── .scrutinizer.yml
├── resources
├── regions
│ ├── provinces.json
│ └── cities.json
├── nationalities.json
└── holidays.json
└── README.md
/etc/china.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/slince/China/HEAD/etc/china.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/*
2 | .DS_Store
3 | .idea/*
4 | composer.lock
5 | .php_cs.cache
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | ; top-most EditorConfig file
2 | root = true
3 |
4 | ; Unix-style newlines
5 | [*]
6 | end_of_line = LF
7 |
8 | [*.php]
9 | indent_style = space
10 | indent_size = 4
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | run();
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # see http://about.travis-ci.org/docs/user/languages/php/ for more hints
2 | language: php
3 |
4 | php:
5 | - 5.6
6 | - 7.0
7 | - 7.1
8 |
9 | before_script:
10 | - composer install
11 |
12 | script: ./vendor/bin/phpunit --coverage-clover=coverage.xml
13 |
14 | after_success:
15 | - bash <(curl -s https://codecov.io/bash)
16 |
17 | notifications:
18 | email: false
--------------------------------------------------------------------------------
/src/Common/ResourceFile.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Common;
15 |
16 | class ResourceFile extends \SplFileInfo
17 | {
18 | }
--------------------------------------------------------------------------------
/doc/4-nationality.md:
--------------------------------------------------------------------------------
1 | ## 民族查询
2 |
3 | 我国一共有56个民族,目前此服务只提供了基本的数据查询服务;如名称,人口以及拼音写法;此项服务数据摘自百度百科;
4 |
5 | ### 查找所有的民族
6 | ```php
7 |
8 | $nationalityService = $chna->getNationality();
9 |
10 | print_r($nationalityService->findAll()->count()); //56
11 |
12 | ```
13 |
14 | ### 按名称查找
15 |
16 | ```php
17 | $hezhe = $nationalityService->find('赫哲族'):
18 |
19 | echo $hezhe->getPinyin(); //输出“hè zhé zú”
20 | echo $hezhe->getPopulation(); //输出人口
21 | ```
--------------------------------------------------------------------------------
/tests/ChinaTest.php:
--------------------------------------------------------------------------------
1 | getChina();
10 | $this->assertEquals('中国', $china->getName());
11 | $this->assertEquals('中华人民共和国', $china->getOfficialName());
12 | $this->assertEquals('CN', $china->getIsoCode());
13 | $this->assertEquals(['zh_CN', 'zh_TW'], $china->getLanguages());
14 | }
15 | }
--------------------------------------------------------------------------------
/src/Common/Utils.php:
--------------------------------------------------------------------------------
1 | getChina()->getHoliday();
12 | $holidays = $holidayService->findAll();
13 | $this->assertGreaterThan(0, count($holidays));
14 | $this->assertNotEmpty($holidays->toArray());
15 | // var_dump($holidays->toArray());
16 | }
17 | }
--------------------------------------------------------------------------------
/tests/Holiday/DateTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(12, $date->getMonth());
15 | $this->assertEquals(8, $date->getDay());
16 | $this->assertEquals('12月8日', $date->toString());
17 | $this->assertEquals('12-8', $date->format('{month}-{day}'));
18 | }
19 | }
--------------------------------------------------------------------------------
/src/Region/RegionCollection.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region;
15 |
16 | use Doctrine\Common\Collections\ArrayCollection;
17 |
18 | class RegionCollection extends ArrayCollection implements RegionCollectionInterface
19 | {
20 | use AddressFinderTrait;
21 | }
--------------------------------------------------------------------------------
/tests/Nationality/NationalityTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('阿昌族', $nationality->getName());
14 | $this->assertEquals('ā chāng zú', $nationality->getPinyin());
15 | $this->assertEquals(39555, $nationality->getPopulation());
16 | }
17 | }
--------------------------------------------------------------------------------
/src/Region/Location/City.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region\Location;
15 |
16 | class City extends Address
17 | {
18 | /**
19 | * {@inheritdoc}
20 | */
21 | public static function getType(): string
22 | {
23 | return AddressInterface::TYPE_CITY;
24 | }
25 | }
--------------------------------------------------------------------------------
/doc/3-holiday.md:
--------------------------------------------------------------------------------
1 | ## 节日查询
2 |
3 | ### 获取所有的节日
4 |
5 | ```php
6 |
7 | $holidayService = $china->getHoliday();
8 |
9 | print_r($holidayService->findAll());
10 |
11 | ```
12 | ### 按名称查找节日
13 |
14 | ```php
15 | $yuandan = $holidayService->find('元旦节'):
16 |
17 | echo $yuandan->getDate(); //输出 1月1日
18 | ```
19 |
20 | ### 按照节日类型
21 |
22 | 1. 获取传统节日
23 | ```php
24 | $holidayService->findTraditionalHolidays();
25 | ```
26 |
27 | 2. 获取国际通用性节日
28 | ```php
29 | $holidayService->findInternationalHolidays();
30 | ```
31 |
32 | 3. 获取24节气
33 |
34 | ```php
35 | $holidayService->findSolarTermHolidays();
36 | ```
--------------------------------------------------------------------------------
/src/Region/Location/District.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region\Location;
15 |
16 | class District extends Address
17 | {
18 | /**
19 | * {@inheritdoc}
20 | */
21 | public static function getType(): string
22 | {
23 | return AddressInterface::TYPE_DISTRICT;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/Region/Location/Province.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region\Location;
15 |
16 | class Province extends Address
17 | {
18 | /**
19 | * {@inheritdoc}
20 | */
21 | public static function getType(): string
22 | {
23 | return AddressInterface::TYPE_PROVINCE;
24 | }
25 | }
--------------------------------------------------------------------------------
/tests/Holiday/HolidayLoaderTest.php:
--------------------------------------------------------------------------------
1 | assertNotEmpty($holidays->toArray());
17 | $this->assertInstanceOf(HolidayInterface::class, $holidays->first());
18 | }
19 | }
--------------------------------------------------------------------------------
/doc/0-index.md:
--------------------------------------------------------------------------------
1 | ## 目录
2 |
3 | 1. [基本用法](1-basic.md)
4 | 2. [地区查询](2-region.md)
5 | 3. [节日查询](3-holiday.md)
6 | 4. [民族查询](4-nationality.md)
7 |
8 | ## 命令行工具
9 |
10 | 执行下面命令查看支持的所有命令
11 |
12 | ```bash
13 | $ china list
14 | ```
15 | 输出信息:
16 | ```
17 | Available commands:
18 | help Displays help for a command
19 | list Lists commands
20 | crawl
21 | crawl:holiday 采集节假日数据
22 | crawl:nationality 从百度百科采集民族信息
23 | crawl:region 从国家统计局采集地区信息
24 | view
25 | view:holiday 展示节假日信息
26 | view:nationality 展示民族数据信息
27 | view:region 展示我国省市县信息
28 | ```
29 |
30 | ## TODO
31 | ...
--------------------------------------------------------------------------------
/tests/Nationality/NationalityServiceTest.php:
--------------------------------------------------------------------------------
1 | getChina()->getNationality();
12 | $han = $nationalityService->find('汉族');
13 | $this->assertGreaterThan(0, $han->getPopulation());
14 | }
15 |
16 | public function testFindAll()
17 | {
18 | $nationalityService = $this->getChina()->getNationality();
19 | $this->assertGreaterThan(0, count($nationalityService->findAll()));
20 | }
21 | }
--------------------------------------------------------------------------------
/tests/Holiday/HolidayTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('元旦节', $holiday->getName());
16 | $this->assertEquals(HolidayInterface::TYPE_INTERNATIONAL, $holiday->getType());
17 | $this->assertEquals('1月1日', $holiday->getDate()->toString());
18 | }
19 | }
--------------------------------------------------------------------------------
/tests/Nationality/NationalityLoaderTest.php:
--------------------------------------------------------------------------------
1 | assertNotEmpty($holidays->toArray());
17 | $this->assertInstanceOf(NationalityInterface::class, $holidays->first());
18 | }
19 | }
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ./src
6 |
7 |
8 | ./src/Command
9 | ./src/Common/FilesystemAwareTrait.php
10 |
11 |
12 |
13 |
14 | ./tests/
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/Nationality/NationalityLoader.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Nationality;
15 |
16 | use China\Common\ResourceLoader\LazyLoader;
17 |
18 | class NationalityLoader extends LazyLoader
19 | {
20 | /**
21 | * {@inheritdoc}
22 | */
23 | public function createRecord($record)
24 | {
25 | return new Nationality($record['name'], $record['pinyin'], intval($record['population']));
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Holiday/HolidayLoader.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Holiday;
15 |
16 | use China\Common\ResourceLoader\LazyLoader;
17 |
18 | class HolidayLoader extends LazyLoader
19 | {
20 | /**
21 | * {@inheritdoc}
22 | */
23 | public function createRecord(array $record)
24 | {
25 | $date = explode('月', trim($record['date'], '日'));
26 | return new Holiday($record['name'], $record['type'], new Date(intval($date[0]), intval($date[1])));
27 | }
28 | }
--------------------------------------------------------------------------------
/src/Common/FilesystemAwareInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Common;
15 |
16 | use Symfony\Component\Filesystem\Filesystem;
17 |
18 | interface FilesystemAwareInterface
19 | {
20 | /**
21 | * 获取文件系统
22 | *
23 | * @return Filesystem
24 | */
25 | public function getFilesystem(): Filesystem;
26 |
27 | /**
28 | * 设置文件系统
29 | *
30 | * @param Filesystem $filesystem
31 | */
32 | public function setFilesystem(Filesystem $filesystem);
33 | }
--------------------------------------------------------------------------------
/src/IDCard/IDCardInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\IDCard;
15 |
16 | interface IDCardInterface
17 | {
18 | /**
19 | * 转换成字符串.
20 | *
21 | * @return string
22 | */
23 | public function __toString();
24 |
25 | /**
26 | * 是否是短位身份证
27 | *
28 | * @return boolean
29 | */
30 | public function isShortLength(): bool;
31 |
32 | /**
33 | * 获取长数字.
34 | *
35 | * @return string
36 | */
37 | public function getLongNumber(): string;
38 | }
--------------------------------------------------------------------------------
/src/Nationality/NationalityInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Nationality;
15 |
16 | interface NationalityInterface extends \JsonSerializable
17 | {
18 | /**
19 | * 民族名称
20 | * @return string
21 | */
22 | public function getName(): string;
23 |
24 | /**
25 | * 民族拼音
26 | * @return string
27 | */
28 | public function getPinyin(): string;
29 |
30 | /**
31 | * 人口数量
32 | * @return int
33 | */
34 | public function getPopulation(): int;
35 | }
--------------------------------------------------------------------------------
/src/Nationality/NationalityServiceInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Nationality;
15 |
16 | use Doctrine\Common\Collections\Collection;
17 |
18 | interface NationalityServiceInterface
19 | {
20 | /**
21 | * 获取所有的节假日.
22 | *
23 | * @return Collection
24 | */
25 | public function findAll();
26 |
27 | /**
28 | * 查找指定的民族.
29 | *
30 | * @param string $name
31 | *
32 | * @return NationalityInterface
33 | */
34 | public function find($name);
35 | }
--------------------------------------------------------------------------------
/src/Command/DashboardCommand.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Command;
15 |
16 | use China\China;
17 | use Symfony\Component\Console\Command\Command;
18 |
19 | class DashboardCommand extends Command
20 | {
21 | /**
22 | * @var China
23 | */
24 | protected $china;
25 |
26 | /**
27 | * 获取china对象
28 | *
29 | * @return China
30 | */
31 | protected function getChina(): China
32 | {
33 | if (null === $this->china) {
34 | $this->china = new China();
35 | }
36 | return $this->china;
37 | }
38 | }
--------------------------------------------------------------------------------
/src/Common/ResourceLoader/ResourceLoaderInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Common\ResourceLoader;
15 |
16 | use China\Common\ResourceFile;
17 | use Doctrine\Common\Collections\Collection;
18 |
19 | interface ResourceLoaderInterface extends Collection
20 | {
21 | /**
22 | * 获取资源文件.
23 | *
24 | * @return ResourceFile
25 | */
26 | public function getResourceFile(): ResourceFile;
27 |
28 | /**
29 | * 处理原生数据.
30 | *
31 | * @param array $record
32 | * @return array|object
33 | */
34 | public function createRecord(array $record);
35 | }
--------------------------------------------------------------------------------
/src/Region/RegionCollectionInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region;
15 |
16 | use China\Region\Location\AddressInterface;
17 | use Doctrine\Common\Collections\Collection;
18 |
19 | interface RegionCollectionInterface extends Collection
20 | {
21 | /**
22 | * 根据Code查找地址
23 | *
24 | * @param string $code
25 | *
26 | * @return AddressInterface|null
27 | */
28 | public function findByCode(string $code): ?AddressInterface;
29 |
30 | /**
31 | * 根据Name查找地址
32 | *
33 | * @param string $name
34 | *
35 | * @return AddressInterface|null
36 | */
37 | public function findByName(string $name): ?AddressInterface;
38 | }
--------------------------------------------------------------------------------
/src/Common/FilesystemAwareTrait.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Common;
15 |
16 | use Symfony\Component\Filesystem\Filesystem;
17 |
18 | trait FilesystemAwareTrait
19 | {
20 | /**
21 | * @var Filesystem
22 | */
23 | protected $filesystem;
24 |
25 | /**
26 | * 设置文件系统
27 | *
28 | * @param Filesystem $filesystem
29 | */
30 | public function setFilesystem(Filesystem $filesystem)
31 | {
32 | $this->filesystem = $filesystem;
33 | }
34 |
35 | /**
36 | * 获取文件系统
37 | *
38 | * @return Filesystem
39 | */
40 | public function getFilesystem(): Filesystem
41 | {
42 | return $this->filesystem;
43 | }
44 | }
--------------------------------------------------------------------------------
/src/Holiday/DateInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Holiday;
15 |
16 | interface DateInterface extends \JsonSerializable
17 | {
18 | /**
19 | * 获取天.
20 | *
21 | * @return int
22 | */
23 | public function getDay(): int;
24 |
25 | /**
26 | * 获取month.
27 | *
28 | * @return int
29 | */
30 | public function getMonth(): int;
31 |
32 | /**
33 | * 转换成字符串表达式.
34 | *
35 | * @return string
36 | */
37 | public function toString(): string;
38 |
39 | /**
40 | * 格式化输出日期
41 | *
42 | * @param string $format
43 | *
44 | * @return string
45 | */
46 | public function format(string $format): string;
47 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "slince/china",
3 | "description": "中国资料库查询大全",
4 | "keywords": ["中国", "China", "节日", "地区"],
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "slince",
9 | "email": "taosikai@yeah.net"
10 | }
11 | ],
12 | "require": {
13 | "php": "^7.2||^8.0",
14 | "ext-json": "*",
15 | "symfony/console": "^4.2|^5.0|^6.0",
16 | "doctrine/collections": "^1.0|^2.0",
17 | "slince/config": "^1.1",
18 | "slince/di": "^3.0"
19 | },
20 | "require-dev": {
21 | "phpunit/phpunit": "^7.5|^8.0|^9.0",
22 | "fabpot/goutte": "^4.0",
23 | "symfony/filesystem": "^4.2|^5.0|^6.0"
24 | },
25 | "autoload":{
26 | "psr-4": {
27 | "China\\": "src/"
28 | }
29 | },
30 | "autoload-dev":{
31 | "psr-4": {
32 | "China\\Tests\\": "tests/"
33 | }
34 | },
35 | "bin": [
36 | "bin/china"
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/doc/1-basic.md:
--------------------------------------------------------------------------------
1 | ## 安装
2 |
3 | 执行下面命令安装
4 |
5 | ```bash
6 | $ composer require slince/china
7 | ```
8 |
9 | ## Basic Usage
10 |
11 | ### 节日查询
12 |
13 | ```php
14 |
15 | $china = new China();
16 |
17 | $holidayService = $china->getHoliday();
18 |
19 | print_r($holidayService->findAll());
20 |
21 | ```
22 | 按名称查找节日
23 |
24 | ```php
25 | $yuandan = $holidayService->find('元旦节'):
26 |
27 | echo $yuandan->getDate(); //输出 1月1日
28 | ```
29 |
30 | ### 民族查询
31 |
32 | ```php
33 |
34 | $china = new China();
35 |
36 | $nationalityService = $chna->getNationality();
37 |
38 | print_r($nationalityService->findAll());
39 |
40 | ```
41 |
42 | 按名称查找
43 |
44 | ```php
45 | $hezhe = $nationalityService->find('赫哲族'):
46 |
47 | echo $hezhe->getPinyin(); //输出“hè zhé zú”
48 | echo $hezhe->getPopulation(); //输出人口
49 | ```
50 |
51 |
52 | ### 地址库查询
53 |
54 |
55 | ```php
56 |
57 | $china = new China();
58 |
59 | $regionService = $chna->getRegion();
60 |
61 | print_r($regionService->getProvinces()); //获取树形省市县地区结构
62 | ```
63 |
--------------------------------------------------------------------------------
/tests/Region/AddressFactoryTest.php:
--------------------------------------------------------------------------------
1 | 340000,
15 | 'name' => '安徽省',
16 | 'type' => AddressInterface::TYPE_PROVINCE,
17 | ]);
18 | $bengbu = Address::createFromArray([
19 | 'code' => 340320,
20 | 'name' => '蚌埠市',
21 | 'type' => AddressInterface::TYPE_CITY,
22 | ], $anhui);
23 | $this->assertEquals($anhui, $bengbu->getParent());
24 | }
25 |
26 | public function testCreateWithoutType()
27 | {
28 | $this->expectException(\InvalidArgumentException::class);
29 | Address::createFromArray([
30 | 'code' => 340000,
31 | 'name' => '安徽省',
32 | ]);
33 | }
34 | }
--------------------------------------------------------------------------------
/tests/Region/Location/AddressTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(340000, $province->getCode());
16 | $this->assertEquals('安徽省', $province->getName());
17 | $this->assertEquals(null, $province->getParent());
18 |
19 | $city = new City('340300', '蚌埠市', $province);
20 | $this->assertEquals(340300, $city->getCode());
21 | $this->assertEquals('蚌埠市', $city->getName());
22 | $this->assertEquals($province, $city->getParent());
23 |
24 | $area = new District('340322', '五河县', $city);
25 | $this->assertEquals(340322, $area->getCode());
26 | $this->assertEquals('五河县', $area->getName());
27 | $this->assertEquals($city, $area->getParent());
28 | }
29 | }
--------------------------------------------------------------------------------
/src/Region/RegionLoader.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region;
15 |
16 | use China\Common\ResourceLoader\LazyLoader;
17 | use China\Region\Location\Address;
18 | use China\Region\Location\AddressInterface;
19 |
20 | class RegionLoader extends LazyLoader
21 | {
22 |
23 | protected function createRecords(array $records): array
24 | {
25 | return [$this->createRecord($records)];
26 | }
27 |
28 | /**
29 | * {@inheritdoc}
30 | */
31 | public function createRecord(array $record)
32 | {
33 | $rootData = [
34 | 'type' => AddressInterface::TYPE_PROVINCE,
35 | 'name' => 'China',
36 | 'code' => 0,
37 | 'children' => $record,
38 | ];
39 | return Address::createFromArray($rootData);
40 | }
41 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012-2017 Slince https://www.phpdish.com
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | env:
10 | XDEBUG_MODE: coverage
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 |
20 | - name: Validate composer.json and composer.lock
21 | run: composer validate --strict
22 |
23 | - name: Cache Composer packages
24 | id: composer-cache
25 | uses: actions/cache@v2
26 | with:
27 | path: vendor
28 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
29 | restore-keys: |
30 | ${{ runner.os }}-php-
31 |
32 | - name: Install dependencies
33 | run: composer install --prefer-dist --no-progress
34 |
35 | # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
36 | # Docs: https://getcomposer.org/doc/articles/scripts.md
37 |
38 | - name: Run test suite
39 | run: ./vendor/bin/phpunit --coverage-clover coverage.xml
40 |
41 | - name: Upload coverage to Codecov
42 | uses: codecov/codecov-action@v1
43 | with:
44 | token: ${{ secrets.CODECOV_TOKEN }}
45 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | filter:
2 | excluded_paths:
3 | - "tests/*"
4 | - "vendor/*"
5 |
6 | tools:
7 | external_code_coverage:
8 | timeout: 600
9 |
10 | php_sim: true
11 |
12 | php_changetracking: true
13 |
14 | php_cs_fixer:
15 | enabled: true
16 | config:
17 | level: all
18 | filter:
19 | excluded_paths:
20 | - "tests/*"
21 | - "vendor/*"
22 |
23 | php_mess_detector:
24 | enabled: true
25 | filter:
26 | excluded_paths:
27 | - "tests/*"
28 | - "vendor/*"
29 |
30 | php_pdepend:
31 | enabled: true
32 | filter:
33 | excluded_paths:
34 | - "tests/*"
35 | - "vendor/*"
36 |
37 | php_analyzer:
38 | enabled: true
39 | filter:
40 | excluded_paths:
41 | - "tests/*"
42 | - "vendor/*"
43 |
44 |
45 | php_cpd:
46 | enabled: true
47 | excluded_dirs:
48 | - "tests/*"
49 | - "vendor/*"
50 |
51 | php_loc:
52 | enabled: true
53 | excluded_dirs:
54 | - "tests/*"
55 | - "vendor/*"
--------------------------------------------------------------------------------
/src/Holiday/HolidayInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Holiday;
15 |
16 | interface HolidayInterface extends \JsonSerializable
17 | {
18 | /**
19 | * 节日类型,中国传统节日.
20 | *
21 | * @var string
22 | */
23 | const TYPE_TRADITIONAL = 'traditional';
24 |
25 | /**
26 | * 节日类型,中国24节气.
27 | *
28 | * @var string
29 | */
30 | const TYPE_SOLAR_TERM = 'solar_term';
31 |
32 | /**
33 | * 节日类型,国际节日.
34 | *
35 | * @var string
36 | */
37 | const TYPE_INTERNATIONAL = 'international';
38 |
39 | /**
40 | * 获取名称.
41 | *
42 | * @return string
43 | */
44 | public function getName(): string;
45 |
46 | /**
47 | * 获取类型.
48 | *
49 | * @return string
50 | */
51 | public function getType(): string;
52 |
53 | /**
54 | * 获取日期
55 | *
56 | * @return DateInterface
57 | */
58 | public function getDate(): DateInterface;
59 | }
--------------------------------------------------------------------------------
/src/Nationality/NationalityService.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Nationality;
15 |
16 | use China\Common\ResourceFile;
17 | use Doctrine\Common\Collections\Collection;
18 |
19 | class NationalityService implements NationalityServiceInterface
20 | {
21 | /**
22 | * @var Collection
23 | */
24 | protected $nationalities;
25 |
26 | public function __construct(ResourceFile $resourceFile)
27 | {
28 | $this->nationalities = new NationalityLoader($resourceFile);
29 | }
30 |
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function findAll()
35 | {
36 | return $this->nationalities;
37 | }
38 |
39 | /**
40 | * {@inheritdoc}
41 | */
42 | public function find($name)
43 | {
44 | return $this->nationalities->filter(function(NationalityInterface $nationality) use ($name){
45 | return $nationality->getName() === $name;
46 | })->first();
47 | }
48 | }
--------------------------------------------------------------------------------
/doc/2-region.md:
--------------------------------------------------------------------------------
1 | ## 国内省市县地区查询
2 |
3 | ### 获取地区查询服务
4 |
5 | 所有的服务获取均通过 `China\China`对象;
6 |
7 | ```php
8 | $china = new China\China();
9 |
10 | $regionService = $china->getRegion();
11 |
12 | $regionService->getProvinces(); // 获取所有的省(树形层级结构)
13 | ```
14 |
15 | ### 基本查询
16 |
17 | - `findByName` 按照名称查询
18 | - `findByCode` 按照地区码
19 | - `filter` 按照自定义的闭包查询
20 |
21 |
22 | ```php
23 | $anhui = $regionService->findByName('安徽省'):
24 | $beijing = $regionService->findByName('110000'): //根据地区码
25 | ```
26 |
27 | ### 地区的链式结构
28 |
29 | 通过`AddressInterface`的`getParent()`和`getChildren()`方法你可以自由地查找当前地区的上级或者下级地区;
30 | 需要注意的是下级地区集合是`RegionCollectionInterfaec`实例,该实例支持上述的三条基本查询;
31 |
32 | ```php
33 | $bengbushi = $regionService->findByName('蚌埠市');
34 | echo $bengbushi->getParent()->getName(); //输出蚌埠市所属省, 安徽省
35 | $yuhuiqu = $bengbushi->getChildren()->findByName('禹会区'); //获取蚌埠市下属禹会区
36 | $yuhuiqu->getParent()->getChildren()->findByName('淮上区'); //获取禹会区同级淮上区
37 | ```
38 |
39 | ### 查找身份证归属地
40 |
41 | ```php
42 | $huaiyuanxian = $regionService->findByIdCard('340321199212026972'); //怀远县
43 | ```
44 | 注意,你需要提供一个完整有效的身份证号码;查找出来的地区定位到县级地区;你可以通过地区的链式方法获取到省市级地区;
45 |
46 | ```php
47 | $city = $huaiyuanxian->getParent(); //蚌埠市
48 | $province = $huaiyuanxian->getParent()->getParent(); //安徽省
49 | ```
--------------------------------------------------------------------------------
/src/Command/CrawlCommand.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Command;
15 |
16 | use China\Common\FilesystemAwareInterface;
17 | use China\Common\FilesystemAwareTrait;
18 | use Goutte\Client;
19 | use Symfony\Component\Console\Command\Command;
20 |
21 | class CrawlCommand extends Command implements FilesystemAwareInterface
22 | {
23 | use FilesystemAwareTrait;
24 |
25 | /**
26 | * @var string
27 | */
28 | protected $resourceDir;
29 |
30 | /**
31 | * @var Client
32 | */
33 | protected $client;
34 |
35 | public function __construct(string $resourceDir)
36 | {
37 | $this->resourceDir = $resourceDir;
38 | parent::__construct();
39 | }
40 |
41 | /**
42 | * Goutte 实例
43 | * @return Client
44 | */
45 | public function getClient(): Client
46 | {
47 | if ($this->client) {
48 | return $this->client;
49 | }
50 | return $this->client = new Client();
51 | }
52 | }
--------------------------------------------------------------------------------
/src/Region/AddressFinderTrait.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region;
15 |
16 | use China\Region\Location\AddressInterface;
17 |
18 | trait AddressFinderTrait
19 | {
20 | /**
21 | * 根据Code查找地址
22 | *
23 | * @param string $code
24 | *
25 | * @return AddressInterface|null
26 | */
27 | public function findByCode(string $code): ?AddressInterface
28 | {
29 | $result = $this->filter(function(AddressInterface $address) use ($code){
30 | return $address->getCode() == $code;
31 | })->first();
32 | return $result ?: null;
33 | }
34 |
35 | /**
36 | * 根据Name查找地址
37 | *
38 | * @param string $name
39 | *
40 | * @return AddressInterface|null
41 | */
42 | public function findByName(string $name): ?AddressInterface
43 | {
44 | $result = $this->filter(function(AddressInterface $address) use ($name){
45 | return $address->getName() == $name;
46 | })->first();
47 | return $result ?: null;
48 | }
49 | }
--------------------------------------------------------------------------------
/tests/IDCard/IDCardTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('340321199212026972', $idCard);
14 | $this->assertEquals('340321199212026972', $idCard->getLongNumber());
15 | $this->assertFalse($idCard->isShortLength());
16 | }
17 |
18 | public function testCreateError()
19 | {
20 | try {
21 | $idCard = new IDCard('340321199212026973');
22 | $this->fail();
23 | } catch (\Exception $exception) {
24 | $this->assertStringContainsString('invalid', $exception->getMessage());
25 | }
26 |
27 | try {
28 | $idCard = new IDCard('qwe340321199212026973');
29 | $this->fail();
30 | } catch (\Exception $exception) {
31 | $this->assertStringContainsString('length should be 15 numbers or 18 numbers', $exception->getMessage());
32 | }
33 |
34 | try {
35 | $idCard = new IDCard('34032119921202697');
36 | $this->fail();
37 | } catch (\Exception $exception) {
38 | $this->assertStringContainsString('card length should be 15 numbers or 18 numbers', $exception->getMessage());
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/src/Holiday/Holiday.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Holiday;
15 |
16 | final class Holiday implements HolidayInterface
17 | {
18 | /**
19 | * @var string
20 | */
21 | protected $name;
22 |
23 | /**
24 | * @var string
25 | */
26 | protected $type;
27 |
28 | protected $date;
29 |
30 | public function __construct(string $name, string $type, DateInterface $date)
31 | {
32 | $this->name = $name;
33 | $this->type = $type;
34 | $this->date = $date;
35 | }
36 |
37 | /**
38 | * {@inheritdoc}
39 | */
40 | public function getName(): string
41 | {
42 | return $this->name;
43 | }
44 |
45 | /**
46 | * {@inheritdoc}
47 | */
48 | public function getType(): string
49 | {
50 | return $this->type;
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | */
56 | public function getDate(): DateInterface
57 | {
58 | return $this->date;
59 | }
60 |
61 | /**
62 | * {@inheritdoc}
63 | */
64 | public function jsonSerialize()
65 | {
66 | return [
67 | 'name' => $this->name,
68 | 'type' => $this->type,
69 | 'date' => $this->date,
70 | ];
71 | }
72 | }
--------------------------------------------------------------------------------
/src/Holiday/HolidayServiceInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Holiday;
15 |
16 | use Doctrine\Common\Collections\Collection;
17 |
18 | interface HolidayServiceInterface
19 | {
20 | /**
21 | * 获取所有的节假日.
22 | *
23 | * @return HolidayInterface[]|Collection
24 | */
25 | public function findAll(): iterable;
26 |
27 | /**
28 | * 获取所有的传统节日.
29 | *
30 | * @return HolidayInterface[]|Collection
31 | */
32 | public function findTraditionalHolidays(): iterable;
33 |
34 | /**
35 | * 获取所有的国际节日.
36 | *
37 | * @return HolidayInterface[]|Collection
38 | */
39 | public function findInternationalHolidays(): iterable;
40 |
41 | /**
42 | * 获取所有的节气.
43 | *
44 | * @return HolidayInterface[]|Collection
45 | */
46 | public function findSolarTermHolidays(): iterable;
47 |
48 | /**
49 | * 根据类型获取节假日.
50 | *
51 | * @param string $type
52 | *
53 | * @return HolidayInterface[]|Collection
54 | */
55 | public function findHolidaysByType(string $type): iterable;
56 |
57 | /**
58 | * 查找指定的民族.
59 | *
60 | * @param string $name
61 | *
62 | * @return HolidayInterface
63 | */
64 | public function find(string $name): ?HolidayInterface;
65 | }
--------------------------------------------------------------------------------
/src/Region/Location/AddressInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region\Location;
15 |
16 | use China\Region\RegionCollectionInterface;
17 |
18 | interface AddressInterface extends \JsonSerializable
19 | {
20 | /**
21 | * 类型,省
22 | *
23 | * @return string
24 | */
25 | const TYPE_PROVINCE = 'province';
26 |
27 | /**
28 | * 类型,市
29 | *
30 | * @return string
31 | */
32 | const TYPE_CITY = 'city';
33 |
34 | /**
35 | * 类型,区县
36 | *
37 | * @return string
38 | */
39 | const TYPE_DISTRICT = 'district';
40 |
41 | /**
42 | * 获取Code.
43 | *
44 | * @return int
45 | */
46 | public function getCode(): int;
47 |
48 | /**
49 | * 获取地址名称.
50 | *
51 | * @return string
52 | */
53 | public function getName(): string;
54 |
55 | /**
56 | * 获取上一级地址
57 | *
58 | * @return AddressInterface
59 | */
60 | public function getParent(): ?AddressInterface;
61 |
62 | /**
63 | * 设置子地区
64 | * @param iterable $children
65 | */
66 | public function setChildren(iterable $children);
67 |
68 | /**
69 | * 获取子地区.
70 | *
71 | * @return RegionCollectionInterface|AddressInterface[]
72 | */
73 | public function getChildren(): iterable;
74 | }
--------------------------------------------------------------------------------
/src/Command/ShowNationalityCommand.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Command;
15 |
16 | use China\Nationality\NationalityInterface;
17 | use Symfony\Component\Console\Input\InputInterface;
18 | use Symfony\Component\Console\Output\OutputInterface;
19 | use Symfony\Component\Console\Style\SymfonyStyle;
20 |
21 | class ShowNationalityCommand extends DashboardCommand
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function configure()
27 | {
28 | $this->setName('view:nationality');
29 | $this->setDescription('展示民族数据信息');
30 | }
31 |
32 | /**
33 | * {@inheritdoc}
34 | */
35 | public function execute(InputInterface $input, OutputInterface $output)
36 | {
37 | $nationalityService = $this->getChina()->getNationality();
38 | $style = new SymfonyStyle($input, $output);
39 | $headers = ['名称', '拼音', '人口'];
40 |
41 | $nationalities = $nationalityService->findAll()->toArray();
42 | $rows = array_map(function(NationalityInterface $nationality){
43 | return [
44 | "{$nationality->getName()}",
45 | $nationality->getPinyin(),
46 | $nationality->getPopulation(),
47 | ];
48 | }, $nationalities);
49 | $style->table($headers, $rows);
50 | return 0;
51 | }
52 | }
--------------------------------------------------------------------------------
/src/Region/RegionServiceInterface.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region;
15 |
16 | use China\IDCard\IDCardInterface;
17 | use China\Region\Location\AddressInterface;
18 | use China\Region\Location\Province;
19 | use Doctrine\Common\Collections\Collection;
20 |
21 | interface RegionServiceInterface
22 | {
23 | /**
24 | * 获取所有省份.
25 | *
26 | * @return Province[]|Collection
27 | */
28 | public function getProvinces(): iterable;
29 |
30 | /**
31 | * 查找身份证号码归属地.
32 | *
33 | * @param string|IDCardInterface $idCard
34 | *
35 | * @return AddressInterface|null
36 | */
37 | public function findByIdCard($idCard): ?AddressInterface;
38 |
39 | /**
40 | * 筛选地区.
41 | *
42 | * @param \Closure $callback
43 | *
44 | * @return AddressInterface[]|RegionCollectionInterface
45 | */
46 | public function filter(\Closure $callback): iterable;
47 |
48 | /**
49 | * 根据Code查找地址
50 | *
51 | * @param string $code
52 | *
53 | * @return AddressInterface|null
54 | */
55 | public function findByCode(string $code): ?AddressInterface;
56 |
57 | /**
58 | * 根据Name查找地址
59 | *
60 | * @param string $name
61 | *
62 | * @return AddressInterface|null
63 | */
64 | public function findByName(string $name): ?AddressInterface;
65 | }
--------------------------------------------------------------------------------
/src/Nationality/Nationality.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Nationality;
15 |
16 | final class Nationality implements NationalityInterface
17 | {
18 | /**
19 | * @var string
20 | */
21 | protected $name;
22 |
23 | /**
24 | * @var string
25 | */
26 | protected $pinyin;
27 |
28 | /**
29 | * @var number
30 | */
31 | protected $population;
32 |
33 | public function __construct(string $name, string $pinyin, int $population)
34 | {
35 | $this->name = $name;
36 | $this->pinyin = $pinyin;
37 | $this->population = $population;
38 | }
39 |
40 | /**
41 | * {@inheritdoc}
42 | */
43 | public function getName(): string
44 | {
45 | return $this->name;
46 | }
47 |
48 | /**
49 | * {@inheritdoc}
50 | */
51 | public function getPinyin(): string
52 | {
53 | return $this->pinyin;
54 | }
55 |
56 | /**
57 | * {@inheritdoc}
58 | */
59 | public function getPopulation(): int
60 | {
61 | return $this->population;
62 | }
63 |
64 | /**
65 | * {@inheritdoc}
66 | */
67 | public function jsonSerialize()
68 | {
69 | return [
70 | 'name' => $this->name,
71 | 'pinyin' => $this->pinyin,
72 | 'population' => $this->population,
73 | ];
74 | }
75 | }
--------------------------------------------------------------------------------
/tests/Region/RegionCollectionTest.php:
--------------------------------------------------------------------------------
1 | 340000,
16 | 'name' => '安徽省',
17 | 'type' => AddressInterface::TYPE_PROVINCE,
18 | ]);
19 | $bengbu = Address::createFromArray([
20 | 'code' => 340320,
21 | 'name' => '蚌埠市',
22 | 'type' => AddressInterface::TYPE_CITY,
23 | ], $anhui);
24 |
25 | return new RegionCollection([
26 | $anhui,
27 | $bengbu,
28 | ]);
29 | }
30 |
31 | public function testFindByName()
32 | {
33 | $regions = $this->createCollection();
34 | $this->assertEquals('安徽省', $regions->findByName('安徽省')->getName());
35 | $this->assertEquals(340000, $regions->findByName('安徽省')->getCode());
36 | }
37 |
38 | public function testFindByCode()
39 | {
40 | $regions = $this->createCollection();
41 | $this->assertEquals('蚌埠市', $regions->findByCode(340320)->getName());
42 | $this->assertEquals(340320, $regions->findByCode(340320)->getCode());
43 | }
44 |
45 | public function testFilter()
46 | {
47 | $regions = $this->createCollection()->filter(function(AddressInterface $address){
48 | return strpos($address->getCode(), '340') === 0;
49 | });
50 | $this->assertCount(2, $regions);
51 | }
52 | }
--------------------------------------------------------------------------------
/src/Command/Application.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Command;
15 |
16 | use China\Common\FilesystemAwareInterface;
17 | use Symfony\Component\Console\Application as BaseApplication;
18 | use Symfony\Component\Filesystem\Filesystem;
19 |
20 | final class Application extends BaseApplication
21 | {
22 | /**
23 | * @var string
24 | */
25 | protected $resourceDir;
26 |
27 | public function __construct(string $resourceDir)
28 | {
29 | $this->resourceDir = $resourceDir;
30 | parent::__construct('China');
31 | }
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | protected function getDefaultCommands(): array
37 | {
38 | return array_merge(parent::getDefaultCommands(), $this->createCommands());
39 | }
40 |
41 | protected function createCommands(): array
42 | {
43 | $commands = [
44 | new CrawlHolidayCommand($this->resourceDir),
45 | new CrawlNationalityCommand($this->resourceDir),
46 | new CrawlRegionCommand($this->resourceDir),
47 | new ShowHolidayCommand(),
48 | new ShowNationalityCommand(),
49 | new ShowRegionCommand(),
50 | ];
51 | $filesystem = new Filesystem();
52 | foreach ($commands as $command) {
53 | if ($command instanceof FilesystemAwareInterface) {
54 | $command->setFilesystem($filesystem);
55 | }
56 | }
57 | return $commands;
58 | }
59 | }
--------------------------------------------------------------------------------
/src/Common/ResourceLoader/LazyLoader.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Common\ResourceLoader;
15 |
16 | use China\Common\ResourceFile;
17 | use Doctrine\Common\Collections\AbstractLazyCollection;
18 | use Doctrine\Common\Collections\ArrayCollection;
19 | use Slince\Config\Config;
20 |
21 | class LazyLoader extends AbstractLazyCollection implements ResourceLoaderInterface
22 | {
23 | /**
24 | * @var ResourceFile
25 | */
26 | protected $resourceFile;
27 |
28 | public function __construct(ResourceFile $resourceFile)
29 | {
30 | $this->resourceFile = $resourceFile;
31 | }
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function getResourceFile(): ResourceFile
37 | {
38 | return $this->resourceFile;
39 | }
40 |
41 | /**
42 | * {@inheritdoc}
43 | */
44 | public function doInitialize()
45 | {
46 | $data = (new Config($this->resourceFile->getPathname()))->toArray();
47 | $this->collection = new ArrayCollection($this->createRecords($data));
48 | }
49 |
50 | protected function createRecords(array $records): array
51 | {
52 | $processed = [];
53 | foreach ($records as $record) {
54 | $processed[] = $this->createRecord($record);
55 | }
56 | return $processed;
57 | }
58 |
59 | /**
60 | * {@inheritdoc}
61 | */
62 | public function createRecord(array $record)
63 | {
64 | return $record;
65 | }
66 | }
--------------------------------------------------------------------------------
/src/IDCard/IDCard.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\IDCard;
15 |
16 | class IDCard implements IDCardInterface
17 | {
18 | /**
19 | * 身份证数字.
20 | *
21 | * @var string
22 | */
23 | protected $id;
24 |
25 | public function __construct(string $id)
26 | {
27 | self::assertValidIDCard($id);
28 | $this->id = $id;
29 | }
30 |
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function __toString()
35 | {
36 | return $this->id;
37 | }
38 |
39 | /**
40 | * {@inheritdoc}
41 | */
42 | public function isShortLength(): bool
43 | {
44 | return strlen($this->id) === 15;
45 | }
46 |
47 | /**
48 | * {@inheritdoc}
49 | */
50 | public function getLongNumber(): string
51 | {
52 | $id = $this->id;
53 | if ($this->isShortLength()) {
54 | $id = IDCardUtils::convertIDCard15to18($this->id);
55 | }
56 |
57 | return $id;
58 | }
59 |
60 | /**
61 | * 身份证是否合法.
62 | *
63 | * @param string $id
64 | */
65 | public static function assertValidIDCard(string $id)
66 | {
67 | $length = strlen($id);
68 | if ($length !== 15 && $length !== 18) {
69 | throw new \InvalidArgumentException(sprintf('The id "%s" card length should be 15 numbers or 18 numbers, given %d', $id, $length));
70 | }
71 | $convertedId = $id;
72 | if ($length === 15) {
73 | $convertedId = IDCardUtils::convertIDCard15to18($id);
74 | }
75 | if (!IDCardUtils::check18IDCard($convertedId)) {
76 | throw new \InvalidArgumentException(sprintf('The Id card "%s" is invalid', $id));
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/resources/regions/provinces.json:
--------------------------------------------------------------------------------
1 | [{"code":"110000","name":"北京市","type":"province","children":[]},{"code":"120000","name":"天津市","type":"province","children":[]},{"code":"130000","name":"河北省","type":"province","children":[]},{"code":"140000","name":"山西省","type":"province","children":[]},{"code":"150000","name":"内蒙古自治区","type":"province","children":[]},{"code":"210000","name":"辽宁省","type":"province","children":[]},{"code":"220000","name":"吉林省","type":"province","children":[]},{"code":"230000","name":"黑龙江省","type":"province","children":[]},{"code":"310000","name":"上海市","type":"province","children":[]},{"code":"320000","name":"江苏省","type":"province","children":[]},{"code":"330000","name":"浙江省","type":"province","children":[]},{"code":"340000","name":"安徽省","type":"province","children":[]},{"code":"350000","name":"福建省","type":"province","children":[]},{"code":"360000","name":"江西省","type":"province","children":[]},{"code":"370000","name":"山东省","type":"province","children":[]},{"code":"410000","name":"河南省","type":"province","children":[]},{"code":"420000","name":"湖北省","type":"province","children":[]},{"code":"430000","name":"湖南省","type":"province","children":[]},{"code":"440000","name":"广东省","type":"province","children":[]},{"code":"450000","name":"广西壮族自治区","type":"province","children":[]},{"code":"460000","name":"海南省","type":"province","children":[]},{"code":"500000","name":"重庆市","type":"province","children":[]},{"code":"510000","name":"四川省","type":"province","children":[]},{"code":"520000","name":"贵州省","type":"province","children":[]},{"code":"530000","name":"云南省","type":"province","children":[]},{"code":"540000","name":"西藏自治区","type":"province","children":[]},{"code":"610000","name":"陕西省","type":"province","children":[]},{"code":"620000","name":"甘肃省","type":"province","children":[]},{"code":"630000","name":"青海省","type":"province","children":[]},{"code":"640000","name":"宁夏回族自治区","type":"province","children":[]},{"code":"650000","name":"新疆维吾尔自治区","type":"province","children":[]},{"code":"710000","name":"台湾省","type":"province","children":[]},{"code":"810000","name":"香港特别行政区","type":"province","children":[]},{"code":"820000","name":"澳门特别行政区","type":"province","children":[]}]
--------------------------------------------------------------------------------
/tests/Region/RegionServiceTest.php:
--------------------------------------------------------------------------------
1 | getChina()->getRegion();
12 | $provinces = $regionService->getProvinces();
13 | $this->assertCount(34, $provinces);
14 | $this->assertEquals('北京市', $provinces->first()->getName());
15 | }
16 |
17 | public function testFindByCode()
18 | {
19 | $regionService = $this->getChina()->getRegion();
20 | $beijing = $regionService->findByCode('110000');
21 | $this->assertEquals('北京市', $beijing->getName());
22 | }
23 |
24 | public function testFindByName()
25 | {
26 | $regionService = $this->getChina()->getRegion();
27 | $beijing = $regionService->findByName('江宁区');
28 | $this->assertEquals('320115', $beijing->getCode());
29 | }
30 |
31 | public function testFind()
32 | {
33 | $regionService = $this->getChina()->getRegion();
34 | $this->assertNull($regionService->findByName('不存在的地区'));
35 | $bengbu = $regionService->findByName('蚌埠市');
36 | $this->assertEquals($regionService->findByName('安徽省'), $bengbu->getParent());
37 | $this->assertContains($regionService->findByName('怀远县'), $bengbu->getChildren());
38 | }
39 |
40 | public function testFindByIdCard()
41 | {
42 | $regionService = $this->getChina()->getRegion();
43 | $address = $regionService->findByIdCard('340321199106196978');
44 | $this->assertEquals($regionService->findByName('怀远县'), $address);
45 | $this->assertEquals($regionService->findByName('蚌埠市'), $address->getParent());
46 | $this->assertEquals($regionService->findByName('安徽省'), $address->getParent()->getParent());
47 | }
48 |
49 | public function testFindChain()
50 | {
51 | $regionService = $this->getChina()->getRegion();
52 | $anhui = $regionService->findByName('安徽省');
53 | $this->assertCount(16, $anhui->getChildren());
54 | $this->assertEquals($anhui, $anhui->getChildren()->first()->getParent());
55 | }
56 | }
--------------------------------------------------------------------------------
/src/Holiday/HolidayService.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Holiday;
15 |
16 | use China\Common\ResourceFile;
17 | use Doctrine\Common\Collections\Collection;
18 |
19 | class HolidayService implements HolidayServiceInterface
20 | {
21 | /**
22 | * @var Collection
23 | */
24 | protected $holidays;
25 |
26 | public function __construct(ResourceFile $resourceFile)
27 | {
28 | $this->holidays = new HolidayLoader($resourceFile);
29 | }
30 |
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function findAll(): iterable
35 | {
36 | return $this->holidays;
37 | }
38 |
39 | /**
40 | * {@inheritdoc}
41 | */
42 | public function findTraditionalHolidays(): iterable
43 | {
44 | return $this->findHolidaysByType(HolidayInterface::TYPE_TRADITIONAL);
45 | }
46 |
47 | /**
48 | * {@inheritdoc}
49 | */
50 | public function findInternationalHolidays(): iterable
51 | {
52 | return $this->findHolidaysByType(HolidayInterface::TYPE_INTERNATIONAL);
53 | }
54 |
55 | /**
56 | * {@inheritdoc}
57 | */
58 | public function findSolarTermHolidays(): iterable
59 | {
60 | return $this->findHolidaysByType(HolidayInterface::TYPE_SOLAR_TERM);
61 | }
62 |
63 | /**
64 | * {@inheritdoc}
65 | */
66 | public function findHolidaysByType(string $type): iterable
67 | {
68 | return $this->holidays->filter(function(HolidayInterface $holiday) use ($type){
69 | return $holiday->getType() === $type;
70 | });
71 | }
72 |
73 | /**
74 | * {@inheritdoc}
75 | */
76 | public function find(string $name): ?HolidayInterface
77 | {
78 | $result = $this->holidays->filter(function(HolidayInterface $holiday) use ($name){
79 | return $holiday->getName() === $name;
80 | })->first();
81 | return $result ?: null;
82 | }
83 | }
--------------------------------------------------------------------------------
/src/Command/ShowRegionCommand.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Command;
15 |
16 | use China\Region\Location\AddressInterface;
17 | use Symfony\Component\Console\Input\InputInterface;
18 | use Symfony\Component\Console\Input\InputOption;
19 | use Symfony\Component\Console\Output\OutputInterface;
20 | use Symfony\Component\Console\Style\SymfonyStyle;
21 |
22 | class ShowRegionCommand extends DashboardCommand
23 | {
24 | protected static $types = [
25 | AddressInterface::TYPE_PROVINCE => '省',
26 | AddressInterface::TYPE_CITY => '市',
27 | AddressInterface::TYPE_DISTRICT => '区 ',
28 | ];
29 |
30 | /**
31 | * {@inheritdoc}
32 | */
33 | public function configure()
34 | {
35 | $this->setName('view:region');
36 | $this->addOption('parent', 'p', InputOption::VALUE_OPTIONAL);
37 | $this->setDescription('展示我国省市县信息');
38 | }
39 |
40 | /**
41 | * {@inheritdoc}
42 | */
43 | public function execute(InputInterface $input, OutputInterface $output)
44 | {
45 | $regionService = $this->getChina()->getRegion();
46 | $style = new SymfonyStyle($input, $output);
47 | $headers = ['Code', '名称', '类型'];
48 |
49 | if ($parentName = $input->getOption('parent')) {
50 | $parent = $regionService->findByName($parentName) ?: $regionService->findByCode($parentName);
51 | if ($parent === false) {
52 | throw new \InvalidArgumentException(sprintf('你提供的上级地区“%s”似乎是不存在的', $parentName));
53 | }
54 | $regions = $parent->getChildren()->toArray();
55 | } else {
56 | $regions = $regionService->getProvinces()->toArray();
57 | }
58 |
59 | $rows = array_map(function(AddressInterface $address){
60 | return [
61 | $address->getCode(),
62 | "{$address->getName()}",
63 | static::$types[$address->getType()],
64 | ];
65 | }, $regions);
66 | $style->table($headers, $rows);
67 | return 0;
68 | }
69 | }
--------------------------------------------------------------------------------
/src/IDCard/IDCardUtils.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\IDCard;
15 |
16 | /**
17 | * 算法摘自
18 | * {@link https://www.cnblogs.com/bossikill/p/3679926.html}.
19 | */
20 | final class IDCardUtils
21 | {
22 | /**
23 | * 计算身份证最后一位.
24 | *
25 | * @param string $idCardBody
26 | *
27 | * @return bool|string
28 | */
29 | public static function calcIDCardCode(string $idCardBody)
30 | {
31 | if (strlen($idCardBody) != 17) {
32 | return false;
33 | }
34 | //加权因子
35 | $factor = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
36 | //校验码对应值
37 | $code = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
38 | $checksum = 0;
39 |
40 | for ($i = 0; $i < strlen($idCardBody); ++$i) {
41 | $checksum += substr($idCardBody, $i, 1) * $factor[$i];
42 | }
43 |
44 | return $code[$checksum % 11];
45 | }
46 |
47 | /**
48 | * 将15位身份证升级到18位.
49 | *
50 | * @param string $id
51 | *
52 | * @return bool|string
53 | */
54 | public static function convertIDCard15to18(string $id)
55 | {
56 | if (strlen($id) != 15) {
57 | return false;
58 | } else {
59 | // 如果身份证顺序码是996 997 998 999,这些是为百岁以上老人的特殊编码
60 | if (array_search(substr($id, 12, 3), array('996', '997', '998', '999')) !== false) {
61 | $id = substr($id, 0, 6).'18'.substr($id, 6, 9);
62 | } else {
63 | $id = substr($id, 0, 6).'19'.substr($id, 6, 9);
64 | }
65 | }
66 |
67 | return $id . self::calcIDCardCode($id);
68 | }
69 |
70 | /**
71 | * 18位身份证校验码有效性检查.
72 | *
73 | * @param string $idCard
74 | *
75 | * @return bool
76 | */
77 | public static function check18IDCard(string $idCard): bool
78 | {
79 | if (strlen($idCard) != 18) {
80 | return false;
81 | }
82 | $idCardBody = substr($idCard, 0, 17); //身份证主体
83 | $idCardCode = strtoupper(substr($idCard, 17, 1)); //身份证最后一位的验证码
84 |
85 | return self::calcIDCardCode($idCardBody) === $idCardCode;
86 | }
87 | }
--------------------------------------------------------------------------------
/src/Holiday/Date.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Holiday;
15 |
16 | final class Date implements DateInterface
17 | {
18 | /**
19 | * 月.
20 | *
21 | * @var int
22 | */
23 | protected $month;
24 |
25 | /**
26 | * 天.
27 | *
28 | * @var int
29 | */
30 | protected $day;
31 |
32 | public function __construct(int $month, int $day)
33 | {
34 | $this->setMonth($month);
35 | $this->setDay($day);
36 | }
37 |
38 | /**
39 | * {@inheritdoc}
40 | */
41 | public function getDay(): int
42 | {
43 | return $this->day;
44 | }
45 |
46 | /**
47 | * {@inheritdoc}
48 | */
49 | public function getMonth(): int
50 | {
51 | return $this->month;
52 | }
53 |
54 | /**
55 | * {@inheritdoc}
56 | */
57 | public function format(string $format): string
58 | {
59 | return str_replace(['{month}', '{day}',], [
60 | $this->month,
61 | $this->day,
62 | ], $format);
63 | }
64 |
65 | /**
66 | * {@inheritdoc}
67 | */
68 | public function toString(): string
69 | {
70 | return $this->format('{month}月{day}日');
71 | }
72 |
73 | /**
74 | * 字符串输出.
75 | *
76 | * @return string
77 | */
78 | public function __toString()
79 | {
80 | return $this->toString();
81 | }
82 |
83 | /**
84 | * {@inheritdoc}
85 | */
86 | public function jsonSerialize()
87 | {
88 | return $this->toString();
89 | }
90 |
91 | protected function setMonth(int $month)
92 | {
93 | if (!is_numeric($month) || $month < 1 || $month > 12) {
94 | throw new \InvalidArgumentException(sprintf('Wrong month, given "%s"', $month));
95 | }
96 | $this->month = $month;
97 | }
98 |
99 | protected function setDay($day)
100 | {
101 | if (!is_numeric($day) || $day < 1 || $day > 31) {
102 | throw new \InvalidArgumentException(sprintf('Wrong day, given "%s"', $day));
103 | }
104 | $this->day = $day;
105 | }
106 | }
--------------------------------------------------------------------------------
/src/Region/RegionService.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region;
15 |
16 | use China\Common\ResourceFile;
17 | use China\IDCard\IDCard;
18 | use China\Region\Location\AddressInterface;
19 | use Doctrine\Common\Collections\Collection;
20 |
21 | class RegionService implements RegionServiceInterface
22 | {
23 | use AddressFinderTrait;
24 |
25 | /**
26 | * @var AddressInterface
27 | */
28 | protected $regions;
29 |
30 | /**
31 | * 根据code做索引.
32 | *
33 | * @var AddressInterface[]|Collection
34 | */
35 | protected $flattenRegions;
36 |
37 | public function __construct(ResourceFile $file)
38 | {
39 | $this->regions = new RegionLoader($file);
40 | $this->flattenRegions = new RegionCollection();
41 | }
42 |
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function getProvinces(): iterable
47 | {
48 | return $this->regions->first()->getChildren();
49 | }
50 |
51 | /**
52 | * {@inheritdoc}
53 | */
54 | public function findByIdCard($idCard): ?AddressInterface
55 | {
56 | if (is_string($idCard)) {
57 | $idCard = new IDCard($idCard);
58 | }
59 | $areaCode = substr((string)$idCard, 0, 6);
60 |
61 | return $this->findByCode($areaCode);
62 | }
63 |
64 | /**
65 | * {@inheritdoc}
66 | */
67 | public function filter(\Closure $callback): iterable
68 | {
69 | if (!$this->flattenRegions->isEmpty()) {
70 | return $this->flattenRegions->filter($callback);
71 | }
72 | // 没有遍历过则自行遍历
73 | $addresses = [];
74 | $this->traverseTree($this->regions->first(), function(AddressInterface $address) use ($callback, &$addresses){
75 | if ($callback($address) === true) {
76 | $addresses[] = $address;
77 | }
78 | });
79 | return new RegionCollection($addresses);
80 | }
81 |
82 | /**
83 | * 遍历地区树.
84 | *
85 | * @param AddressInterface $address
86 | * @param \Closure $callback
87 | */
88 | protected function traverseTree(AddressInterface $address, \Closure $callback)
89 | {
90 | $callback($address);
91 | //将树形结构扁平化
92 | $this->flattenRegions->add($address);
93 | if ($address->getChildren()) {
94 | foreach ($address->getChildren() as $child) {
95 | $this->traverseTree($child, $callback);
96 | }
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/src/Command/CrawlHolidayCommand.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Command;
15 |
16 | use China\Holiday\Date;
17 | use China\Holiday\Holiday;
18 | use China\Holiday\HolidayInterface;
19 | use Symfony\Component\Console\Input\InputInterface;
20 | use Symfony\Component\Console\Output\OutputInterface;
21 | use Symfony\Component\Console\Style\SymfonyStyle;
22 | use Symfony\Component\DomCrawler\Crawler;
23 |
24 | class CrawlHolidayCommand extends CrawlCommand
25 | {
26 | /**
27 | * 节假日资源地址
28 | *
29 | * @var string
30 | */
31 | const URL = 'http://www.sojson.com/time/holiday.html';
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function configure()
37 | {
38 | $this->setName('crawl:holiday');
39 | $this->setDescription('采集节假日数据');
40 | }
41 |
42 | /**
43 | * {@inheritdoc}
44 | */
45 | public function execute(InputInterface $input, OutputInterface $output)
46 | {
47 | $style = new SymfonyStyle($input, $output);
48 |
49 | $outputFile = $this->resourceDir.'/holidays.json';
50 |
51 | $crawler = $this->getClient()->request('GET', static::URL);
52 | $holidays = $crawler->filter('.festival_list')->each(function(Crawler $node){
53 | $fontNode = $node->filter('font');
54 | $date = $this->parseToDate(strstr($node->text(), '['));
55 | $date = new Date($date[0], $date[1]);
56 | $type = $this->convertColorToType($fontNode->attr('color'));
57 |
58 | return new Holiday($fontNode->text(), $type, $date);
59 | });
60 |
61 | $this->filesystem->dumpFile($outputFile, \json_encode($holidays, JSON_UNESCAPED_UNICODE));
62 |
63 | $style->writeln(sprintf('Crawl completed, please check the file at "%s"', realpath($outputFile)));
64 | return 0;
65 | }
66 |
67 | protected function parseToDate(string $dateString)
68 | {
69 | return explode('/', trim($dateString, ']['));
70 | }
71 |
72 | protected function convertColorToType(string $class): string
73 | {
74 | $type = '';
75 | switch ($class) {
76 | case 'red':
77 | $type = HolidayInterface::TYPE_TRADITIONAL;
78 | break;
79 |
80 | case 'green':
81 | $type = HolidayInterface::TYPE_INTERNATIONAL;
82 | break;
83 |
84 | case 'blue':
85 | $type = HolidayInterface::TYPE_SOLAR_TERM;
86 | break;
87 | }
88 |
89 | return $type;
90 | }
91 | }
--------------------------------------------------------------------------------
/resources/nationalities.json:
--------------------------------------------------------------------------------
1 | [{"name":"阿昌族","pinyin":"ā chāng zú","population":"39,555"},{"name":"鄂温克族","pinyin":"è wēn kè zú","population":"30,875"},{"name":"傈僳族","pinyin":"lì sù zú","population":"702,839"},{"name":"水族","pinyin":"shuǐ zú","population":"411,847"},{"name":"白族","pinyin":"bái zú","population":"1,933,510"},{"name":"高山族","pinyin":"gāo shān zú","population":"4,009"},{"name":"珞巴族","pinyin":"luò bā zú","population":"3,682"},{"name":"塔吉克族","pinyin":"tǎ jí kè zú","population":"51,069"},{"name":"保安族","pinyin":"bǎo ān zú","population":"20,074"},{"name":"仡佬族","pinyin":"gě lǎo zú","population":"550,746"},{"name":"满族","pinyin":"mǎn zú","population":"10,387,958"},{"name":"塔塔尔族","pinyin":"tǎ tǎ ěr zú","population":"3,556"},{"name":"布朗族","pinyin":"bù lǎng zú","population":"119,639"},{"name":"哈尼族","pinyin":"hā ní zú","population":"1,660,932"},{"name":"毛南族","pinyin":"máo nán zú","population":"101,192"},{"name":"土家族","pinyin":"tǔ jiā zú","population":"8,353,912"},{"name":"布依族","pinyin":"bù yī zú","population":"2,870,034"},{"name":"哈萨克族","pinyin":"hā sà kè zú","population":"1,462,588"},{"name":"门巴族","pinyin":"mén bā zú","population":"10,561"},{"name":"土族","pinyin":"tǔ zú","population":"289,565"},{"name":"朝鲜族","pinyin":"cháo xiǎn zú","population":"1,830,929"},{"name":"汉族","pinyin":"hàn zú","population":"1,220,844,520"},{"name":"蒙古族","pinyin":"měng gǔ zú","population":"5,981,840"},{"name":"佤族","pinyin":"wǎ zú","population":"429,709"},{"name":"达斡尔族","pinyin":"dá wò ěr zú","population":"131,992"},{"name":"赫哲族","pinyin":"hè zhé zú","population":"5,354"},{"name":"苗族","pinyin":"miáo zú","population":"9,426,007"},{"name":"维吾尔族","pinyin":"wéi wú ěr zú","population":"10,069,346"},{"name":"傣族","pinyin":"dǎi zú","population":"1,261,311"},{"name":"回族","pinyin":"huí zú","population":"10,586,087"},{"name":"仫佬族","pinyin":"mù lǎo zú","population":"216,257"},{"name":"乌孜别克族","pinyin":"wū zī bié kè zú","population":"10,569"},{"name":"德昂族","pinyin":"dé áng zú","population":"20,556"},{"name":"基诺族","pinyin":"jī nuò zú","population":"23,143"},{"name":"纳西族","pinyin":"nà xī zú","population":"326,295"},{"name":"锡伯族","pinyin":"xī bó zu","population":"190,481"},{"name":"东乡族","pinyin":"dōng xiāng zú","population":"621,500"},{"name":"京族","pinyin":"jīng zú","population":"28,199"},{"name":"怒族","pinyin":"nù zú","population":"37,523"},{"name":"瑶族","pinyin":"yáo zú","population":"2,796,003"},{"name":"侗族","pinyin":"dòng zú","population":"2,879,974"},{"name":"景颇族","pinyin":"jǐng pō zú","population":"147,828"},{"name":"普米族","pinyin":"pǔ mǐ zú","population":"42,861"},{"name":"彝族","pinyin":"yí zú","population":"8,714,393"},{"name":"独龙族","pinyin":"dú lóng zú","population":"6,930"},{"name":"柯尔克孜族","pinyin":"kē ěr kè zī zú","population":"186,708"},{"name":"羌族","pinyin":"qiāng zú","population":"309,576"},{"name":"裕固族","pinyin":"yù gù zú","population":"14,378"},{"name":"俄罗斯族","pinyin":"é luó sī zú","population":"15,393"},{"name":"拉祜族","pinyin":"lā hù zú","population":"485,966"},{"name":"撒拉族","pinyin":"sā lā zú","population":"130,607"},{"name":"藏族","pinyin":"zàng zú","population":"6,282,187"},{"name":"鄂伦春族","pinyin":"è lún chūn zu","population":"8,659"},{"name":"黎族","pinyin":"lí zú","population":"1,463,064"},{"name":"畲族","pinyin":"shē zú","population":"708,651"},{"name":"壮族","pinyin":"zhuàng zú","population":"16,926,381"}]
--------------------------------------------------------------------------------
/src/Command/ShowHolidayCommand.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Command;
15 |
16 | use China\Holiday\HolidayInterface;
17 | use Symfony\Component\Console\Input\InputInterface;
18 | use Symfony\Component\Console\Input\InputOption;
19 | use Symfony\Component\Console\Output\OutputInterface;
20 | use Symfony\Component\Console\Question\ChoiceQuestion;
21 | use Symfony\Component\Console\Style\SymfonyStyle;
22 |
23 | class ShowHolidayCommand extends DashboardCommand
24 | {
25 | protected static $types = [
26 | HolidayInterface::TYPE_TRADITIONAL => '传统节日',
27 | HolidayInterface::TYPE_INTERNATIONAL => '国际节日',
28 | HolidayInterface::TYPE_SOLAR_TERM => '24节气',
29 | ];
30 |
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function configure()
35 | {
36 | $this->setName('view:holiday');
37 | $this->addOption('type', 't', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, '按照类型筛选');
38 | $this->addOption('all', 'a', InputOption::VALUE_NONE, '展现全部数据');
39 | $this->setDescription('展示节假日信息');
40 | }
41 |
42 | /**
43 | * {@inheritdoc}
44 | */
45 | public function execute(InputInterface $input, OutputInterface $output)
46 | {
47 | $holidayService = $this->getChina()->getHoliday();
48 | $style = new SymfonyStyle($input, $output);
49 | $headers = ['名称', '类型', '日期'];
50 |
51 | if ($input->getOption('all')) {
52 | $holidays = $holidayService->findAll()->toArray();
53 | } else {
54 | $types = $input->getOption('type');
55 | if (empty($types)) {
56 | $question = new ChoiceQuestion('请选择节日类型', static::$types, HolidayInterface::TYPE_TRADITIONAL);
57 | $question->setMultiselect(true);
58 | $helper = $this->getHelper('question');
59 | $types = $helper->ask($input, $output, $question);
60 | } else {
61 | $this->checkTypes($types);
62 | }
63 | $holidays = [];
64 | foreach ($types as $type) {
65 | $holidays = array_merge($holidays, $holidayService->findHolidaysByType($type)->toArray());
66 | }
67 | }
68 | $rows = array_map(function(HolidayInterface $holiday){
69 | return [
70 | "{$holiday->getName()}",
71 | static::$types[$holiday->getType()],
72 | $holiday->getDate(),
73 | ];
74 | }, $holidays);
75 | $style->table($headers, $rows);
76 | return 0;
77 | }
78 |
79 | protected function checkTypes($types)
80 | {
81 | foreach ($types as $type) {
82 | if (!isset(static::$types[$type])) {
83 | throw new \InvalidArgumentException(sprintf('类型 "%s" 不支持,请从(%s)做出选择',
84 | $type,
85 | implode(', ', array_keys(static::$types))
86 | ));
87 | }
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/src/Command/CrawlNationalityCommand.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Command;
15 |
16 | use China\Nationality\Nationality;
17 | use Symfony\Component\Console\Input\InputInterface;
18 | use Symfony\Component\Console\Output\OutputInterface;
19 | use Symfony\Component\Console\Style\SymfonyStyle;
20 | use Symfony\Component\DomCrawler\Crawler;
21 |
22 | class CrawlNationalityCommand extends CrawlCommand
23 | {
24 | /**
25 | * @var string
26 | */
27 | const URL = 'https://baike.baidu.com/item/56个民族/383735';
28 |
29 | /**
30 | * {@inheritdoc}
31 | */
32 | public function configure()
33 | {
34 | $this->setName('crawl:nationality');
35 | $this->setDescription('从百度百科采集民族信息');
36 | }
37 |
38 | /**
39 | * {@inheritdoc}
40 | */
41 | public function execute(InputInterface $input, OutputInterface $output)
42 | {
43 | $style = new SymfonyStyle($input, $output);
44 |
45 | $outputFile = $this->resourceDir.'/nationalities.json';
46 |
47 | $crawler = $this->getClient()->request('GET', static::URL);
48 |
49 | $tables = $crawler->filter('table[log-set-param="table_view"]');
50 | $nationalities = $this->extractPinyinData($tables->eq(1));
51 | $populations = $this->extractPopulationData($tables->eq(2));
52 |
53 | $nationalities = $this->mergeData($nationalities,$populations);
54 | $this->filesystem->dumpFile($outputFile, \json_encode($nationalities, JSON_UNESCAPED_UNICODE));
55 |
56 | $style->writeln(sprintf('Crawl completed, please check the file at "%s"', realpath($outputFile)));
57 | return 0;
58 | }
59 |
60 | protected function extractPinyinData(Crawler $crawler)
61 | {
62 | $nationalities = $crawler->filter('tr')->each(function(Crawler $itemNode){
63 | $data = [];
64 | $itemNode->filter('td')->each(function(Crawler $tdNode, $index) use (&$data){
65 | if ($index % 2 === 0) {
66 | $data[$index] = [
67 | 'name' => trim($tdNode->text()),
68 | 'pinyin' => false,
69 | ];
70 | } else {
71 | $data[$index - 1]['pinyin'] = trim($tdNode->text());
72 | }
73 | });
74 | return $data;
75 | });
76 |
77 | return call_user_func_array('array_merge', $nationalities);
78 | }
79 |
80 | protected function extractPopulationData(Crawler $crawler): array
81 | {
82 | $data = [];
83 | $crawler->filter('tr')->each(function(Crawler $itemNode) use (&$data){
84 | $tds = $itemNode->filter('td');
85 | if (count($tds) > 0) {
86 | $name = trim($tds->first()->text());
87 | $data[$name] = trim($tds->eq(1)->text());
88 | }
89 | });
90 |
91 | return $data;
92 | }
93 |
94 | protected function mergeData($nationalityInfos, $populations): array
95 | {
96 | $nationalities = [];
97 | foreach ($nationalityInfos as $nationalityInfo) {
98 | $nationalities[] = new Nationality($nationalityInfo['name'],
99 | $nationalityInfo['pinyin'],
100 | $populations[$nationalityInfo['name']] ?? 0
101 | );
102 | }
103 |
104 | return $nationalities;
105 | }
106 | }
--------------------------------------------------------------------------------
/src/China.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China;
15 |
16 | use China\Common\ResourceFile;
17 | use China\Holiday\HolidayService;
18 | use China\Holiday\HolidayServiceInterface;
19 | use China\Nationality\NationalityService;
20 | use China\Nationality\NationalityServiceInterface;
21 | use China\Region\RegionService;
22 | use China\Region\RegionServiceInterface;
23 | use Slince\Di\Container;
24 |
25 | final class China
26 | {
27 | /**
28 | * @var string
29 | */
30 | protected $name = '中国';
31 |
32 | /**
33 | * @var string
34 | */
35 | protected $officialName = '中华人民共和国';
36 |
37 | /**
38 | * @var string
39 | */
40 | protected $isoCode = 'CN';
41 |
42 | /**
43 | * @var array
44 | */
45 | protected $languages = ['zh_CN', 'zh_TW'];
46 |
47 | /**
48 | * @var string
49 | */
50 | protected $resourceDir;
51 |
52 | protected $container;
53 |
54 | public function __construct(string $resourceDir = __DIR__.'/../resources/')
55 | {
56 | $this->container = new Container();
57 | $this->resourceDir = $resourceDir;
58 | $this->registerParameters();
59 | $this->registerService();
60 | }
61 |
62 | protected function registerParameters()
63 | {
64 | $this->container->setParameters([
65 | 'resource.file.holidays' => $this->resourceDir.'holidays.json',
66 | 'resource.file.nationalities' => $this->resourceDir.'nationalities.json',
67 | 'resource.file.regions' => $this->resourceDir.'regions/regions.json',
68 | ]);
69 | }
70 |
71 | protected function registerService()
72 | {
73 | $this->container->register('holiday', function(Container $container){
74 | return new HolidayService(new ResourceFile($container->getParameter('resource.file.holidays')));
75 | });
76 | $this->container->register('nationality', function(Container $container){
77 | return new NationalityService(new ResourceFile($container->getParameter('resource.file.nationalities')));
78 | });
79 | $this->container->register('region', function(Container $container){
80 | return new RegionService(new ResourceFile($container->getParameter('resource.file.regions')));
81 | });
82 | }
83 |
84 | /**
85 | * 获取名称.
86 | *
87 | * @return string
88 | */
89 | public function getName(): string
90 | {
91 | return $this->name;
92 | }
93 |
94 | /**
95 | * 获取官方名称.
96 | *
97 | * @return string
98 | */
99 | public function getOfficialName(): string
100 | {
101 | return $this->officialName;
102 | }
103 |
104 | /**
105 | * 获取ISO3166两位代码
106 | *
107 | * @return string
108 | */
109 | public function getIsoCode(): string
110 | {
111 | return $this->isoCode;
112 | }
113 |
114 | /**
115 | * 获取语言
116 | *
117 | * @return array
118 | */
119 | public function getLanguages(): array
120 | {
121 | return $this->languages;
122 | }
123 |
124 | /**
125 | * 获取Holiday服务
126 | *
127 | * @return HolidayServiceInterface
128 | */
129 | public function getHoliday(): HolidayServiceInterface
130 | {
131 | return $this->container->get('holiday');
132 | }
133 |
134 | /**
135 | * 获取Nationality服务
136 | *
137 | * @return NationalityServiceInterface
138 | */
139 | public function getNationality(): NationalityServiceInterface
140 | {
141 | return $this->container->get('nationality');
142 | }
143 |
144 | /**
145 | * 获取Region服务
146 | *
147 | * @return RegionServiceInterface
148 | */
149 | public function getRegion(): RegionServiceInterface
150 | {
151 | return $this->container->get('region');
152 | }
153 | }
--------------------------------------------------------------------------------
/src/Region/Location/Address.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Region\Location;
15 |
16 | use China\Region\RegionCollection;
17 | use Doctrine\Common\Collections\Collection;
18 |
19 | abstract class Address implements AddressInterface
20 | {
21 | /**
22 | * @var int
23 | */
24 | protected $code;
25 |
26 | /**
27 | * @var string
28 | */
29 | protected $name;
30 |
31 | /**
32 | * @var AddressInterface
33 | */
34 | protected $parent;
35 |
36 | /**
37 | * 子地区.
38 | *
39 | * @var AddressInterface[]|Collection
40 | */
41 | protected $children;
42 |
43 | public function __construct(int $code, string $name, AddressInterface $parent = null, $children = [])
44 | {
45 | $this->code = $code;
46 | $this->name = $name;
47 | $this->parent = $parent;
48 | $this->children = $children;
49 | }
50 |
51 | public function __toString(): string
52 | {
53 | return $this->getName();
54 | }
55 |
56 | /**
57 | * {@inheritdoc}
58 | */
59 | public function getName(): string
60 | {
61 | return $this->name;
62 | }
63 |
64 | /**
65 | * {@inheritdoc}
66 | */
67 | public function getCode(): int
68 | {
69 | return $this->code;
70 | }
71 |
72 | /**
73 | * {@inheritdoc}
74 | */
75 | public function getParent(): ?AddressInterface
76 | {
77 | return $this->parent;
78 | }
79 |
80 | /**
81 | * {@inheritdoc}
82 | */
83 | public function setChildren($children)
84 | {
85 | $this->children = $children;
86 | }
87 |
88 | /**
89 | * {@inheritdoc}
90 | */
91 | public function getChildren(): iterable
92 | {
93 | return $this->children;
94 | }
95 |
96 | /**
97 | * {@inheritdoc}
98 | */
99 | public function jsonSerialize()
100 | {
101 | return [
102 | 'code' => $this->code,
103 | 'name' => $this->name,
104 | 'type' => static::getType(),
105 | 'children' => $this->getChildren(),
106 | ];
107 | }
108 |
109 | /**
110 | * 获取当前类类型.
111 | * @return string
112 | */
113 | public static function getType(): string
114 | {
115 | return '';
116 | }
117 |
118 | /**
119 | * 创建地区对象
120 | *
121 | * @param array $data
122 | * @param AddressInterface|null $parent
123 | *
124 | * @return AddressInterface
125 | * @throws \InvalidArgumentException
126 | */
127 | public static function createFromArray(array $data, AddressInterface $parent = null)
128 | {
129 | if (!isset($data['type'])) {
130 | throw new \InvalidArgumentException('Missing parameter "type"');
131 | }
132 | $address = null;
133 | $code = intval($data['code']);
134 | switch ($data['type']) {
135 | case AddressInterface::TYPE_PROVINCE:
136 | $address = new Province($code, $data['name'], $parent);
137 | break;
138 | case AddressInterface::TYPE_CITY:
139 | $address = new City($code, $data['name'], $parent);
140 | break;
141 | case AddressInterface::TYPE_DISTRICT:
142 | $address = new District($code, $data['name'], $parent);
143 | break;
144 | }
145 | if (!$address) {
146 | throw new \InvalidArgumentException(sprintf('Bad parameter "type" with "%s"', $data['type']));
147 | }
148 | //子地区
149 | if (!empty($data['children'])) {
150 | $children = array_map(function($regionData) use ($address){
151 | return static::createFromArray($regionData, $address);
152 | }, $data['children']);
153 | $address->setChildren(new RegionCollection($children));
154 | }
155 | return $address;
156 | }
157 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 我国的资料库查询库;本库主要包含民族、节日、地址库信息的查询;部分数据来源采集自百科以及国家统计局;欢迎收藏欢迎贡献代码;
6 |
7 | [](https://github.com/slince/China/actions)
8 | [](https://codecov.io/github/slince/China)
9 | [](https://packagist.org/packages/slince/china)
10 | [](https://scrutinizer-ci.com/g/slince/China/?branch=master)
11 |
12 |
13 | ## Installation
14 |
15 | 执行下面命令安装
16 |
17 | ```bash
18 | > composer require slince/china
19 | ```
20 |
21 | ## Document
22 |
23 | 你可以在这里发现[文档](./doc);
24 |
25 | ## Basic Usage
26 |
27 | ### 节日查询
28 |
29 | ```php
30 |
31 | $china = new China();
32 |
33 | $holidayService = $chna->getHoliday();
34 |
35 | print_r($holidayService->findAll());
36 |
37 | ```
38 | 按名称查找节日
39 |
40 | ```php
41 | $yuandan = $holidayService->find('元旦节'):
42 |
43 | echo $yuandan->getDate(); //输出 1月1日
44 | ```
45 |
46 | ### 民族查询
47 |
48 | ```php
49 |
50 | $china = new China();
51 |
52 | $nationalityService = $chna->getNationality();
53 |
54 | print_r($nationalityService->findAll());
55 |
56 | ```
57 |
58 | 按名称查找
59 |
60 | ```php
61 | $hezhe = $nationalityService->find('赫哲族'):
62 |
63 | echo $hezhe->getPinyin(); //输出“hè zhé zú”
64 | echo $hezhe->getPopulation(); //输出人口
65 | ```
66 |
67 |
68 | ### 地址库查询
69 |
70 |
71 | ```php
72 |
73 | $china = new China();
74 |
75 | $regionService = $china->getRegion();
76 |
77 | print_r($regionService->getProvinces()); //获取树形省市县地区结构
78 | ```
79 |
80 | 按名称查找地区
81 |
82 | ```php
83 | $bengbushi = $regionService->findByName('蚌埠市');
84 | echo $bengbushi->getParent()->getName(); //输出蚌埠市所属省, 安徽省
85 | ```
86 |
87 | 查询身份证所在地
88 |
89 | ```php
90 | $huaiyuan = $regionService->findByIdCard('340321199212026972');
91 | ```
92 |
93 | 地区链功能
94 |
95 | 通过`AddressInterface`的`getParent()`和`getChildren()`方法你可以自由地查找当前地区的上级或者下级地区,下级地区集合是`RegionCollectionInterfaec`
96 | 实例;
97 |
98 | ```php
99 | $yuhuiqu = $bengbushi->getChildren()->findByName('禹会区'); //蚌埠市下属禹会区
100 | $yuhuiqu->getParent()->getChildren()->findByName('淮上区'); //禹会区同级淮上区
101 | ```
102 | Json Serialize
103 |
104 | ```php
105 | $bengbushi = $regionService->findByName('蚌埠市');
106 | echo json_encode($bengbushi);
107 | ```
108 | 上述代码会输出蚌埠市及其下属地区的完整的json树形结构;如果你不需要的话下级地区的话请将children设置为空
109 |
110 | ```php
111 | $bengbushi = $regionService->findByName('蚌埠市');
112 | $bengbushi = clone $bengbushi; //此处需要克隆对象,如果直接修改会破坏原有的地区树结构
113 | $bengbushi->setChildren([]);
114 | echo json_encode($bengbushi);
115 | ```
116 |
117 | > 建议:在电商系统中城市县三级地区联动的数据可以使用此方法获取,避免将数据导入数据库再从数据库获取;
118 |
119 |
120 | ## 命令行工具
121 |
122 | 执行下面命令查看支持的所有命令
123 |
124 | ```bash
125 | $ china list
126 | ```
127 | 输出信息:
128 | ```
129 | Available commands:
130 | help Displays help for a command
131 | list Lists commands
132 | crawl
133 | crawl:holiday 采集节假日数据
134 | crawl:nationality 从百度百科采集民族信息
135 | crawl:region 从国家统计局采集地区信息
136 | view
137 | view:holiday 展示节假日信息
138 | view:nationality 展示民族数据信息
139 | view:region 展示我国省市县信息
140 | ```
141 |
142 | 例: 展示我国所有的省、直辖市、自治区以及特别行政区:
143 |
144 | ```bash
145 | $ china dashboard:region
146 | ```
147 | 上述命令会输出以下结果:
148 |
149 | ```
150 | -------- ------------------ ------
151 | Code 名称 类型
152 | -------- ------------------ ------
153 | 110000 北京市 省
154 | 120000 天津市 省
155 | 130000 河北省 省
156 | 140000 山西省 省
157 | 150000 内蒙古自治区 省
158 | 210000 辽宁省 省
159 | 220000 吉林省 省
160 | 230000 黑龙江省 省
161 | 310000 上海市 省
162 | 320000 江苏省 省
163 | 330000 浙江省 省
164 | 340000 安徽省 省
165 | 350000 福建省 省
166 | 360000 江西省 省
167 | 370000 山东省 省
168 | 410000 河南省 省
169 | 420000 湖北省 省
170 | 430000 湖南省 省
171 | 440000 广东省 省
172 | 450000 广西壮族自治区 省
173 | 460000 海南省 省
174 | 500000 重庆市 省
175 | 510000 四川省 省
176 | 520000 贵州省 省
177 | 530000 云南省 省
178 | 540000 西藏自治区 省
179 | 610000 陕西省 省
180 | 620000 甘肃省 省
181 | 630000 青海省 省
182 | 640000 宁夏回族自治区 省
183 | 650000 新疆维吾尔自治区 省
184 | 710000 台湾省 省
185 | 810000 香港特别行政区 省
186 | 820000 澳门特别行政区 省
187 | -------- ------------------ ------
188 | ```
189 | ...
190 |
191 | ## License
192 |
193 | The MIT license. See [MIT](https://opensource.org/licenses/MIT)
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
--------------------------------------------------------------------------------
/src/Command/CrawlRegionCommand.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * For the full copyright and license information, please view the LICENSE
11 | * file that was distributed with this source code.
12 | */
13 |
14 | namespace China\Command;
15 |
16 | use China\Common\Utils;
17 | use China\Region\Location\AddressInterface;
18 | use China\Region\Location\District;
19 | use China\Region\Location\City;
20 | use China\Region\Location\Province;
21 | use Symfony\Component\Console\Input\InputInterface;
22 | use Symfony\Component\Console\Output\OutputInterface;
23 | use Symfony\Component\Console\Style\SymfonyStyle;
24 | use Symfony\Component\DomCrawler\Crawler;
25 |
26 | class CrawlRegionCommand extends CrawlCommand
27 | {
28 | /**
29 | * 资源地址
30 | *
31 | * @var string
32 | */
33 | const URL = 'http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/201703/t20170310_1471429.html';
34 |
35 | /**
36 | * {@inheritdoc}
37 | */
38 | public function configure()
39 | {
40 | $this->setName('crawl:region');
41 | $this->setDescription('从国家统计局采集地区信息');
42 | }
43 |
44 | /**
45 | * {@inheritdoc}
46 | */
47 | public function execute(InputInterface $input, OutputInterface $output)
48 | {
49 | $style = new SymfonyStyle($input, $output);
50 |
51 | $outputFile = $this->resourceDir.'/regions/regions.json';
52 |
53 | $crawler = $this->getClient()->request('GET', static::URL);
54 |
55 | $regions = $crawler->filter('p.MsoNormal')->each(function(Crawler $node) use (&$provinces, &$cities, &$areas){
56 | $code = $node->filter('span[lang="EN-US"]')->text();
57 | $name = $node->filter('span[style]')->last()->text();
58 |
59 | return [
60 | 'code' => preg_replace('/[^\d]/', '', $code),
61 | 'name' => Utils::clearBlankCharacters($name),
62 | ];
63 | });
64 | //归类数据
65 | list($provinces, $cities, $districts) = $this->organizeRegions($regions);
66 | //构建树形结构
67 | $root = new Province(0, "");
68 | $root->shortCode = 0;
69 | $this->buildRegionsTree(array_merge($provinces, $cities, $districts), $root);
70 |
71 | $this->filesystem->dumpFile($this->resourceDir.'/regions/provinces.json', \json_encode($this->extractAddressesWithoutChildren($provinces), JSON_UNESCAPED_UNICODE));
72 | $this->filesystem->dumpFile($this->resourceDir.'/regions/cities.json', \json_encode($this->extractAddressesWithoutChildren($cities), JSON_UNESCAPED_UNICODE));
73 | $this->filesystem->dumpFile($this->resourceDir.'/regions/districts.json', \json_encode($this->extractAddressesWithoutChildren($districts), JSON_UNESCAPED_UNICODE));
74 | $this->filesystem->dumpFile($outputFile, \json_encode($root->getChildren(), JSON_UNESCAPED_UNICODE));
75 |
76 | $style->writeln(sprintf('Crawl completed, please check the file at "%s"', realpath($outputFile)));
77 | return 0;
78 | }
79 |
80 | /**
81 | * 提取省份数据,去除子地区数据.
82 | *
83 | * @param AddressInterface[] $addresses
84 | *
85 | * @return AddressInterface[]
86 | */
87 | protected function extractAddressesWithoutChildren(array $addresses): array
88 | {
89 | return array_map(function(AddressInterface $address){
90 | $address = clone $address;
91 | $address->setChildren([]);
92 |
93 | return $address;
94 | }, $addresses);
95 | }
96 |
97 | /**
98 | * 分拣数据.
99 | *
100 | * @param array $regions
101 | *
102 | * @return array
103 | */
104 | protected function organizeRegions(array $regions): array
105 | {
106 | $provinces = $cities = $districts = [];
107 | foreach ($regions as $regionData) {
108 | if (substr($regionData['code'], 2) === '0000') {
109 | $province = new Province($regionData['code'], $regionData['name']);
110 | $province->parentCode = 0;
111 | $province->shortCode = substr($regionData['code'], 0, 2);
112 | $provinces[] = $province;
113 | } elseif (substr($regionData['code'], 4) === '00') {
114 | $city = new City($regionData['code'], $regionData['name']);
115 | $city->parentCode = substr($regionData['code'], 0, 2);
116 | $city->shortCode = substr($regionData['code'], 0, 4);
117 | $cities[] = $city;
118 | } else {
119 | $area = new District($regionData['code'], $regionData['name']);
120 | $area->parentCode = substr($regionData['code'], 0, 4);
121 | $area->shortCode = $regionData['code'];
122 | $districts[] = $area;
123 | }
124 | }
125 |
126 | return [
127 | $provinces,
128 | $cities,
129 | $districts,
130 | ];
131 | }
132 |
133 | protected function buildRegionsTree($addresses, AddressInterface $address)
134 | {
135 | $children = [];
136 | foreach ($addresses as $index => $_address) {
137 | if ($_address->parentCode == $address->shortCode) {
138 | unset($addresses[$index]);
139 | $this->buildRegionsTree($addresses, $_address);
140 | $children[] = $_address;
141 | }
142 | }
143 | $address->setChildren($children);
144 | }
145 | }
--------------------------------------------------------------------------------
/resources/holidays.json:
--------------------------------------------------------------------------------
1 | [{"name":"元旦","type":"traditional","date":"01月01日"},{"name":"黑人日","type":"international","date":"01月03日"},{"name":"腊八节","type":"traditional","date":"01月05日"},{"name":"大寒","type":"solar_term","date":"01月20日"},{"name":"小年","type":"traditional","date":"01月20日"},{"name":"国际海关日","type":"international","date":"01月26日"},{"name":"除夕","type":"traditional","date":"01月27日"},{"name":"春节","type":"traditional","date":"01月28日"},{"name":"国际麻风节","type":"international","date":"01月31日"},{"name":"世界湿地日","type":"international","date":"02月02日"},{"name":"立春","type":"solar_term","date":"02月03日"},{"name":"世界抗癌症日","type":"international","date":"02月04日"},{"name":"国际声援南非日","type":"international","date":"02月7日"},{"name":"国际气象节","type":"international","date":"02月10日"},{"name":"元宵节","type":"traditional","date":"02月11日"},{"name":"情人节","type":"international","date":"02月14日"},{"name":"雨水","type":"solar_term","date":"02月18日"},{"name":"国际母语日","type":"international","date":"02月21日"},{"name":"第三世界青年日","type":"international","date":"02月24日"},{"name":"龙抬头","type":"traditional","date":"02月27日"},{"name":"国际罕见病日","type":"international","date":"02月29日"},{"name":"国际海豹日","type":"international","date":"03月01日"},{"name":"国际爱耳日","type":"international","date":"03月03日"},{"name":"惊蛰","type":"solar_term","date":"03月06日"},{"name":"学雷锋日","type":"traditional","date":"03月05日"},{"name":"三八妇女节","type":"traditional","date":"03月08日"},{"name":"植树节","type":"international","date":"03月12日"},{"name":"白色情人节","type":"international","date":"03月14日"},{"name":"消费者权益日","type":"international","date":"03月15日"},{"name":"国际航海日","type":"international","date":"03月17日"},{"name":"世界无肉日","type":"international","date":"03月20日"},{"name":"春分","type":"solar_term","date":"03月20日"},{"name":"世界睡眠日","type":"international","date":"03月21日"},{"name":"世界水日","type":"international","date":"03月22日"},{"name":"世界气象日","type":"international","date":"03月23日"},{"name":"愚人节","type":"international","date":"04月01日"},{"name":"国际儿童图书日","type":"international","date":"04月02日"},{"name":"寒食节","type":"traditional","date":"04月03日"},{"name":"清明节","type":"traditional","date":"04月04日"},{"name":"世界卫生日","type":"international","date":"04月07日"},{"name":"世界帕金森日","type":"international","date":"04月11日"},{"name":"复活节","type":"international","date":"04月16日"},{"name":"谷雨","type":"solar_term","date":"04月20日"},{"name":"世界地球日","type":"international","date":"04月22日"},{"name":"世界读书日","type":"international","date":"04月23日"},{"name":"世界儿童日","type":"international","date":"04月24日"},{"name":"知识产权日","type":"international","date":"04月26日"},{"name":"佛诞","type":"traditional","date":"04月29日"},{"name":"全国交通安全反思日","type":"international","date":"04月30日"},{"name":"国际劳动节","type":"international","date":"05月01日"},{"name":"五四青年节","type":"traditional","date":"05月04日"},{"name":"立夏","type":"solar_term","date":"05月05日"},{"name":"世界红十字日","type":"international","date":"05月08日"},{"name":"世界微笑日","type":"international","date":"05月08日"},{"name":"母亲节","type":"international","date":"05月14日"},{"name":"国际护士节","type":"international","date":"05月12日"},{"name":"国际家庭日","type":"international","date":"05月15日"},{"name":"全国助残日","type":"international","date":"05月15日"},{"name":"世界电信日","type":"international","date":"05月17日"},{"name":"国际博物馆日","type":"international","date":"05月18日"},{"name":"小满","type":"solar_term","date":"05月21日"},{"name":"五卅运动纪念","type":"traditional","date":"05月30日"},{"name":"端午节","type":"traditional","date":"05月30日"},{"name":"世界无烟日","type":"international","date":"05月31日"},{"name":"六一儿童节","type":"international","date":"06月01日"},{"name":"世界环境日","type":"international","date":"06月05日"},{"name":"芒种","type":"solar_term","date":"06月05日"},{"name":"全国爱眼日","type":"international","date":"06月06日"},{"name":"中国人口日","type":"traditional","date":"06月11日"},{"name":"父亲节","type":"international","date":"06月18日"},{"name":"世界难民日","type":"international","date":"06月20日"},{"name":"夏至","type":"solar_term","date":"06月21日"},{"name":"中国儿童慈善活动日","type":"traditional","date":"06月22日"},{"name":"国际奥林匹克日","type":"international","date":"06月23日"},{"name":"全国土地日","type":"international","date":"06月25日"},{"name":"国际禁毒日","type":"international","date":"06月26日"},{"name":"世界青年联欢节","type":"international","date":"06月30日"},{"name":"中国共产党诞生日","type":"traditional","date":"07月01日"},{"name":"香港回归日","type":"traditional","date":"07月01日"},{"name":"国际体育记者日","type":"international","date":"07月02日"},{"name":"国际接吻日","type":"international","date":"07月06日"},{"name":"小暑","type":"solar_term","date":"07月07日"},{"name":"世界人口日","type":"international","date":"07月11日"},{"name":"大暑","type":"solar_term","date":"07月22日"},{"name":"非洲妇女日","type":"international","date":"07月30日"},{"name":"八一建军节","type":"traditional","date":"08月01日"},{"name":"立秋","type":"solar_term","date":"08月07日"},{"name":"日本投降日","type":"international","date":"08月15日"},{"name":"处暑","type":"solar_term","date":"08月23日"},{"name":"七夕","type":"traditional","date":"08月28日"},{"name":"抗日战争胜利纪念日","type":"traditional","date":"09月03日"},{"name":"中元节","type":"traditional","date":"09月05日"},{"name":"白露","type":"solar_term","date":"09月07日"},{"name":"国际扫盲日","type":"international","date":"09月08日"},{"name":"教师节","type":"international","date":"09月10日"},{"name":"国际臭氧层保护日","type":"international","date":"09月16日"},{"name":"“九一八”事变纪念日","type":"traditional","date":"09月18日"},{"name":"国际和平日","type":"international","date":"09月21日"},{"name":"国际爱牙日","type":"international","date":"09月20日"},{"name":"世界无车日","type":"international","date":"09月22日"},{"name":"秋分","type":"solar_term","date":"09月23日"},{"name":"国际聋人节","type":"international","date":"09月24日"},{"name":"世界旅游日","type":"international","date":"09月27日"},{"name":"国庆节","type":"traditional","date":"10月01日"},{"name":"世界动物日","type":"international","date":"10月04日"},{"name":"中秋节","type":"traditional","date":"10月04日"},{"name":"寒露","type":"solar_term","date":"10月08日"},{"name":"世界邮政日","type":"international","date":"10月09日"},{"name":"辛亥革命纪念日","type":"traditional","date":"10月10日"},{"name":"中国少年先锋队诞辰日","type":"traditional","date":"10月13日"},{"name":"世界标准日","type":"international","date":"10月14日"},{"name":"国际盲人节","type":"international","date":"10月15日"},{"name":"世界粮食日","type":"international","date":"10月16日"},{"name":"国际消除贫困日","type":"international","date":"10月17日"},{"name":"世界传统医药日","type":"international","date":"10月22日"},{"name":"霜降","type":"solar_term","date":"10月23日"},{"name":"联合国日","type":"international","date":"10月24日"},{"name":"重阳","type":"traditional","date":"10月28日"},{"name":"世界勤俭日","type":"international","date":"10月31日"},{"name":"万圣节","type":"international","date":"10月31日"},{"name":"立冬","type":"solar_term","date":"11月07日"},{"name":"中国记者日","type":"traditional","date":"11月08日"},{"name":"世界青年节","type":"international","date":"11月10日"},{"name":"光棍节","type":"international","date":"11月11日"},{"name":"世界糖尿病日","type":"international","date":"11月14日"},{"name":"国际大学生节","type":"international","date":"11月17日"},{"name":"世界问候日","type":"international","date":"11月21日"},{"name":"小雪","type":"solar_term","date":"11月22日"},{"name":"感恩节","type":"international","date":"11月23日"},{"name":"世界艾滋病日","type":"international","date":"12月01日"},{"name":"国际残疾人日","type":"international","date":"12月03日"},{"name":"大雪","type":"solar_term","date":"12月07日"},{"name":"“一二九”运动纪念日","type":"traditional","date":"12月09日"},{"name":"世界足球日","type":"international","date":"12月09日"},{"name":"世界人权日","type":"international","date":"12月10日"},{"name":"西安事变纪念日","type":"traditional","date":"12月12日"},{"name":"南京大屠杀","type":"traditional","date":"12月13日"},{"name":"澳门回归日","type":"traditional","date":"12月20日"},{"name":"国际篮球日","type":"international","date":"12月21日"},{"name":"冬至","type":"solar_term","date":"12月22日"},{"name":"平安夜","type":"international","date":"12月24日"},{"name":"圣诞节","type":"international","date":"12月25日"}]
--------------------------------------------------------------------------------
/resources/regions/cities.json:
--------------------------------------------------------------------------------
1 | [{"code":"110100","name":"市辖区","type":"city","children":[]},{"code":"120100","name":"市辖区","type":"city","children":[]},{"code":"130100","name":"石家庄市","type":"city","children":[]},{"code":"130200","name":"唐山市","type":"city","children":[]},{"code":"130300","name":"秦皇岛市","type":"city","children":[]},{"code":"130400","name":"邯郸市","type":"city","children":[]},{"code":"130500","name":"邢台市","type":"city","children":[]},{"code":"130600","name":"保定市","type":"city","children":[]},{"code":"130700","name":"张家口市","type":"city","children":[]},{"code":"130800","name":"承德市","type":"city","children":[]},{"code":"130900","name":"沧州市","type":"city","children":[]},{"code":"131000","name":"廊坊市","type":"city","children":[]},{"code":"131100","name":"衡水市","type":"city","children":[]},{"code":"139000","name":"省直辖县级行政区划","type":"city","children":[]},{"code":"140100","name":"太原市","type":"city","children":[]},{"code":"140200","name":"大同市","type":"city","children":[]},{"code":"140300","name":"阳泉市","type":"city","children":[]},{"code":"140400","name":"长治市","type":"city","children":[]},{"code":"140500","name":"晋城市","type":"city","children":[]},{"code":"140600","name":"朔州市","type":"city","children":[]},{"code":"140700","name":"晋中市","type":"city","children":[]},{"code":"140800","name":"运城市","type":"city","children":[]},{"code":"140900","name":"忻州市","type":"city","children":[]},{"code":"141000","name":"临汾市","type":"city","children":[]},{"code":"141100","name":"吕梁市","type":"city","children":[]},{"code":"150100","name":"呼和浩特市","type":"city","children":[]},{"code":"150200","name":"包头市","type":"city","children":[]},{"code":"150300","name":"乌海市","type":"city","children":[]},{"code":"150400","name":"赤峰市","type":"city","children":[]},{"code":"150500","name":"通辽市","type":"city","children":[]},{"code":"150600","name":"鄂尔多斯市","type":"city","children":[]},{"code":"150700","name":"呼伦贝尔市","type":"city","children":[]},{"code":"150800","name":"巴彦淖尔市","type":"city","children":[]},{"code":"150900","name":"乌兰察布市","type":"city","children":[]},{"code":"152200","name":"兴安盟","type":"city","children":[]},{"code":"152500","name":"锡林郭勒盟","type":"city","children":[]},{"code":"152900","name":"阿拉善盟","type":"city","children":[]},{"code":"210100","name":"沈阳市","type":"city","children":[]},{"code":"210200","name":"大连市","type":"city","children":[]},{"code":"210300","name":"鞍山市","type":"city","children":[]},{"code":"210400","name":"抚顺市","type":"city","children":[]},{"code":"210500","name":"本溪市","type":"city","children":[]},{"code":"210600","name":"丹东市","type":"city","children":[]},{"code":"210700","name":"锦州市","type":"city","children":[]},{"code":"210800","name":"营口市","type":"city","children":[]},{"code":"210900","name":"阜新市","type":"city","children":[]},{"code":"211000","name":"辽阳市","type":"city","children":[]},{"code":"211100","name":"盘锦市","type":"city","children":[]},{"code":"211200","name":"铁岭市","type":"city","children":[]},{"code":"211300","name":"朝阳市","type":"city","children":[]},{"code":"211400","name":"葫芦岛市","type":"city","children":[]},{"code":"220100","name":"长春市","type":"city","children":[]},{"code":"220200","name":"吉林市","type":"city","children":[]},{"code":"220300","name":"四平市","type":"city","children":[]},{"code":"220400","name":"辽源市","type":"city","children":[]},{"code":"220500","name":"通化市","type":"city","children":[]},{"code":"220600","name":"白山市","type":"city","children":[]},{"code":"220700","name":"松原市","type":"city","children":[]},{"code":"220800","name":"白城市","type":"city","children":[]},{"code":"222400","name":"延边朝鲜族自治州","type":"city","children":[]},{"code":"230100","name":"哈尔滨市","type":"city","children":[]},{"code":"230200","name":"齐齐哈尔市","type":"city","children":[]},{"code":"230300","name":"鸡西市","type":"city","children":[]},{"code":"230400","name":"鹤岗市","type":"city","children":[]},{"code":"230500","name":"双鸭山市","type":"city","children":[]},{"code":"230600","name":"大庆市","type":"city","children":[]},{"code":"230700","name":"伊春市","type":"city","children":[]},{"code":"230800","name":"佳木斯市","type":"city","children":[]},{"code":"230900","name":"七台河市","type":"city","children":[]},{"code":"231000","name":"牡丹江市","type":"city","children":[]},{"code":"231100","name":"黑河市","type":"city","children":[]},{"code":"231200","name":"绥化市","type":"city","children":[]},{"code":"232700","name":"大兴安岭地区","type":"city","children":[]},{"code":"310100","name":"市辖区","type":"city","children":[]},{"code":"320100","name":"南京市","type":"city","children":[]},{"code":"320200","name":"无锡市","type":"city","children":[]},{"code":"320300","name":"徐州市","type":"city","children":[]},{"code":"320400","name":"常州市","type":"city","children":[]},{"code":"320500","name":"苏州市","type":"city","children":[]},{"code":"320600","name":"南通市","type":"city","children":[]},{"code":"320700","name":"连云港市","type":"city","children":[]},{"code":"320800","name":"淮安市","type":"city","children":[]},{"code":"320900","name":"盐城市","type":"city","children":[]},{"code":"321000","name":"扬州市","type":"city","children":[]},{"code":"321100","name":"镇江市","type":"city","children":[]},{"code":"321200","name":"泰州市","type":"city","children":[]},{"code":"321300","name":"宿迁市","type":"city","children":[]},{"code":"330100","name":"杭州市","type":"city","children":[]},{"code":"330200","name":"宁波市","type":"city","children":[]},{"code":"330300","name":"温州市","type":"city","children":[]},{"code":"330400","name":"嘉兴市","type":"city","children":[]},{"code":"330500","name":"湖州市","type":"city","children":[]},{"code":"330600","name":"绍兴市","type":"city","children":[]},{"code":"330700","name":"金华市","type":"city","children":[]},{"code":"330800","name":"衢州市","type":"city","children":[]},{"code":"330900","name":"舟山市","type":"city","children":[]},{"code":"331000","name":"台州市","type":"city","children":[]},{"code":"331100","name":"丽水市","type":"city","children":[]},{"code":"340100","name":"合肥市","type":"city","children":[]},{"code":"340200","name":"芜湖市","type":"city","children":[]},{"code":"340300","name":"蚌埠市","type":"city","children":[]},{"code":"340400","name":"淮南市","type":"city","children":[]},{"code":"340500","name":"马鞍山市","type":"city","children":[]},{"code":"340600","name":"淮北市","type":"city","children":[]},{"code":"340700","name":"铜陵市","type":"city","children":[]},{"code":"340800","name":"安庆市","type":"city","children":[]},{"code":"341000","name":"黄山市","type":"city","children":[]},{"code":"341100","name":"滁州市","type":"city","children":[]},{"code":"341200","name":"阜阳市","type":"city","children":[]},{"code":"341300","name":"宿州市","type":"city","children":[]},{"code":"341500","name":"六安市","type":"city","children":[]},{"code":"341600","name":"亳州市","type":"city","children":[]},{"code":"341700","name":"池州市","type":"city","children":[]},{"code":"341800","name":"宣城市","type":"city","children":[]},{"code":"350100","name":"福州市","type":"city","children":[]},{"code":"350200","name":"厦门市","type":"city","children":[]},{"code":"350300","name":"莆田市","type":"city","children":[]},{"code":"350400","name":"三明市","type":"city","children":[]},{"code":"350500","name":"泉州市","type":"city","children":[]},{"code":"350600","name":"漳州市","type":"city","children":[]},{"code":"350700","name":"南平市","type":"city","children":[]},{"code":"350800","name":"龙岩市","type":"city","children":[]},{"code":"350900","name":"宁德市","type":"city","children":[]},{"code":"360100","name":"南昌市","type":"city","children":[]},{"code":"360200","name":"景德镇市","type":"city","children":[]},{"code":"360300","name":"萍乡市","type":"city","children":[]},{"code":"360400","name":"九江市","type":"city","children":[]},{"code":"360500","name":"新余市","type":"city","children":[]},{"code":"360600","name":"鹰潭市","type":"city","children":[]},{"code":"360700","name":"赣州市","type":"city","children":[]},{"code":"360800","name":"吉安市","type":"city","children":[]},{"code":"360900","name":"宜春市","type":"city","children":[]},{"code":"361000","name":"抚州市","type":"city","children":[]},{"code":"361100","name":"上饶市","type":"city","children":[]},{"code":"370100","name":"济南市","type":"city","children":[]},{"code":"370200","name":"青岛市","type":"city","children":[]},{"code":"370300","name":"淄博市","type":"city","children":[]},{"code":"370400","name":"枣庄市","type":"city","children":[]},{"code":"370500","name":"东营市","type":"city","children":[]},{"code":"370600","name":"烟台市","type":"city","children":[]},{"code":"370700","name":"潍坊市","type":"city","children":[]},{"code":"370800","name":"济宁市","type":"city","children":[]},{"code":"370900","name":"泰安市","type":"city","children":[]},{"code":"371000","name":"威海市","type":"city","children":[]},{"code":"371100","name":"日照市","type":"city","children":[]},{"code":"371200","name":"莱芜市","type":"city","children":[]},{"code":"371300","name":"临沂市","type":"city","children":[]},{"code":"371400","name":"德州市","type":"city","children":[]},{"code":"371500","name":"聊城市","type":"city","children":[]},{"code":"371600","name":"滨州市","type":"city","children":[]},{"code":"371700","name":"菏泽市","type":"city","children":[]},{"code":"410100","name":"郑州市","type":"city","children":[]},{"code":"410200","name":"开封市","type":"city","children":[]},{"code":"410300","name":"洛阳市","type":"city","children":[]},{"code":"410400","name":"平顶山市","type":"city","children":[]},{"code":"410500","name":"安阳市","type":"city","children":[]},{"code":"410600","name":"鹤壁市","type":"city","children":[]},{"code":"410700","name":"新乡市","type":"city","children":[]},{"code":"410800","name":"焦作市","type":"city","children":[]},{"code":"410900","name":"濮阳市","type":"city","children":[]},{"code":"411000","name":"许昌市","type":"city","children":[]},{"code":"411100","name":"漯河市","type":"city","children":[]},{"code":"411200","name":"三门峡市","type":"city","children":[]},{"code":"411300","name":"南阳市","type":"city","children":[]},{"code":"411400","name":"商丘市","type":"city","children":[]},{"code":"411500","name":"信阳市","type":"city","children":[]},{"code":"411600","name":"周口市","type":"city","children":[]},{"code":"411700","name":"驻马店市","type":"city","children":[]},{"code":"419000","name":"省直辖县级行政区划","type":"city","children":[]},{"code":"420100","name":"武汉市","type":"city","children":[]},{"code":"420200","name":"黄石市","type":"city","children":[]},{"code":"420300","name":"十堰市","type":"city","children":[]},{"code":"420500","name":"宜昌市","type":"city","children":[]},{"code":"420600","name":"襄阳市","type":"city","children":[]},{"code":"420700","name":"鄂州市","type":"city","children":[]},{"code":"420800","name":"荆门市","type":"city","children":[]},{"code":"420900","name":"孝感市","type":"city","children":[]},{"code":"421000","name":"荆州市","type":"city","children":[]},{"code":"421100","name":"黄冈市","type":"city","children":[]},{"code":"421200","name":"咸宁市","type":"city","children":[]},{"code":"421300","name":"随州市","type":"city","children":[]},{"code":"422800","name":"恩施土家族苗族自治州","type":"city","children":[]},{"code":"429000","name":"省直辖县级行政区划","type":"city","children":[]},{"code":"430100","name":"长沙市","type":"city","children":[]},{"code":"430200","name":"株洲市","type":"city","children":[]},{"code":"430300","name":"湘潭市","type":"city","children":[]},{"code":"430400","name":"衡阳市","type":"city","children":[]},{"code":"430500","name":"邵阳市","type":"city","children":[]},{"code":"430600","name":"岳阳市","type":"city","children":[]},{"code":"430700","name":"常德市","type":"city","children":[]},{"code":"430800","name":"张家界市","type":"city","children":[]},{"code":"430900","name":"益阳市","type":"city","children":[]},{"code":"431000","name":"郴州市","type":"city","children":[]},{"code":"431100","name":"永州市","type":"city","children":[]},{"code":"431200","name":"怀化市","type":"city","children":[]},{"code":"431300","name":"娄底市","type":"city","children":[]},{"code":"433100","name":"湘西土家族苗族自治州","type":"city","children":[]},{"code":"440100","name":"广州市","type":"city","children":[]},{"code":"440200","name":"韶关市","type":"city","children":[]},{"code":"440300","name":"深圳市","type":"city","children":[]},{"code":"440400","name":"珠海市","type":"city","children":[]},{"code":"440500","name":"汕头市","type":"city","children":[]},{"code":"440600","name":"佛山市","type":"city","children":[]},{"code":"440700","name":"江门市","type":"city","children":[]},{"code":"440800","name":"湛江市","type":"city","children":[]},{"code":"440900","name":"茂名市","type":"city","children":[]},{"code":"441200","name":"肇庆市","type":"city","children":[]},{"code":"441300","name":"惠州市","type":"city","children":[]},{"code":"441400","name":"梅州市","type":"city","children":[]},{"code":"441500","name":"汕尾市","type":"city","children":[]},{"code":"441600","name":"河源市","type":"city","children":[]},{"code":"441700","name":"阳江市","type":"city","children":[]},{"code":"441800","name":"清远市","type":"city","children":[]},{"code":"441900","name":"东莞市","type":"city","children":[]},{"code":"442000","name":"中山市","type":"city","children":[]},{"code":"445100","name":"潮州市","type":"city","children":[]},{"code":"445200","name":"揭阳市","type":"city","children":[]},{"code":"445300","name":"云浮市","type":"city","children":[]},{"code":"450100","name":"南宁市","type":"city","children":[]},{"code":"450200","name":"柳州市","type":"city","children":[]},{"code":"450300","name":"桂林市","type":"city","children":[]},{"code":"450400","name":"梧州市","type":"city","children":[]},{"code":"450500","name":"北海市","type":"city","children":[]},{"code":"450600","name":"防城港市","type":"city","children":[]},{"code":"450700","name":"钦州市","type":"city","children":[]},{"code":"450800","name":"贵港市","type":"city","children":[]},{"code":"450900","name":"玉林市","type":"city","children":[]},{"code":"451000","name":"百色市","type":"city","children":[]},{"code":"451100","name":"贺州市","type":"city","children":[]},{"code":"451200","name":"河池市","type":"city","children":[]},{"code":"451300","name":"来宾市","type":"city","children":[]},{"code":"451400","name":"崇左市","type":"city","children":[]},{"code":"460100","name":"海口市","type":"city","children":[]},{"code":"460200","name":"三亚市","type":"city","children":[]},{"code":"460300","name":"三沙市","type":"city","children":[]},{"code":"460400","name":"儋州市","type":"city","children":[]},{"code":"469000","name":"省直辖县级行政区划","type":"city","children":[]},{"code":"500100","name":"市辖区","type":"city","children":[]},{"code":"500200","name":"县","type":"city","children":[]},{"code":"510100","name":"成都市","type":"city","children":[]},{"code":"510300","name":"自贡市","type":"city","children":[]},{"code":"510400","name":"攀枝花市","type":"city","children":[]},{"code":"510500","name":"泸州市","type":"city","children":[]},{"code":"510600","name":"德阳市","type":"city","children":[]},{"code":"510700","name":"绵阳市","type":"city","children":[]},{"code":"510800","name":"广元市","type":"city","children":[]},{"code":"510900","name":"遂宁市","type":"city","children":[]},{"code":"511000","name":"内江市","type":"city","children":[]},{"code":"511100","name":"乐山市","type":"city","children":[]},{"code":"511300","name":"南充市","type":"city","children":[]},{"code":"511400","name":"眉山市","type":"city","children":[]},{"code":"511500","name":"宜宾市","type":"city","children":[]},{"code":"511600","name":"广安市","type":"city","children":[]},{"code":"511700","name":"达州市","type":"city","children":[]},{"code":"511800","name":"雅安市","type":"city","children":[]},{"code":"511900","name":"巴中市","type":"city","children":[]},{"code":"512000","name":"资阳市","type":"city","children":[]},{"code":"513200","name":"阿坝藏族羌族自治州","type":"city","children":[]},{"code":"513300","name":"甘孜藏族自治州","type":"city","children":[]},{"code":"513400","name":"凉山彝族自治州","type":"city","children":[]},{"code":"520100","name":"贵阳市","type":"city","children":[]},{"code":"520200","name":"六盘水市","type":"city","children":[]},{"code":"520300","name":"遵义市","type":"city","children":[]},{"code":"520400","name":"安顺市","type":"city","children":[]},{"code":"520500","name":"毕节市","type":"city","children":[]},{"code":"520600","name":"铜仁市","type":"city","children":[]},{"code":"522300","name":"黔西南布依族苗族自治州","type":"city","children":[]},{"code":"522600","name":"黔东南苗族侗族自治州","type":"city","children":[]},{"code":"522700","name":"黔南布依族苗族自治州","type":"city","children":[]},{"code":"530100","name":"昆明市","type":"city","children":[]},{"code":"530300","name":"曲靖市","type":"city","children":[]},{"code":"530400","name":"玉溪市","type":"city","children":[]},{"code":"530500","name":"保山市","type":"city","children":[]},{"code":"530600","name":"昭通市","type":"city","children":[]},{"code":"530700","name":"丽江市","type":"city","children":[]},{"code":"530800","name":"普洱市","type":"city","children":[]},{"code":"530900","name":"临沧市","type":"city","children":[]},{"code":"532300","name":"楚雄彝族自治州","type":"city","children":[]},{"code":"532500","name":"红河哈尼族彝族自治州","type":"city","children":[]},{"code":"532600","name":"文山壮族苗族自治州","type":"city","children":[]},{"code":"532800","name":"西双版纳傣族自治州","type":"city","children":[]},{"code":"532900","name":"大理白族自治州","type":"city","children":[]},{"code":"533100","name":"德宏傣族景颇族自治州","type":"city","children":[]},{"code":"533300","name":"怒江傈僳族自治州","type":"city","children":[]},{"code":"533400","name":"迪庆藏族自治州","type":"city","children":[]},{"code":"540100","name":"拉萨市","type":"city","children":[]},{"code":"540200","name":"日喀则市","type":"city","children":[]},{"code":"540300","name":"昌都市","type":"city","children":[]},{"code":"540400","name":"林芝市","type":"city","children":[]},{"code":"540500","name":"山南市","type":"city","children":[]},{"code":"542400","name":"那曲地区","type":"city","children":[]},{"code":"542500","name":"阿里地区","type":"city","children":[]},{"code":"610100","name":"西安市","type":"city","children":[]},{"code":"610200","name":"铜川市","type":"city","children":[]},{"code":"610300","name":"宝鸡市","type":"city","children":[]},{"code":"610400","name":"咸阳市","type":"city","children":[]},{"code":"610500","name":"渭南市","type":"city","children":[]},{"code":"610600","name":"延安市","type":"city","children":[]},{"code":"610700","name":"汉中市","type":"city","children":[]},{"code":"610800","name":"榆林市","type":"city","children":[]},{"code":"610900","name":"安康市","type":"city","children":[]},{"code":"611000","name":"商洛市","type":"city","children":[]},{"code":"620100","name":"兰州市","type":"city","children":[]},{"code":"620200","name":"嘉峪关市","type":"city","children":[]},{"code":"620300","name":"金昌市","type":"city","children":[]},{"code":"620400","name":"白银市","type":"city","children":[]},{"code":"620500","name":"天水市","type":"city","children":[]},{"code":"620600","name":"武威市","type":"city","children":[]},{"code":"620700","name":"张掖市","type":"city","children":[]},{"code":"620800","name":"平凉市","type":"city","children":[]},{"code":"620900","name":"酒泉市","type":"city","children":[]},{"code":"621000","name":"庆阳市","type":"city","children":[]},{"code":"621100","name":"定西市","type":"city","children":[]},{"code":"621200","name":"陇南市","type":"city","children":[]},{"code":"622900","name":"临夏回族自治州","type":"city","children":[]},{"code":"623000","name":"甘南藏族自治州","type":"city","children":[]},{"code":"630100","name":"西宁市","type":"city","children":[]},{"code":"630200","name":"海东市","type":"city","children":[]},{"code":"632200","name":"海北藏族自治州","type":"city","children":[]},{"code":"632300","name":"黄南藏族自治州","type":"city","children":[]},{"code":"632500","name":"海南藏族自治州","type":"city","children":[]},{"code":"632600","name":"果洛藏族自治州","type":"city","children":[]},{"code":"632700","name":"玉树藏族自治州","type":"city","children":[]},{"code":"632800","name":"海西蒙古族藏族自治州","type":"city","children":[]},{"code":"640100","name":"银川市","type":"city","children":[]},{"code":"640200","name":"石嘴山市","type":"city","children":[]},{"code":"640300","name":"吴忠市","type":"city","children":[]},{"code":"640400","name":"固原市","type":"city","children":[]},{"code":"640500","name":"中卫市","type":"city","children":[]},{"code":"650100","name":"乌鲁木齐市","type":"city","children":[]},{"code":"650200","name":"克拉玛依市","type":"city","children":[]},{"code":"650400","name":"吐鲁番市","type":"city","children":[]},{"code":"650500","name":"哈密市","type":"city","children":[]},{"code":"652300","name":"昌吉回族自治州","type":"city","children":[]},{"code":"652700","name":"博尔塔拉蒙古自治州","type":"city","children":[]},{"code":"652800","name":"巴音郭楞蒙古自治州","type":"city","children":[]},{"code":"652900","name":"阿克苏地区","type":"city","children":[]},{"code":"653000","name":"克孜勒苏柯尔克孜自治州","type":"city","children":[]},{"code":"653100","name":"喀什地区","type":"city","children":[]},{"code":"653200","name":"和田地区","type":"city","children":[]},{"code":"654000","name":"伊犁哈萨克自治州","type":"city","children":[]},{"code":"654200","name":"塔城地区","type":"city","children":[]},{"code":"654300","name":"阿勒泰地区","type":"city","children":[]},{"code":"659000","name":"自治区直辖县级行政区划","type":"city","children":[]}]
--------------------------------------------------------------------------------