6月二十五号开始,CSDN首页就一直在推送关于爬取网易云音乐评论的的相关文章,但是,能力有限,对于做了反爬虫处理的就弄不来了。最近在学网页中的三级联动,但是没有找到关于省份、城市、县区的数组,只能列出简单的几个示范,就意外看到了2017年统计用区划代码,查看源码也是将包括了信息展示的,可以拿来练练手。开始呢,观摩了一下这个结构,省份名前都是带有简短的html地址的,不过需要拼接;并且下一级再下一级也都是一样的,所以我只需要写一个方法就可以把所有的信息(省+市区+县区)都给读取出来。
为了让自己能够有个可视化的操作,用类似节点的方式,自己看的更加明白些,就多写了个创建文件夹的方法。
效果就是和上面这样。当然这个可以扩展,起初只是可视化一下,下一篇写JDBC的,将信息保存到数据库。
具体的实现需要jsoup包,用于解析html的代码类库。
我们需要借助包的几个方法
第一:(注意:别导错了包)
第二:就OK了。html()的返回类型就是一个String类型。他会把所有的源码变成一个带格式的字符串输出
(注意:别导错了包)
以下就是简单的爬去网页源码。
至于userAgent().get()的特殊请求可以参照大牛的博客。
我写的是将其拆分成一个数组,并用正则表达式中的分组获取到我需要的数据,省的信息暂时保存在home.txt文件当中,而创建文件夹就是读取其中的数据,并根据其中拼接的网址,继续传入方法。照此循环。创建了有336个文件。我的电脑运行看七八分钟吧。至于没有再继续往县级别创建文件夹是怕电脑会烧坏。
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BootMain {
/**
* 创建Pattern对象,放入正则表达式
*/
static Pattern p=Pattern.compile("(\\d+\\.html)\">([\\u4e00-\\u9fa5]{2,8}[市省区县乡镇会乡])");
static Pattern pFileName=Pattern.compile("[\\u4e00-\\u9fa5]{2,8}[市省区县乡镇会乡]");
static BufferedReader bw=null;
static RobotAddress robotAddress=new RobotAddress();
static String indexURL="http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2017/";
BootMain m=new BootMain();
public static void main(String[] args) {
File file=new File("Address");
if (!file.exists()){
file.mkdir();
}
/**
第一步获取所有的省份地址,并创建省级文件夹
*/
String homeFilePath="Address\\home.txt";
//首先获取主页的数据加上主页的后缀
robotAddress.home(indexURL+"index.html",homeFilePath,1);
//调用创建文件夹创建,创建各城市的文件夹
robotAddress.newFolder(homeFilePath,"Address\\");
System.out.println("省级文件夹创建成功!开始创建市级城市文件夹");
/**
* 第二步
* 需要循环读取home中的网址信息,传入到两个方法中
* 我在这边需要循环读取home的城市信息,输出到方法当中
*/
BufferedReader br=null;
try {
//读取的文件
br=new BufferedReader(new FileReader(homeFilePath));
String shear="";
while ((shear=br.readLine())!=null){
String name=shear.substring(shear.lastIndexOf("#")+1);
String url=shear.substring(0,shear.lastIndexOf("#"));
String saveFilePath="Address\\"+name+"\\"+name+".txt";
//固定网址+各省份的地址----各省份的名字
robotAddress.home(url,saveFilePath,2);
}
br.close();
System.out.println("市级城市文件夹创建成功!开始创建区县文件夹");
/**
* 第三步 获取每个子文件中的信息-再创建市/区的文件夹
* 再通过home.txt文件信息,拿到省的名字,拿到其根目录下的xx省.txt文件,传入newFolder方法,
*/
String[] provinceNameLists=file.list();
//输出其目录下的文件列表
for (int i = 0; i <provinceNameLists.length ; i++) {
//判断是否为文件夹 获取文件夹中子文本信息
//folder--Address\\江西\\
String folder="Address\\"+provinceNameLists[i]+"\\";
//provinceInfoPath--Address\\江西\\江西省.txt
String provinceInfoPath=folder+provinceNameLists[i]+".txt";
//传入到出创建文件夹方法中
if (provinceNameLists[i].indexOf(".")==-1){
robotAddress.newFolder(provinceInfoPath,folder);
/**
* 第四步 获取每个子文件中的信息,传入home方法。
*/
File cityFile =new File(folder+"\\");
//将个省份的城市名称放入数组
String[] cityNameLists=cityFile.list();
//传入创建文件夹方法
for (int j = 0; j <cityNameLists.length ; j++) {
if (cityNameLists[j].indexOf(".")==-1){
//cityNamePath--Address\\江西省\\上饶市\\
String cityNamePath=folder+"\\"+cityNameLists[j];
//读取写入的城市信息
br=new BufferedReader(new FileReader(provinceInfoPath));
while ((shear=br.readLine())!=null){
String name=shear.substring(shear.lastIndexOf("#")+1);
String url=shear.substring(0,shear.lastIndexOf("#"));
//保存 市级城市信息文件的地址---Address\\江西省\\上饶市\\上饶市.txt
String saveFilePath=cityNamePath+"\\"+cityNameLists[j]+".txt";
//固定网址+各省份的地址----各省份的名字
robotAddress.home(url,saveFilePath,2);
//创建文件夹--各市中的县级文件夹
robotAddress.newFolder(saveFilePath,cityNamePath+"\\"+name+"\\");
}
br.close();
}
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
public class RobotAddress {
/**
*保存html地址到本地
* @param URL 爬取的地址
* @param saveFilePath 关键字信息保存的地址
* @param order 程序运行的步骤
*/
public void home(String URL,String saveFilePath,int order){
BufferedWriter bw=null;
//暂时储存为HTMl源码的路径
String deleteUrl="Address\\test.txt";
try {
Document document=Jsoup.connect(URL).userAgent("").get();
String[] htmls=document.html().split("\n");
//创建新的文件对象,写入
bw=new BufferedWriter(new FileWriter(saveFilePath));
for (int i = 0; i <htmls.length ; i++) {
Matcher m= BootMain.p.matcher(htmls[i]);
//符合我要爬的内容,写入文档
if (m.find()){
switch (order){
case 1:
/*
第一步-写入每个省份的信息到home.txt
*/
bw.write(BootMain.indexURL+m.group(1)+"#"+m.group(2));
break;
case 2:
/*
第二步-写入对应省份的子文件夹
*/
bw.write(URL.substring(0,URL.lastIndexOf("."))+"/"+m.group(1)+"#"+m.group(2));
break;
default:
break;
}
bw.newLine();
}
}
//关闭流
bw.close();
System.out.println("^_^写入成功");
} catch (Exception e) {
//捕捉异常-保证继续运行
Date d=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
bw=new BufferedWriter(new FileWriter("Address\\Exception.txt",true));
//写入错误情况下的 地址-错误信息-时间
bw.write(URL+"\t"+e.toString()+"\t"+sdf.format(d));
bw.newLine();
System.out.println(e);
} catch (IOException e1) {
System.out.println(e1);
}
}finally {
//关闭资源
if (bw!=null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 读取主页txt获取其中的 城市的URL并创建相应的文件
* 需要传入地址
* @param infoPath 1.读取城市信息的路径(本地)(动态变化的)
* @param folder 2.创建文件夹的父级文件夹(动态变化)
*/
public void newFolder(String infoPath,String folder) {
try {
File file = null;
//读取的文件
BufferedReader br = new BufferedReader(new FileReader(infoPath));
String shear = null;
while ((shear = br.readLine()) != null) {
String name = shear.substring(shear.indexOf("#") + 1);
//将读取到的地址名拿出来放File路径当中,文件名为截取出来的对象
file = new File(folder+ name);
//创建文件目录
file.mkdir();
}
br.close();
} catch (Exception e) {
//捕捉异常-保证继续运行
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("Address\\Exception.txt", true));
//写入错误情况下的 地址-错误信息-时间
bw.write(infoPath + "\t" + e.toString() + "\t" + sdf.format(d));
bw.newLine();
System.out.println(e);
} catch (IOException e1) {
System.out.println(e1);
}
}
}
}写的
比较乱吧。欢迎交流。下载地址。其中删除了部分城市文件夹。在后期文章会写入数据库、展示在html。