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。