基于 selenium 爬虫 抓取统计局省市县区域数据

本贴最后更新于 2236 天前,其中的信息可能已经事过景迁

前言

在做用户收货地址管理的时候  需要用到省 市 县 城镇 数据 
但是网上普遍都只有 省 市 县 而没有城镇(街道)的数据
于是就自己动手 丰衣足食了~
顺便记录一下 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 浏览器)

QQ20180831144335jpg

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

QQ20180831150245jpg

接下来就是代码初始化了

//配置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 标签里面

QQ20180831161445jpg

先爬取省份 代码如下:

    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 标签取出

QQ20180831164305jpg

代码如下

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;
    }
}
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3453 回帖 • 203 关注
  • Selenium
    16 引用 • 13 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...