首先需要下载相关的依赖包,我用的是eclipse,直接百度maven然后搜索相应的依赖放到pom文件中就行了。
爬取的网址为:http://info.sporttery.cn/football/match_result.php
代码的大致步骤为:
1.用scanner输入需要爬取的起始日期和截止日期
2.用URL和openStream将起始日期到截止日期的网页下载到本地,由于可能会有很多页,所以就需要先知道page数再按照page逐页下载。
3.用indexOf("html")提取本地的HTML文件,并按照名称排序。
4.用Jsoup解析HTML文件,表头只需要首次解析时提取,表内容则每次都需要读取。
5.用XSSFWorkbook 将解析的文本写入excel。
6.用delete方法删除已下载到本地的HTML文件。
完整代码如下:
package com.xlh.bd.internal.service;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Scanner;
import org.apache.commons.io.FileUtils;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class SpiderSgkjService {
/**
* 爬取500网竞彩足球的赛果开奖数据
*/
public static String startDate = null; //起始日期
public static String endDate = null; //截止日期
public static List<String> result = new ArrayList<String>();
public static int titleLen = 0;
// volatile boolean keepRunning = true; //volatile保证了线程可以正确的读取其他线程写入的值
// private final Object lockobj = new Object();
public static String url = "http://info.sporttery.cn/football/match_result.php?page=";
public static List<String> urlList = new ArrayList<String>(); //网页列表
public static List<String> timeList = new ArrayList<String>(); //时间列表
public static int pageCount = 0;
public void getUrlList() throws IOException{
DateFormat format2 = new SimpleDateFormat("yyyy-MM-dd"); //字符串时间格式
Scanner sc = new Scanner(System.in);
System.out.println("请输入起始日期,格式为yyyy-MM-dd:");
startDate = sc.next();
@SuppressWarnings("unused")
Date date = null;
try {
date = (Date)format2.parse(startDate);
} catch (ParseException e) {
System.out.println("起始日期输入格式错误");
e.printStackTrace();
}
Scanner sc2 = new Scanner(System.in);
System.out.println("请输入截止日期,格式为yyyy-MM-dd:");
endDate = sc2.next();
@SuppressWarnings("unused")
Date date2 = null;
try {
date2 = (Date)format2.parse(endDate);
} catch (ParseException e) {
System.out.println("截止日期输入格式错误");
e.printStackTrace();
}
sc.close();
sc2.close();
String url2 = url +1+"&search_league=0&start_date="+startDate+"&end_date="+endDate;
Document doc = Jsoup.connect(url2).get(); //从URL直接加载 HTML 文档
// Element content = doc.getElementById("headerTr");//得到id为headerTr的所有东西
Elements links = doc.getElementsByClass("m-page");
for (Element element : links) {
String linkText2 = element.text();//得到<td>...</td>里面的内容
int first = linkText2.indexOf("有");//要提取的字符串起始位置
int last = linkText2.indexOf("场");//要提取的字符串终止位置
pageCount = (int) Math.ceil(Double.parseDouble(linkText2.substring(first+1, last))/30);
System.out.println("共有"+pageCount+"页需要爬取,请耐心等耐!");
}
}
public class ReadHtml extends Thread {
private String s = null;
public ReadHtml(String s){
this.s = s ;
}
public void run(){
System.out.println("正在下载"+s);
for (int i=1; i<=pageCount; i++) {
String url2 = url + i +"&search_league=0&start_date="+startDate+"&end_date="+endDate;
System.out.println("Page" + i + "starts!");
try {
File dest = new File("src/page" + i +".html");
InputStream is; //接收字节输入流
FileOutputStream fos = new FileOutputStream(dest); //字节输出流
URL temp = new URL(url2); //加载网页
is = temp.openStream();
BufferedInputStream bis = new BufferedInputStream(is);//为字节输入流加缓冲
BufferedOutputStream bos = new BufferedOutputStream(fos);//为字节输出流加缓冲
int length;
byte[] bytes = new byte[1024*20];
while((length = bis.read(bytes, 0, bytes.length)) != -1){
fos.write(bytes, 0, length);
}
bos.close();
fos.close();
bis.close();
is.close();
sleep(10); //间隔0.01秒
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static List<File> listHtmlFiles(String path){
File file = new File(path); //读取本地html的路径
File[] array = file.listFiles(); //用于存储路径下的文件名
List<File> array2 = new ArrayList<File>();
for(int i=0;i<array.length;i++){
if(array[i].isFile()&&array[i].getName().indexOf("html")>-1){
array2.add(array[i]);
}
}
List<Integer> num = new ArrayList<Integer>();
for(int i=0;i<array2.size();i++){
String string = array2.get(i).toString();
int first = string.indexOf("page");
int last = string.indexOf(".");
num.add(Integer.parseInt(string.substring(first+"page".length(), last)));
}
Collections.sort(num); //按值排序
List<String> num2 = new ArrayList<String>();
for (Integer integer : num) {
num2.add("page"+String.valueOf(integer)+".html");
}
List<File> array3 = new ArrayList<File>();
for(int i=0;i<num2.size();i++){
for (File file2 : array2) {
if(file2.toString().contains(num2.get(i))) array3.add(file2);
}
System.out.println(array3.get(i));
}
return array3;
}
public static void getLocalhtml(String path) { //解析本地的html
List<File> array = listHtmlFiles(path);
//循环读取并解析这些文件
for(int i=0; i<array.size(); i++){
try{
//文件名字
System.out.println("正在解析网址:" + array.get(i).getName()+"!");
//下面开始解析本地的html
Document doc = Jsoup.parse(array.get(i), "gb2312");
Elements links = doc.getElementsByClass("match_list");//分离出class="match_list"的所有东西
Element link = links.get(0);
if(i==0){ //仅第一次需要读取表头
Elements links2 = link.getElementsByTag("th");
List<String> title = new ArrayList<String>();
for (Element element : links2) {
String linkText2 = element.text();//得到<th>...</th>里面的内容
title.add(linkText2);
result.add(linkText2);
}
titleLen = title.size();
// System.out.println(titleLen);
}
Element link2 = links.get(1);
Elements links22 = link2.getElementsByTag("td");
for (int j=0; j<links22.size()-2; j++) { //读取表的内容
String linkText22 = links22.get(j).text();//得到<td>...</td>里面的内容
result.add(linkText22);
}
System.out.println(array.get(i).getName()+"解析完毕!");
} catch (Exception e) {
System.out.println("网址:" + array.get(i).getName() + "解析出错");
e.printStackTrace();
continue;
}
}
}
public static void writeExcel(String path) throws IOException{ //将网页数据写入excel
getLocalhtml(path);
//创建一个文件
File file2 = new File(path+"pioTest2.xlsx");
file2.createNewFile();
//将excel数据存盘
FileOutputStream stream2 = FileUtils.openOutputStream(file2);
//创建excel工作簿(最后需要往里写数据)
XSSFWorkbook workbook2 = new XSSFWorkbook();
XSSFSheet sheet2 = workbook2.createSheet();//创建sheet
System.out.println("正在写入excel!");
for (int i = 0; i < result.size()/titleLen; i++) { //创建行
XSSFRow row2 = sheet2.createRow(i);
for (int j = i*titleLen; j < (i+1)*titleLen; j++) { //创建单元格
XSSFCell cell2 = row2.createCell(j-i*titleLen);
cell2.setCellValue(result.get(j));
}
}
workbook2.write(stream2);
stream2.close();
workbook2.close();
System.out.println("写入完毕!");
}
public static void deleteHtml(String path){ //删除path下的html文件
File file = new File(path);
File[] files = file.listFiles();
for (File file2 : files) {
if(file2.getName().indexOf("html")>-1) file2.delete();
}
}
public static void main(String[] args) throws ParseException, IOException, InterruptedException {
SpiderSgkjService ss = new SpiderSgkjService();
ss.getUrlList();
ReadHtml rt = ss.new ReadHtml("500网竞彩足球赛果开奖数据!");
rt.start();
try {
rt.join(); //保证网页读取完毕
System.out.println();
} catch (InterruptedException e) {
e.printStackTrace();
}
String path = "D:\\xlh\\src\\";
writeExcel(path);
deleteHtml(path);
}
}
至于Thread是为了可以多线程爬取,比如把football换成basketball就可以再同时爬取篮球的数据,这里就没有加上,有需要的自己将url中的football设置成变量,同时在main函数中多生成一个ReadHtml类和rt同时start就行了。