首先需要下载相关的依赖包,我用的是eclipse,直接百度maven然后搜索相应的依赖放到pom文件中就行了。
爬取的网址为:http://info.sporttery.cn/roll/fb_list.php?s=&c=%CF%FA%C1%BF%B9%AB%B8%E6&2
代码的大致步骤为:
1.先用URL和openStream将销量公告所有时期的网页下载到本地,由于可能会有很多页,所以就需要先知道page数再按照page逐页下载。
2.用indexOf("html")提取本地的HTML文件,并按照名称排序(这里涉及到page10和page2的排序规则,正常的是2在前面,但因为是字符串所以page10排在了前面,所以需要特殊处理,处理方法见listHtmlFiles方法)。
3.用Jsoup解析HTML文件,将每周公告对应的链接保存到linkedHref中
4.用scanner输入需要爬取的起始日期和截止日期,并用matchHtml方法提取该时间段的每周销量公告对应的链接
5.用Jsoup解析所需爬取的HTML文件,将图片对应的链接保存到PhotoHtmlList中。
6.用URL链接图片地址,并用ByteArrayOutputStream将图片保存为jpg格式。
7.用delete方法删除已下载到本地的HTML文件。
完整代码如下:
package com.xlh.bd.internal.service;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
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 SpiderXlggService {
/**
* 爬取销量公告数据
*/
public static String startDate = null; //起始日期
public static String endDate = null; //截止日期
public static List
public static String url = "http://info.sporttery.cn/roll/fb_list.php?c=%CF%FA%C1%BF%B9%AB%B8%E6&&page=";
public static List
public static List
public static List
public static int pageCount = 0;
public void getAllUrlList() throws IOException{
String url2 = url +1;
Document doc = Jsoup.connect(url2).get(); //从URL直接加载 HTML 文档
Elements links = doc.getElementsByClass("m-page");
for (Element element : links) {
Elements links2 = element.getElementsByTag("a");//得到... 里面的内容
String linkText = null;
for (Element element2 : links2) {
linkText = element2.attr("href"); //读取href的值
}
int first = linkText.indexOf("page=");
int last = linkText.indexOf("&&");
pageCount = (int) Math.ceil(Double.parseDouble(linkText.substring(first+"page=".length(), last)));
System.out.println("共有"+pageCount+"页需要爬取,请耐心等耐!");
}
}
public class ReadAllHtml extends Thread {
private String s = null;
public ReadAllHtml(String s){
this.s = s ;
}
public void run(){
System.out.println("正在下载"+s);
for (int i=1; i<=pageCount; i++) {
String url2 = url + i;
System.out.println("Page" + i + "starts!");
try {
File dest = new File("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 file = new File(path); //读取本地html的路径
File[] array = file.listFiles(); //用于存储路径下的文件名
List
for(int i=0;i
array2.add(array[i]);
}
}
List
for(int i=0;i
int first = string.indexOf("page");
int last = string.indexOf(".");
num.add(Integer.parseInt(string.substring(first+"page".length(), last)));
}
Collections.sort(num); //按值排序
List
for (Integer integer : num) {
num2.add("page"+String.valueOf(integer)+".html");
}
List
for(int i=0;i
if(file2.toString().contains(num2.get(i))) array3.add(file2);
}
}
return array3;
}
public static void getLocalhtml(String path) { //解析本地的html
List
//循环读取并解析这些文件
for(int i=0; i
//文件名字
System.out.println("正在解析网址:" + array.get(i).getName()+"!");
//下面开始解析本地的html
Document doc = Jsoup.parse(array.get(i), "gb2312");
Elements links = doc.getElementsByClass("List_L FloatL");//分离出class="List_L FloatL"的所有东西
for (Element link : links) {
Elements links2 = link.getElementsByTag("li");
for (Element element : links2) {
Elements links3 = element.getElementsByTag("a");//得到... 里面的内容
for (Element element3 : links3) {
String linkText2 = element3.attr("href");//得到... 里面的内容
if(!linkText2.contains("销量公告")) linkedHref.add(linkText2);
}
}
}
System.out.println(array.get(i).getName()+"解析完毕!");
} catch (Exception e) {
System.out.println("网址:" + array.get(i).getName() + "解析出错");
e.printStackTrace();
continue;
}
}
// for (String string:linkedHref) {
// System.out.println(string);
// }
}
public static void matchHtml() throws IOException{
DateFormat format2 = new SimpleDateFormat("yyyy/MMdd"); //字符串时间格式
Scanner sc = new Scanner(System.in);
System.out.println("请输入起始日期,格式为yyyy/MMdd:");
startDate = sc.next();
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/MMdd:");
endDate = sc2.next();
Date date2 = null;
try {
date2 = (Date)format2.parse(endDate);
} catch (ParseException e) {
System.out.println("截止日期输入格式错误");
e.printStackTrace();
}
sc.close();
sc2.close();
Calendar dd = Calendar.getInstance(); //定义日期实例
dd.setTime(date);
while(dd.getTime().before(date2)){ //不包括endDate
String str = format2.format(dd.getTime()); //日期转换为字符串
dd.add(Calendar.DATE, 1); //天数加1
for(String string:linkedHref){
if(string.contains(str)) {
urlList.add(string); //网页列表
timeList.add(str.substring(5));
}
}
}
// for (String string : urlList) {
// System.out.println(string);
// }
}
public static void writeExcel(String path) throws IOException{ //将网页链接写入excel
//创建一个文件
File file2 = new File(path+"urlList.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 < urlList.size(); i++) { //创建行
XSSFRow row2 = sheet2.createRow(i);
XSSFCell cell2 = row2.createCell(0);
cell2.setCellValue(urlList.get(i));
}
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 class ReadNeedHtml extends Thread {
private String s = null;
public ReadNeedHtml(String s){
this.s = s ;
}
public void run(){
System.out.println("正在下载"+s);
for (int i=0; i
System.out.println(timeList.get(i) + "starts!");
try {
File dest = new File(timeList.get(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 file = new File(path); //读取本地html的路径
File[] array = file.listFiles(); //用于存储路径下的文件名
List
for(int i=0;i
array2.add(array[i]);
}
}
Collections.sort(array2); //按名称排序
return array2;
}
public static void getPhotoHtml(String path) { //解析本地的html
List
//循环读取并解析这些文件
for(int i=0; i
//文件名字
System.out.println("正在解析网址:" + array.get(i).getName()+"!");
//下面开始解析本地的html
Document doc = Jsoup.parse(array.get(i), "gb2312");
Elements links = doc.getElementsByClass("jc-article");//分离出class="jc-article"的所有东西
for (Element link : links) {
Elements links3 = link.getElementsByTag("img");//得到... 里面的内容
for (Element element3 : links3) {
String linkText2 = element3.attr("src");//得到... 里面的内容
PhotoHtmlList.add(linkText2);
}
}
System.out.println(array.get(i).getName()+"解析完毕!");
} catch (Exception e) {
System.out.println("网址:" + array.get(i).getName() + "解析出错");
e.printStackTrace();
continue;
}
}
// for (String string:PhotoHtmlList) {
// System.out.println(string);
// }
}
public static void DownloadPhoto(List
for (int i = 0; i < PhotoHtmlList.size(); i++) {
String strUrl = PhotoHtmlList.get(i);
//构造URL
URL url = new URL(strUrl);
//构造连接
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//打开连接
conn.connect();
//打开这个网站的输入流
InputStream inStream = conn.getInputStream();
//用这个做中转站 ,把图片数据都放在了这里,再调用toByteArray()即可获得数据的byte数组
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
//用这个是很好的,不用一次就把图片读到了文件中
//要是需要把图片用作其他用途呢?所以直接把图片的数据弄成一个变量,十分有用
//相当于操作这个变量就能操作图片了
byte [] buff = new byte[1024]; //网址图片较小,1024Byte足够了
//1024Byte=1KB,分配1KB的缓存
//这个就是循环读取,是一个临时空间,多大都没关系
//byte[]的大小,说明你一次操作最大字节是多少
int len = 0;
while((len=inStream.read(buff))!=-1){//读取图片数据
outStream.write(buff,0,len);
}
inStream.close();
outStream.close();
//把图片数据填入文件中
File file = new File(timeList.get(i)+".jpg");
FileOutputStream op = new FileOutputStream(file);
op.write(outStream.toByteArray());
op.close();
}
}
public static void main(String[] args) throws ParseException, IOException, InterruptedException {
SpiderXlggService ss = new SpiderXlggService();
ss.getAllUrlList();
ReadAllHtml rt = ss.new ReadAllHtml("爬取所有销量公告!");
rt.start();
try {
rt.join(); //保证网页读取完毕
} catch (InterruptedException e) {
e.printStackTrace();
}
String path = "D:\\xlh\\1zhangliang\\mgr后台项目\\bd_internal_api\\src\\";
getLocalhtml(path); //解析路径下的所有html
matchHtml(); //匹配需要提取的html
writeExcel(path); //将需提取的html保存到excel
deleteHtml(path); //删除所有html文件
ReadNeedHtml rt2 = ss.new ReadNeedHtml("爬取所需销量公告!");
rt2.start();
try {
rt2.join(); //保证网页读取完毕
} catch (InterruptedException e) {
e.printStackTrace();
}
getPhotoHtml(path);
DownloadPhoto(PhotoHtmlList);
deleteHtml(path); //删除所有html文件
}
}