前言

在做用户收货地址管理的时候 需要用到省 市 县 城镇 数据
但是网上普遍都只有 省 市 县 而没有城镇(街道)的数据
于是就自己动手 丰衣足食了~
顺便记录一下 selenium 爬虫的使用

国家统计局官方地址

http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2017/index.html

安装Selenium

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.14.0</version>
        </dependency>

安装Chrom Driver驱动 (使用Chrom浏览器爬取)

导入Chrom Driver支持的Maven

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-chrome-driver</artifactId>
            <version>3.9.1</version>
        </dependency>

除了导入Maven 还需要导入驱动

驱动下载地址 https://www.seleniumhq.org/download/

可以看到 支持的浏览器比较多 我这里选择的是谷歌的 Google Chrome Driver (需要本机安装Chrome 浏览器)

aaac792ad8cc410a97cee046e2dfa61a_QQ20180831144335.jpg

选择运行环境下载 有Linux Mac Window的驱动

559ad14d24aa4d7fa629a7370ec185af_QQ20180831150245.jpg

接下来就是代码初始化了

	//配置ChromeDriver驱动路径
	System.setProperty("webdriver.chrome.driver", "/driver/chromedriver_win32/chromedriver.exe");
	//构建 WebDriver
	WebDriver webDriver = new ChromeDriver();

安装Phantomjs无头浏览器驱动 (使用Phantomjs爬取)

调用Chrome 驱动的话 会自动打开Chrome浏览器进行调试

而大部分情况下 应该是不需要去打开Chrome浏览器的 这时候就可以用Phantomjs驱动了
下载地址是:http://phantomjs.org/download.html
选择对应的环境下载 有Windows Linux Mac
下载了驱动后 还需要导入一个Maven 然后就是初始化了

        <dependency>
            <groupId>com.github.detro</groupId>
            <artifactId>ghostdriver</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.seleniumhq.selenium</groupId>
                    <artifactId>selenium-java</artifactId>
                </exclusion>
            </exclusions>
            <version>2.1.0</version>
        </dependency>

代码初始化

			//配置phantomjs 驱动路径
        System.setProperty("phantomjs.binary.path",  "/driver/windows/phantomjs.exe");
        WebDriver webDriver = new PhantomJSDriver();

解析数据

我们打开 要爬取的网站:http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2017/index.html 然后打开开发者模式

可以看到 每一行的省份 都在每一个 class为provincetr的tr标签里 而每一个省份 又在provincetr里面的td标签 中的a标签里面

d3f18fde4c1d4abb8108cb9338f15beb_QQ20180831161445.jpg

先爬取省份 代码如下:

        File file = new File("");
		//配置驱动路径
        System.setProperty("webdriver.chrome.driver", file.getAbsolutePath() + "/driver/chromedriver_win32/chromedriver.exe");
        WebDriver webDriver = new ChromeDriver();

        webDriver.get("http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2017/index.html");
        //查询classname为provincetr的标签
        List<WebElement> provincetr = webDriver.findElements(By.className("provincetr"));
        for (WebElement webElement : provincetr) {
            //按标签名查找   查找a标签
            List<WebElement> a = webElement.findElements(By.tagName("a"));
            for (WebElement element : a) {
                System.out.println("省份:"+element.getText());
            }
        }

最后输出结果如下 (我就不全部贴出来了)

省份:北京市
省份:天津市
省份:河北省
.....

然后我们接着分析城市数据 从省份 随便点一个进入

这时候可以看到 每一行是 代码 和 城市名称 而每一行都在 class 为 citytr的tr标签中

tr标签里又有两个a标签 第一个是 区划代码的a标签 第二个 是 城市的a标签 我们把第二个a标签取出

9c3d7b51df484187b16e00099c77e5bd_QQ20180831164305.jpg

代码如下

    public static void main(String args[]) {
        File file = new File("");
        System.setProperty("webdriver.chrome.driver", file.getAbsolutePath() + "/driver/chromedriver_win32/chromedriver.exe");
        System.setProperty("phantomjs.binary.path", file.getAbsolutePath() + "/driver/windows/phantomjs.exe");

        WebDriver webDriver = new ChromeDriver();
        webDriver.get("http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2017/index.html");
        //查询classname为provincetr的标签
        List<WebElement> provincetr = webDriver.findElements(By.className("provincetr"));
        for (WebElement webElement : provincetr) {
            //按标签名查找   查找a标签
            List<WebElement> a = webElement.findElements(By.tagName("a"));
            for (WebElement element : a) {
                System.out.println("省份:" + element.getText());
                //获取a标签的跳转链接
                String src = element.getAttribute("href");
                //读取市的数据
                scannerCity(src);
            }
        }
    }

    public static void scannerCity(String src) {
        WebDriver webDriver = new PhantomJSDriver();
        webDriver.get(src);
        List<WebElement> citytr = webDriver.findElements(By.className("citytr"));
        for (WebElement webElement : citytr) {
            List<WebElement> aTag = webElement.findElements(By.tagName("a"));
            WebElement city = aTag.get(1);
            System.out.println("城市:" + city.getText());
        }
        //释放
        webDriver.close();
    }

输出结果如下:

省份:北京市
	城市:市辖区
省份:天津市
	城市:市辖区
省份:河北省
	城市:石家庄市
	城市:唐山市
	....

完整的解析省市区 城镇代码

这里是整体 解析数据的代码

	public class GetRegion {
	    static {
	        File file = new File("");
	        System.setProperty("webdriver.chrome.driver", file.getAbsolutePath() + "/driver/chromedriver_win32/chromedriver.exe");
	        System.setProperty("phantomjs.binary.path", file.getAbsolutePath() + "/driver/windows/phantomjs.exe");
	
	    }
	
	    /**
	     * 构建四个爬虫进程
	     */
	    private static WebDriver provinceDriver = new ChromeDriver();
	    private static WebDriver cityDriver = new ChromeDriver();
	    private static WebDriver countyDriver = new ChromeDriver();
	    private static WebDriver towntrDriver = new ChromeDriver();
	
	    public static void main(String args[]) throws IOException, InterruptedException {
	        LinkedList<RegionEntry> linkedList = new LinkedList<>();
	        provinceDriver.get("http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2017/index.html");
	        //查询classname为provincetr的标签
	        List<WebElement> provincetr = provinceDriver.findElements(By.className("provincetr"));
	        for (WebElement webElement : provincetr) {
	            //按标签名查找   查找a标签
	            List<WebElement> a = webElement.findElements(By.tagName("a"));
	            for (WebElement element : a) {
	                System.out.println("省份:"+element.getText());
	                RegionEntry provinceRegionEntity = new RegionEntry();
	                provinceRegionEntity.setType(1);
	                provinceRegionEntity.setName(element.getText());
	                //构建一个ID
	                provinceRegionEntity.setId(IdGeneratorCore.generatorId());
	
	                linkedList.add(provinceRegionEntity);
	                //获取a标签的跳转链接
	                String src = element.getAttribute("href");
	                //读取市的数据
	                LinkedList<RegionEntry> citys = scannerCity(provinceRegionEntity.getId(), src);
	                linkedList.addAll(citys);
	            }
	        }
	        Gson gson = new Gson();
	        String toJson = gson.toJson(linkedList);
	        Files.write(toJson.getBytes(), new File("D://region.json"));
	        System.out.println("处理完毕");
	        // close 方法:关闭当前窗口,如果浏览器是当前打开的最后一个窗口,则退出浏览器
	        provinceDriver.close();
	        cityDriver.close();
	        countyDriver.close();
	        towntrDriver.close();
	        //quit  退出此驱动程序,关闭每个关联窗口。
	        provinceDriver.quit();
	        cityDriver.quit();
	        countyDriver.quit();
	        towntrDriver.quit();
	    }
	
	    /**
	     * 扫描 城市
	     *
	     * @param supperId
	     * @param src
	     * @return
	     */
	    public static LinkedList<RegionEntry> scannerCity(Long supperId, String src) throws InterruptedException {
	
	        LinkedList<RegionEntry> linkedList = new LinkedList<>();
	        cityDriver.get(src);
	        List<WebElement> citytr = cityDriver.findElements(By.className("citytr"));
	        for (WebElement webElement : citytr) {
	            List<WebElement> aTag = webElement.findElements(By.tagName("a"));
	            WebElement city = aTag.get(1);
	            if (aTag == null || aTag.size() <= 1) {
	                continue;
	            }
	            System.out.println("    城市:"+webElement.getText());
	            RegionEntry cityRegionEntity = new RegionEntry();
	            cityRegionEntity.setType(2);
	            cityRegionEntity.setName(city.getText());
	            cityRegionEntity.setId(IdGeneratorCore.generatorId());
	            cityRegionEntity.setSupperId(supperId);
	            linkedList.add(cityRegionEntity);
	
	            //扫描县城
	            LinkedList<RegionEntry> countys = scannerCounty(cityRegionEntity.getId(), city.getAttribute("href"));
	            linkedList.addAll(countys);
	        }
	        return linkedList;
	    }
	
	    /**
	     * 扫描区县
	     *
	     * @param supperId
	     * @param src
	     * @return
	     */
	    public static LinkedList<RegionEntry> scannerCounty(Long supperId, String src) throws InterruptedException {
	        LinkedList<RegionEntry> linkedList = new LinkedList<>();
	        countyDriver.get(src);
	        List<WebElement> countytr = countyDriver.findElements(By.className("countytr"));
	        for (WebElement webElement : countytr) {
	            List<WebElement> aTag = webElement.findElements(By.tagName("a"));
	            if (aTag == null || aTag.size() <= 1) {
	                continue;
	            }
	            System.out.println("        区县:"+webElement.getText());
	            WebElement county = aTag.get(1);
	            RegionEntry countytrRegions = new RegionEntry();
	            countytrRegions.setType(3);
	            countytrRegions.setName(county.getText());
	            countytrRegions.setId(IdGeneratorCore.generatorId());
	            countytrRegions.setSupperId(supperId);
	            linkedList.add(countytrRegions);
	
	            LinkedList<RegionEntry> countys = scannerTowntr(countytrRegions.getId(), county.getAttribute("href"));
	            linkedList.addAll(countys);
	        }
	        return linkedList;
	    }
	
	    /**
	     * 扫描城镇(街道)
	     *
	     * @param supperId
	     * @param src
	     * @return
	     */
	    public static LinkedList<RegionEntry> scannerTowntr(Long supperId, String src) throws InterruptedException {
	        Thread.sleep(100);
	        LinkedList<RegionEntry> linkedList = new LinkedList<>();
	        towntrDriver.get(src);
	        List<WebElement> towntr = towntrDriver.findElements(By.className("towntr"));
	        for (WebElement webElement : towntr) {
	            List<WebElement> aTag = webElement.findElements(By.tagName("a"));
	            WebElement towntrWebElement = aTag.get(1);
	            if (aTag == null || aTag.size() <= 1) {
	                continue;
	            }
	            System.out.println("            街道:"+towntrWebElement.getText());
	            RegionEntry towntrRegionEntity = new RegionEntry();
	            towntrRegionEntity.setType(4);
	            towntrRegionEntity.setName(towntrWebElement.getText());
	            towntrRegionEntity.setId(IdGeneratorCore.generatorId());
	            towntrRegionEntity.setSupperId(supperId);
	            linkedList.add(towntrRegionEntity);
	        }
	        //释放
	        return linkedList;
	    }
	}