文章目录
Java爬虫程序简介:
有关爬虫基础知识的内容请参考:爬虫基础知识(Python版)
/** * 程序名:Crawler * 作者:--------------------------------- * 编译环境:Microsoft Windows 7(64-bit)下的NetBeans IDE 7.3 * 源文件:Crawler.java, DownloadPage.java, Parser.java, SameFileName.java, TxtFileFilter.java, Work.java * 功能: * 1.多线程地连接互联网,获取页面源代码,在工作中随时可以停止或退出 * 2.通过正则表达式匹配,根据用户的选择可提取URL、电子邮箱、QQ号码、日期、电驴链接等信息 * 3.用户可自定义正则表达式,从页面源代码或在正文中提取信息 * 4.用户可自定义URL的正则表达式,当页面含有匹配的URL时,继续连接并提取信息 * 5.允许下载网页或URL指向的文件(如exe、mp3等) * 6.获取网页正文(去掉源代码中的html标签和js脚本等) * 7.下载并保存网页中的图片或网页中含有的自定义格式的文件 * 8.通过设置代理服务器连接互联网 * 9.请求网页时发送给定的Cookie */
- 此程序本是清华大学的课程设计(但是找不到链接网址了,当初下载下来没有记下网址)
- 优点:此程序是一个比较适合爬虫基础入门的程序,便于初学者了解爬虫的实现流程,也更适合Java的一些基础学习,例如HTTP连接、对于字符串的操作与正则匹配、对于IO流概念的理解、对于文件的读写等都是一个比较不错的学习程序。
- 有程序的地方就有缺点,此程序也不例外。
- 在Work工作类中: “继续爬取新的网页”功能处的实现,我有一丝不理解其目的何在(在测试的过程中没有理解。)
- DownLoadPage线程实现细节中:
- 1.存在太多重复的http连接,一个功能的实现需要一次连接。能否考虑一次连接就实现提取或保存不同信息的功能呢?是否可以考虑将该连接封装一下呢?我想或许可以。
- 2.存在太多文件输入输出,文件读写问题也存在其它类中,是否可以考虑将文件读写单独封装一下呢?尽管可能每次需要的文件读写不同,有一些读写方式也确实特殊,无法合并,但总是有较大的一部分是相同的,这一部分共同点或许就是可以封装的点。
- 此程序针对一般的网页还可以,但是针对一些特制的网页(例如爱奇艺,腾讯视频等)或者动态加载机制的网页就失效了,此外程序对于下载的源文件或者文本文件并没有进行格式处理,会出现打不开或者特别乱等情况,下载的文件也需要文件链接的绝对路径,例如图片需要完整的路径格式才可正确下载,对于相对路径下的图片则无能为力。
学习准备:
一、学习此程序最好搭配JDK文档如JAVA-SE-8-API.chm(网上有资源)
二、 关于正则表达式:
1. python正则表达式大全
2. 最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等
三、关于文件读写相关内容:
UML结构图(用IDEA生成即可):
程序运行截图:
程序实现:
一、主类:Crawler(画主界面,捕捉按键):
/* * To change this template, choose Tools | Templates * and open the template in the editor. */
package crawler;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
/** * 主类:Crawler * 功能:画界面,捕捉按键 */
public class Crawler extends JApplet {
static JFrame frame; // 界面
static JTextField inputurljtf, importtxtjtf, proxyaddrjtf, proxyportjtf; // 输入网址、导入文件、代理地址、代理端口的输入框
static JTextField userdefsourcejtf, userdeftextjtf, continueurljtf, saveformatjtf, cookiejtf; // 自定义正则表达式(两个)、继续搜索的网址、存储格式、Cookie的输入框
static ButtonGroup bgrp; // 两个单选框的组
static JRadioButton inputurljrb, importtxtjrb; // 输入网址和导入文件的单选框
static JButton choosefilejb, startjb, stopjb; // 浏览文件、开始、停止按钮
static JCheckBox arrjcb[], useproxyjcb, sendcookiejcb; // 18个功能选项、是否使用代理、是否发送Cookie的复选框
static JLabel proxyaddrjlb, proxyportjlb; // "地址"和"端口"提示标语
static Work work = null; // 启动的工作
@Override
public void init() {
frame = new JFrame("Crawler");
frame.setSize(406, 446); // 窗体大小
frame.setLocation(350, 130); // 窗体初始位置
frame.setResizable(false); // 不可以改变大小
/* 点击窗口右上角的×时退出程序 */
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent arg0) {
deletetempfile();
System.out.println("退出");
System.exit(0);
}
});
/* 设置输入网址的输入框 */
inputurljtf=new JTextField("", 8192);
inputurljtf.setSize(286, 20);
inputurljtf.setLocation(110, 10);
inputurljtf.setBackground(Color.WHITE);
frame.add(inputurljtf);
/* 设置导入文件的输入框 */
importtxtjtf=new JTextField("", 8192);
importtxtjtf.setSize(205, 20);
importtxtjtf.setLocation(110, 40);
importtxtjtf.setBackground(Color.WHITE);
frame.add(importtxtjtf);
/* 设置两个单选框和组 */
bgrp = new ButtonGroup();
inputurljrb = new JRadioButton("输入网页地址 ", true);
importtxtjrb = new JRadioButton("从txt导入网址", false);
bgrp.add(inputurljrb);
bgrp.add(importtxtjrb);
inputurljrb.setSize(110, 20);
importtxtjrb.setSize(110, 20);
inputurljrb.setLocation(0, 10);
importtxtjrb.setLocation(0, 40);
frame.add(inputurljrb);
frame.add(importtxtjrb);
/* 设置浏览按钮 */
choosefilejb = new JButton("浏览...");
choosefilejb.setSize(75, 20);
choosefilejb.setLocation(320, 40);
frame.add(choosefilejb);
arrjcb = new JCheckBox[18];
/* 设置提取URL的复选框 */
arrjcb[0] = new JCheckBox("提取URL");
arrjcb[0].setSize(92, 20);
arrjcb[0].setLocation(0, 70);
/* 设置提取电子邮箱地址的复选框 */
arrjcb[1] = new JCheckBox("提取电子邮箱地址");
arrjcb[1].setSize(132, 20);
arrjcb[1].setLocation(135,70);
/* 设置提取ip地址的复选框 */
arrjcb[2] = new JCheckBox("提取ip地址");
arrjcb[2].setSize(98, 20);
arrjcb[2].setLocation(270, 70);
/* 设置提取手机号码的复选框 */
arrjcb[3] = new JCheckBox("提取手机号码");
arrjcb[3].setSize(113, 20);
arrjcb[3].setLocation(0, 95);
/* 设置提取电话号码的复选框 */
arrjcb[4] = new JCheckBox("提取电话号码");
arrjcb[4].setSize(113, 20);
arrjcb[4].setLocation(135, 95);
/* 设置提取QQ号码的复选框 */
arrjcb[5] = new JCheckBox("提取QQ号码");
arrjcb[5].setSize(99, 20);
arrjcb[5].setLocation(270, 95);
/* 设置提取身份证号码的复选框 */
arrjcb[6] = new JCheckBox("提取身份证号码");
arrjcb[6].setSize(119, 20);
arrjcb[6].setLocation(0, 120);
/* 设置提取日期的复选框 */
arrjcb[7] = new JCheckBox("提取日期");
arrjcb[7].setSize(93, 20);
arrjcb[7].setLocation(135, 120);
/* 设置提取时间的复选框 */
arrjcb[8] = new JCheckBox("提取时间");
arrjcb[8].setSize(93, 20);
arrjcb[8].setLocation(270, 120);
/* 设置提取电驴链接的复选框 */
arrjcb[9] = new JCheckBox("提取电驴链接(ed2k://...)");
arrjcb[9].setSize(176, 20);
arrjcb[9].setLocation(0, 145);
/* 设置提取迅雷链接的复选框 */
arrjcb[10] = new JCheckBox("提取迅雷链接(thunder://...)");
arrjcb[10].setSize(184, 20);
arrjcb[10].setLocation(186, 145);
/* 设置从源代码提取自定义正则表达式内容的复选框和对应的输入框 */
arrjcb[11] = new JCheckBox("从源代码提取以下内容");
arrjcb[11].setSize(160, 20);
arrjcb[11].setLocation(0, 175);
userdefsourcejtf = new JTextField("", 8192);
userdefsourcejtf.setSize(234, 20);
userdefsourcejtf.setLocation(162, 175);
frame.add(userdefsourcejtf);
/* 设置从正文提取自定义正则表达式内容的复选框和对应的输入框 */
arrjcb[12] = new JCheckBox("在正文中提取以下内容");
arrjcb[12].setSize(160, 20);
arrjcb[12].setLocation(0, 205);
userdeftextjtf = new JTextField("", 8192);
userdeftextjtf.setSize(234, 20);
userdeftextjtf.setLocation(162, 205);
frame.add(userdeftextjtf);
/* 设置继续爬网页的复选框和对应的输入框 */
arrjcb[13] = new JCheckBox("继续爬以下网页");
arrjcb[13].setSize(119, 20);
arrjcb[13].setLocation(0, 235);
continueurljtf = new JTextField("", 8192);
continueurljtf.setSize(275, 20);
continueurljtf.setLocation(121, 235);
frame.add(continueurljtf);
/* 设置保存目标的复选框 */
arrjcb[14] = new JCheckBox("保存目标");
arrjcb[14].setSize(93, 20);
arrjcb[14].setLocation(0, 265);
/* 设置保存网页正文的复选框 */
arrjcb[15] = new JCheckBox("保存网页正文");
arrjcb[15].setSize(113, 20);
arrjcb[15].setLocation(135, 265);
/* 设置下载网页图片的复选框 */
arrjcb[16] = new JCheckBox("下载网页图片");
arrjcb[16].setSize(113, 20);
arrjcb[16].setLocation(270, 265);
/* 设置下载指定格式文件的复选框和对应的输入框 */
arrjcb[17] = new JCheckBox("下载以下格式的文件");
arrjcb[17].setSize(142, 20);
arrjcb[17].setLocation(0, 295);
saveformatjtf = new JTextField("", 8192);
saveformatjtf.setSize(252, 20);
saveformatjtf.setLocation(144, 295);
frame.add(saveformatjtf);
/* 设置以上复选框的字体并显示 */
int i;
for(i = 0; i <= 17; i++) {
arrjcb[i].setFont(new Font(Font.DIALOG, Font.PLAIN, 13));
frame.add(arrjcb[i]);
}
/* 设置使用代理服务器的复选框 */
useproxyjcb = new JCheckBox("使用代理服务器");
useproxyjcb.setSize(119, 20);
useproxyjcb.setLocation(0, 325);
useproxyjcb.setFont(new Font(Font.DIALOG, Font.PLAIN, 13));
frame.add(useproxyjcb);
/* 设置代理地址的提示 */
proxyaddrjlb = new JLabel("地址:");
proxyaddrjlb.setSize(33, 20);
proxyaddrjlb.setLocation(139, 325);
proxyaddrjlb.setFont(new Font(Font.DIALOG, Font.PLAIN, 13));
frame.add(proxyaddrjlb);
/* 设置代理地址的输入框 */
proxyaddrjtf = new JTextField("", 256);
proxyaddrjtf.setSize(108, 20);
proxyaddrjtf.setLocation(173, 325);
frame.add(proxyaddrjtf);
/* 设置代理端口的提示 */
proxyportjlb = new JLabel("端口:");
proxyportjlb.setSize(33, 20);
proxyportjlb.setLocation(306, 325);
proxyportjlb.setFont(new Font(Font.DIALOG, Font.PLAIN, 13));
frame.add(proxyportjlb);
/* 设置代理端口的输入框 */
proxyportjtf = new JTextField("", 16);
proxyportjtf.setSize(56, 20);
proxyportjtf.setLocation(340, 325);
frame.add(proxyportjtf);
/* 设置发送Cookie的复选框 */
sendcookiejcb = new JCheckBox("发送Cookie");
sendcookiejcb.setSize(97, 20);
sendcookiejcb.setLocation(0, 355);
sendcookiejcb.setFont(new Font(Font.DIALOG, Font.PLAIN, 13));
frame.add(sendcookiejcb);
/* 设置Cookie的输入框 */
cookiejtf = new JTextField("", 8192);
cookiejtf.setSize(295, 20);
cookiejtf.setLocation(101, 355);
frame.add(cookiejtf);
/* 设置开始按钮 */
startjb = new JButton("开 始 (Enter)");
startjb.setSize(190, 23);
startjb.setLocation(4, 386);
frame.add(startjb);
/* 设置停止按钮 */
stopjb = new JButton("停 止");
stopjb.setSize(190, 23);
stopjb.setLocation(205, 386);
stopjb.setBackground(Color.LIGHT_GRAY);
frame.add(stopjb);
frame.setLayout(null); // 取消默认布局管理器
}
@Override
public void start() {
/* 点击"浏览"按钮时的响应 */
ActionListener choosefileal = new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
/* 若已开始工作则不响应 */
if (work == null || !work.isAlive()) {
importtxtjrb.setSelected(true);
/* 弹出选择文件的对话框 */
JFileChooser jfc = new JFileChooser (".");
jfc.setAcceptAllFileFilterUsed(false);
jfc.addChoosableFileFilter(new TxtFileFilter());
int result = jfc.showOpenDialog(null);
if(result == JFileChooser.APPROVE_OPTION) {
String path = jfc.getSelectedFile().getAbsolutePath();
importtxtjtf.setText(path);
}
}
}
};
choosefilejb.addActionListener(choosefileal);
final Crawler crawler = this;
/* 点击"开始"按钮时的响应 */
ActionListener startal = new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
/* 若已开始工作则不响应 */
if (work == null || !work.isAlive()) {
System.out.println("开始");
work = new Work(); // 启动一项新工作
work.start();
}
}
};
startjb.addActionListener(startal);
/* 点击停止按钮时的响应 */
ActionListener stopal = new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
/* 若当前没有工作则不响应 */
if (work != null && work.isAlive()) {
work.needstop = true; // 依次将所有子线程的needstop设为true,使各子线程尽快终止
System.out.println("准备停止...");
deletetempfile(); // 删除临时文件
while (work.isAlive()) {
}
System.out.println("已停止");
}
}
};
stopjb.addActionListener(stopal);
/* 在任意一个输入框按回车键视为点击"开始"按钮 */
addenterlistener(inputurljtf);
addenterlistener(importtxtjtf);
addenterlistener(userdefsourcejtf);
addenterlistener(userdeftextjtf);
addenterlistener(continueurljtf);
addenterlistener(saveformatjtf);
addenterlistener(proxyaddrjtf);
addenterlistener(proxyportjtf);
addenterlistener(cookiejtf);
frame.setVisible(true); // 将界面显示
}
void addenterlistener(JTextField jtf) {
jtf.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent event)
{
if (event.getKeyText(event.getKeyCode()).compareToIgnoreCase("Enter")==0) {
startjb.doClick(); // 模拟点击"开始"按钮
}
}
});
}
/* 删除所有临时文件 */
void deletetempfile() {
Integer i;
for (i = 1; i <= 500; i++) {
new File("~tmp"+i.toString()).delete();
new File("~"+i.toString()+"saveurls.txt").delete();
}
}
/* 主函数 */
public static void main(String[] args) {
JApplet applet = new Crawler();
System.out.println("欢迎使用java版网络爬虫Crawler");
applet.init();
applet.start();
}
}
二、Work类(网络爬虫的工作类,启动DownloadPage线程,并保存要连接的URL的队列):
从主页面获取网页URL或者选择从文件导入URL信息加入到待爬取队列中,同时从主页面获取一些基本信息,例如是否使用代理或者添加cookie等内容。
/* * To change this template, choose Tools | Templates * and open the template in the editor. */
package crawler;
import java.awt.Color;
import java.util.*;
import java.io.*;
import java.util.concurrent.*;
import java.util.regex.*;
/** * * @author 1100012773, 1100012778 */
/** * Work类 * 网络爬虫的工作类,启动DownloadPage线程,并保存要连接的URL的队列 */
public class Work extends Thread {
boolean needstop; // 是否需要停止(由Crawler控制)
/* 构造函数 */
public Work() {
needstop = false;
}
@Override
public void run() {
/* 开始工作时,更改三个按钮的颜色 */
Crawler.startjb.setBackground(Color.LIGHT_GRAY);
Crawler.stopjb.setBackground(null);
Crawler.choosefilejb.setBackground(Color.LIGHT_GRAY);
Set<String> set = new HashSet<String>(); // 记录连接的URL
Queue<String> queue = new LinkedList<String>(); // 记录即将连接的URL
/* 直接输入网址 */
if(Crawler.inputurljrb.isSelected()) {
queue.offer(Crawler.inputurljtf.getText());
}
/* 从txt文件中导入网址 */
else {
String importfilename = Crawler.importtxtjtf.getText();
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
String readstr;
fis = new FileInputStream(importfilename);
isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
while ((readstr = br.readLine()) != null) {
queue.offer(readstr);
}
} catch(FileNotFoundException e) {
System.out.println("找不到指定文件");
} catch(IOException e) {
System.out.println("读取文件失败");
} finally {
try {
if (br != null) br.close();
if (isr != null) isr.close();
if (fis != null) fis.close();
} catch (IOException ex) {
System.out.println("关闭文件失败");
}
}
}
/* 判断是否需要代理服务器,若需要则读取代理服务器的地址和端口 */
boolean useproxy = Crawler.useproxyjcb.isSelected();
if (useproxy) {
if (!Pattern.matches("(((25)[0-5][0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9]))\\.(((25)[0-5][0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9]))\\.(((25)[0-5][0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9]))\\.(((25)[0-5][0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9]))", Crawler.proxyaddrjtf.getText())) {
useproxy = false;
System.out.println("代理服务器地址格式错误");
}
else if (!Pattern.matches(("[0-9]{1,5}"), Crawler.proxyportjtf.getText())) {
useproxy = false;
System.out.println("代理服务器端口格式错误");
}
}
/* 是否需要发送Cookie */
boolean sendcookie = Crawler.sendcookiejcb.isSelected();
/* 直到即将连接的URL为空才结束循环 */
while (!queue.isEmpty()) {
if (needstop) break;
String str;
int queuesize = queue.size();
if (queuesize > 500) queuesize = 500; // 设置DownloadPage线程数最多为500
Integer i;
boolean b[] = new boolean[18];
for (i = 0; i <= 17; i++)
b[i] = Crawler.arrjcb[i].isSelected();
CountDownLatch runningthreadnum = new CountDownLatch(queue.size());
DownloadPage task[] = new DownloadPage[queuesize+1];
for (i = 1; i <= queuesize; i++) {
if (needstop) {
int j;
for (j = 1; j < i; j++)
if (task[j] != null) task[j].needstop = true;
break;
}
str = queue.poll();
str = str.replace(" ", "");
if (!str.equals("")) {
if (str.indexOf("://") == -1 || str.indexOf("://") > 12) str = "http://" + str; // 若输入的网址没有http://,则补上
set.add(str);
task[i] = new DownloadPage(str, i, b, runningthreadnum); // 新建任务
if (useproxy) task[i].getproxyinfo(Crawler.proxyaddrjtf.getText(), Crawler.proxyportjtf.getText()); // 需要的话设置代理
if (sendcookie) task[i].getcookiecontent(Crawler.cookiejtf.getText());
task[i].gettext(Crawler.userdefsourcejtf.getText(), Crawler.userdeftextjtf.getText(), Crawler.continueurljtf.getText(), Crawler.saveformatjtf.getText()); // 获取输入框内容
task[i].start(); // 任务开始
}
else {
runningthreadnum.countDown(); // 网址为空,没有新建任务,线程数自动减一
}
}
try {
/* 等候全部DownloadPage线程结束 */
while (runningthreadnum.getCount() > 0) {
sleep(200);
if (needstop) {
int j;
for (j = 1; j <= queuesize; j++)
if (task[j] != null) task[j].needstop = true;
sleep(1000);
break;
}
}
} catch (InterruptedException ex) {
System.out.println("线程中断异常");
}
/* 若还需要爬新的网页,则加入队列中 */
if (b[13]) {
for (i = 1; i <= queuesize; i++) {
if (needstop) break;
String urlsavefile = "~"+i.toString()+"saveurls.txt";
File file = new File(urlsavefile);
if (file.exists()) {
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
fis = new FileInputStream(file);
isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
String line;
String regex = Crawler.continueurljtf.getText();
while ((line = br.readLine()) != null) {
boolean pass = false;
/* 若在输入框中没有输入任何字符,视为继续爬任何网页,否则只爬符合那条正则表达式的内容 */
if (regex.equals("")) {
pass = true;
}
else {
pass = Pattern.matches(regex, line);
}
if (pass) {
if (set.add(line)) {
queue.offer(line);
}
}
}
} catch (PatternSyntaxException ex) {
System.out.println("自定义正则表达式语法错误");
} catch (FileNotFoundException ex) {
System.out.println("临时保存url的文件不存在");
} catch (IOException ex) {
System.out.println("读取临时保存url的文件失败");
} finally {
try {
if (br != null) br.close();
if (isr != null) isr.close();
if (fis != null) fis.close();
} catch (IOException ex) {
System.out.println("关闭临时文件失败");
}
}
file.delete();
} // end of if(file.exists())
} // end of for
} // end of if(b[13])
} // end of while
/* 工作结束时,更改三个按钮的颜色 */
Crawler.startjb.setBackground(null);
Crawler.stopjb.setBackground(Color.LIGHT_GRAY);
Crawler.choosefilejb.setBackground(null);
}
}
三、DownloadPage类(给定URL等信息,连接互联网下载信息,交由Parser类提取数据,如果用户有需要则保存相应内容):
public class DownloadPage extends Thread实则为线程类,实现网页获取下载以及保存到文件的各类细节,是爬虫的重要实现类:
/* * To change this template, choose Tools | Templates * and open the template in the editor. */
package crawler;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
/** * * @author 1100012773, 1100012778 */
/** * DownloadPage类 * 功能:给定URL等信息,连接互联网下载信息,交由Parser类提取数据,如果用户有需要则保存相应内容 */
public class DownloadPage extends Thread {
private Integer tempfileid; // 临时文件对应的序号
private String url; // 网页链接
private String tempfilename; // 临时文件名
private String objectname; // 目标名称(如果URL对应的是网页则取网页标题,否则直接从URL中提取)
private String userdefsource; // 用户自定义的正则表达式(对应从源代码中匹配)
private String userdeftext; // 用户自定义的正则表达式(对应从正文中匹配)
private String continueurl; // 要继续爬的URL的正则表达式
private String saveformat; // 要存储的文件格式
private boolean useproxy = false, sendcookie = false; // 是否使用代理服务器、是否发送Cookie
private String proxyaddr; // 代理地址
private String cookie; // Cookie内容
private int proxyport; // 代理端口
private boolean need[]; // 对应18个复选框的真值
private boolean error = false; // 是否出错
private CountDownLatch runningthreadnum; // 当前线程数
boolean needstop; // 是否需要停止(由Work控制)
/* 构造函数 */
public DownloadPage(String u, Integer tfi, boolean n[], CountDownLatch rtn) {
super();
url = u;
tempfileid = tfi;
tempfilename = "~tmp"+tfi.toString();
need = new boolean[18];
int i;
for (i = 0 ;i <= 17; i++)
need[i] = n[i];
runningthreadnum = rtn;
needstop = false;
}
/* 获取代理服务器信息 */
public void getproxyinfo(String paddr, String pp) {
useproxy = true;
proxyaddr = paddr;
proxyport = Integer.valueOf(pp);
}
/* 获取Cookie内容 */
public void getcookiecontent(String cookie) {
sendcookie = true;
this.cookie = cookie;
}
/* 获取输入框内容 */
public void gettext(String userdefsource, String userdeftext, String continueurl, String saveformat) {
this.userdefsource = userdefsource;
this.userdeftext = userdeftext;
this.continueurl = continueurl;
this.saveformat = saveformat;
}
@Override
public void run() {
try {
System.out.println("准备连接 - "+url);
String charcode = null;
if (!needstop) charcode = getcharcodefromurl(); // 分析网页编码类型
String content = null;
if (!needstop) content = getcontentfromurl(charcode); // 获取网页内容
if (!needstop) outputtotempfile(content, charcode); // 将网页内容输出到临时文件中
if (!error && !needstop) {
Parser parser = new Parser(url, tempfileid, content, need);
String title = parser.gettitle(); // 获取网页标题
if (title.equals("")) System.out.println("连接成功 - "+url);
else System.out.println("连接成功 - "+title);
parser.parse(userdefsource, userdeftext, continueurl, saveformat); // 分析网页内容并提取需要的数据
if (title.equals("")) System.out.println("提取信息成功 - "+url);
else System.out.println("提取信息成功 - "+title);
/* 若需要保存目标…… */
if (need[14] && !needstop) {
/* 该目标为网页且有非空标题 */
if (!title.equals("")) {
File file = new File(tempfilename);
if (file.exists()) {
new File("下载\\目标").mkdirs();
System.out.println("目标保存为 - "+SameFileName.newfilename("下载\\目标\\", title+".html"));
file.renameTo(new File("下载\\目标\\"+SameFileName.newfilename("下载\\目标\\", title+".html"))); // 将之前的临时文件重命名即可
}
}
/* 该目标不是网页或是网页但没有非空标题 */
else {
objectname = SameFileName.newfilename("下载\\目标\\", getobjname(url));
new File("下载\\目标").mkdirs();
System.out.println("目标保存为 - "+objectname);
downloadbybyte(url, "下载\\目标\\"+objectname); // 重新下载(因为之前的下载很可能会丢失部分特殊字符的数据)
}
}
/* 若需要保存网页正文…… */
if (need[15] && !needstop) {
String textname = null;
if (!title.equals("")) {
textname = title+".txt";
}
else {
textname = getobjname(url)+".txt";
}
new File("下载\\网页正文").mkdirs();
textname = SameFileName.newfilename(("下载\\网页正文\\"), textname);
System.out.println("网页正文保存为 - "+textname);
outputtext(content, charcode, "下载\\网页正文\\"+textname); // 将网页正文输出到指定的文件
}
/* 若需要下载网页中特定格式的文件…… */
if (need[16] || need[17]) {
Set<String> filesuffixset = new HashSet<String>();
/* 需要下载图片 */
if (need[16]) {
filesuffixset.add(".jpg");
filesuffixset.add(".gif");
filesuffixset.add(".png");
filesuffixset.add(".jpeg");
filesuffixset.add(".bmp");
}
/* 需要下载自定义格式的文件 */
if (need[17]) {
Pattern pattern = Pattern.compile("\\.(\\w|\\-|\\_)+", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(saveformat);
while (matcher.find()) {
filesuffixset.add(saveformat.substring(matcher.start(), matcher.end()).toLowerCase());
}
}
if (!filesuffixset.isEmpty() && !needstop) downloadfile(content, "下载 - "+title, filesuffixset); // 下载文件
}
}
} catch (MalformedURLException ex) {
System.out.println("url格式不对 - "+url); // url格式不对
error = true;
} catch (IOException ex) {
System.out.println("网络连接异常 - "+url); // 网络连接异常
error = true;
}
File file = new File(tempfilename);
if (file.exists()) file.delete(); // 删除临时文件
runningthreadnum.countDown(); // 线程数减一
}
/* 获取网页编码类型 */
private String getcharcodefromurl() {
try {
/* 若需要使用代理服务器则设置代理 */
SocketAddress add = null;
if (useproxy) add = new InetSocketAddress(proxyaddr, proxyport);
Proxy proxy = null;
if (useproxy) proxy = new Proxy(Proxy.Type.HTTP , add);
/* 连接网络,获取网页头信息 */
URL u = new URL(url);
HttpURLConnection urlconnection = null;
if (useproxy) urlconnection = (HttpURLConnection)u.openConnection(proxy);
else urlconnection = (HttpURLConnection)u.openConnection();
if (sendcookie) urlconnection.setRequestProperty("Cookie", cookie);
urlconnection.connect();
String charcode = null;
/* 分析网页头信息 */
Map<String, List<String>> map = urlconnection.getHeaderFields();
Set<String> keys = map.keySet();
Iterator<String> iterator = keys.iterator();
String key = null;
String tmp = null;
while (iterator.hasNext()) {
if (needstop) return "UTF-8";
key = iterator.next();
tmp = map.get(key).toString().toLowerCase();
/* 若网页头中含有"Content-Type"项且含有"charset="字段,则提取信息并返回 */
if (key != null && key.equals("Content-Type")) {
int m = tmp.indexOf("charset=");
if (m != -1) {
charcode = tmp.substring(m + 8).replace("]", "");
return charcode;
}
}
}
if (needstop) return "UTF-8";
/* 重新连接,逐行提取网页源代码,再从源代码中寻找字符编码信息 */
HttpURLConnection conn = null;
if (useproxy) conn = (HttpURLConnection)(new URL(url).openConnection(proxy));
else conn = (HttpURLConnection)(new URL(url).openConnection());
if (sendcookie) conn.setRequestProperty("Cookie", cookie);
conn.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (needstop) return "UTF-8";
line = line.toLowerCase();
/* 在读取的字符串中寻找"charset="字段 */
int indexofcharset = line.indexOf("charset=");
if (indexofcharset > 0) {
line = line.substring(indexofcharset);
int indexofquotation = line.indexOf("\"");
if (indexofquotation > 0) {
return line.substring(8, indexofquotation);
}
}
}
} catch (MalformedURLException ex) {
}
catch (IOException ex) {
}
return "UTF-8"; // 默认是UTF-8编码
}
/* 获取网页内容 */
private String getcontentfromurl(String charcode) {
try {
/* 若需要使用代理服务器则先设置代理 */
SocketAddress add = null;
if (useproxy) add = new InetSocketAddress(proxyaddr, proxyport);
Proxy proxy = null;
if (useproxy) proxy = new Proxy(Proxy.Type.HTTP , add);
/* 连接网络 */
HttpURLConnection conn = null;
if (useproxy) conn = (HttpURLConnection)(new URL(url).openConnection(proxy));
else conn = (HttpURLConnection)(new URL(url).openConnection());
if (sendcookie) conn.setRequestProperty("Cookie", cookie);
conn.connect();
InputStream is = conn.getInputStream();
if (needstop) return "";
String content = readfromstream(is, charcode); // 在InputStream中获取内容
return content;
} catch(MalformedURLException e) {
System.out.println("url格式不对 - "+url);
error = true;
} catch (IOException ex) {
System.out.println("网络连接异常 - "+url);
error = true;
}
return "";
}
/* 从网页给的输入流中获取内容并保存在String中 */
private String readfromstream(InputStream stream, String charcode) throws IOException {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, charcode));
StringBuilder sb = new StringBuilder();
String line;
/* 逐行读取数据 */
while ((line = reader.readLine()) != null) {
if (needstop) return "";
sb.append(line+"\r\n");
}
return sb.toString();
} catch (UnsupportedEncodingException ex) {
System.out.println("无法识别的编码方式 - "+url);
error = true;
}
return "";
}
/* 将网页内容输出到临时文件 */
private void outputtotempfile(String content, String charcode) {
File file = new File(tempfilename);
FileOutputStream fos = null;
Writer out = null;
try {
fos = new FileOutputStream(file, false);
out = new OutputStreamWriter(fos, charcode);
out.write(content);
} catch (FileNotFoundException ex) {
System.out.println("临时文件名出错");
error = true;
} catch (IOException ex) {
System.out.println("临时文件输出失败");
error = true;
} finally {
try {
if (out != null) out.close();
if (fos != null) fos.close();
} catch (IOException ex) {
System.out.println("无法关闭临时文件");
}
}
}
/* 逐字节地下载网页目标 */
private boolean downloadbybyte(String url, String savefile) throws MalformedURLException {
boolean succeed = true;
URL u = new URL(url);
DataInputStream dis = null;
FileOutputStream fos = null;
try {
if (needstop) return false;
/* 设置代理、连网等同上 */
SocketAddress add = null;
if (useproxy) add = new InetSocketAddress(proxyaddr, proxyport);
Proxy proxy = null;
if (useproxy) proxy = new Proxy(Proxy.Type.HTTP , add);
HttpURLConnection conn = null;
if (useproxy) conn = (HttpURLConnection)(new URL(url).openConnection(proxy));
else conn = (HttpURLConnection)(new URL(url).openConnection());
if (sendcookie) conn.setRequestProperty("Cookie", cookie);
conn.connect();
dis = new DataInputStream(conn.getInputStream());
if (needstop) return false;
fos = new FileOutputStream(new File(savefile));
byte buffer[] = new byte[65536];
int length;
/* 每次固定读若干字节的内容 */
while ((length = dis.read(buffer)) > 0) {
fos.write(buffer, 0, length);
if (needstop) return false;
}
} catch (IOException ex) {
System.out.println("下载失败 - "+savefile.substring(savefile.lastIndexOf("\\")+1));
succeed = false;
} finally {
try {
if (dis != null) dis.close();
if (fos != null) fos.close();
} catch (IOException ex) {
System.out.println("关闭下载的文件失败");
}
}
return succeed;
}
/* 根据URL获取目标名称 */
private String getobjname(String url) {
if (needstop) return url;
String destfile = new String(url);
if (destfile.endsWith("/")) destfile = destfile.substring(0, destfile.length() - 1);
//选择最后的‘/’后的内容作为标题(文件名)
int lastslashpos = destfile.lastIndexOf("/");
destfile = destfile.substring(lastslashpos + 1);
int lastdotpos = destfile.lastIndexOf(".");
if (lastdotpos > 0) {
int tmpindex = destfile.indexOf("?", lastdotpos);
if (tmpindex > 0) destfile = destfile.substring(0, tmpindex);
if ((tmpindex = destfile.indexOf("%", lastdotpos)) > 0) destfile = destfile.substring(0, tmpindex);
if ((tmpindex = destfile.indexOf("&", lastdotpos)) > 0) destfile = destfile.substring(0, tmpindex);
if ((tmpindex = destfile.indexOf("=", lastdotpos)) > 0) destfile = destfile.substring(0, tmpindex);
if ((tmpindex = destfile.indexOf("+", lastdotpos)) > 0) destfile = destfile.substring(0, tmpindex);
if ((tmpindex = destfile.indexOf(":", lastdotpos)) > 0) destfile = destfile.substring(0, tmpindex);
}
//替换不合法标识符
destfile = destfile.replace(":", "").replace("<","").replace(">","").replace("?","").replace("|","").replace("*","").replace("/","").replace("\\","").replace("\"", "");
//避免标题(文件名)过长
if (destfile.length() > 127) destfile = destfile.substring(destfile.length() - 127);
return destfile;
}
/* 输出网页正文 */
private void outputtext(String content, String charcode, String savefile) {
if (needstop) return;
String text = new String(content);
/* 删去所有js脚本、html标签,并将&***;变为原有字符 */
text = text.replaceAll("<(s|S)(c|C)(r|R)(i|I)(p|P)(t|T)[^>]*?>[\\s\\S]*?</(s|S)(c|C)(r|R)(i|I)(p|P)(t|T)>", "").replaceAll("<(s|S)(t|T)(y|Y)(l|L)(e|E)[^>]*?>[\\s\\S]*?</(s|S)(t|T)(y|Y)(l|L)(e|E)>","").replaceAll("<br>","\r\n").replaceAll("<[\\s\\S]*?>", "").replaceAll("(\r\n)+","\r\n").replaceAll("(\\s)+"," ").replaceAll("\\&((nbsp)|(\\#12288)|(\\#160))(\\;)?", " ").replaceAll("\\&((lt)|(\\#60))(\\;)?","<").replaceAll("\\&((gt)|(\\#62))(\\;)?",">").replaceAll("\\&((quot)|(#34))(\\;)?","\"").replaceAll("\\&((apos)|(\\#39))(\\;)?","'").replaceAll("\\©(\\;)?","©").replaceAll("\\®(\\;)?","®").replaceAll("\\&((amp)|(#38))(\\;)?","&");
File file = new File(savefile);
FileOutputStream fos = null;
Writer out = null;
try {
fos = new FileOutputStream(file, false);
out = new OutputStreamWriter(fos, charcode);
if (needstop) return;
out.write(text);
} catch (FileNotFoundException ex) {
System.out.println("网页正文文件名出错");
error = true;
} catch (IOException ex) {
System.out.println("网页正文输出失败");
error = true;
} finally {
try {
if (out != null) out.close();
if (fos != null) fos.close();
} catch (IOException ex) {
System.out.println("无法关闭网页正文文件");
}
}
}
/* 下载指定格式的文件 */
void downloadfile(String content, String dir, Set<String> suffixset) throws MalformedURLException, IOException {
Set<String> downloaded = new HashSet<String>();
Pattern pattern = Pattern.compile("(http://|ftp://|https://|rstp://|telnet://|file://)([\\w-]+\\.)+[\\w-]+(/[\\w\\-\\_\\.\\/\\?\\%\\&\\=\\:\\+\\,]*)?", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(content);
/* 从网页源码中提取指定格式的URL */
while (matcher.find()) {
if (needstop) return;
String url = content.substring(matcher.start(), matcher.end());
String destfile = getobjname(url);
destfile = SameFileName.newfilename("下载\\"+dir+"\\", destfile);
int lastdotpos = destfile.lastIndexOf(".");
if (lastdotpos > 0) {
if (suffixset.contains(destfile.substring(lastdotpos).toLowerCase()) && downloaded.add(url.toLowerCase())) {
new File("下载\\"+dir).mkdirs();
if (downloadbybyte(url, "下载\\"+dir+"\\"+destfile)) System.out.println("下载成功 - "+destfile); /* 下载该URL */
}
}
}
}
}
四、辅助类:
1.SameFileName类(若某个目录下已存在某文件,更改新文件的文件名):
(如a.txt->a[2].txt,ab[3]->ab[4])
/* * To change this template, choose Tools | Templates * and open the template in the editor. */
package crawler;
import java.io.*;
/** * * @author 1100012773, 1100012778 */
/** * SameFileName类 * 若某个目录下已存在某文件,更改新文件的文件名(如a.txt->a[2].txt,ab[3]->ab[4]) */
public class SameFileName {
public static String newfilename(String dir, String oldfilename) {
String filename = oldfilename;
File file = new File(dir+oldfilename);
if (!file.exists()) return filename;
int lastdotpos = oldfilename.lastIndexOf(".");
Integer index = 1;
//没有后缀的情况
if (lastdotpos == -1) {
while (true) {
index++;
filename = oldfilename+"["+index.toString()+"]";
if (!new File(dir+filename).exists()) return filename;
}
}
//带后缀的情况(如.html)
else {
String suffix = oldfilename.substring(lastdotpos);
while (true) {
index++;
filename = oldfilename.substring(0, lastdotpos)+"["+index.toString()+"]"+suffix;
if (!new File(dir+filename).exists()) return filename;
}
}
}
}
2.TxtFileFilter类(文件筛选器,只用于点击"浏览"按钮弹出的选择文件的对话框):
/* * To change this template, choose Tools | Templates * and open the template in the editor. */
package crawler;
import java.io.File;
import javax.swing.filechooser.*;
/** * * @author 1100012773, 1100012778 */
/** * TxtFileFilter类 * 文件筛选器,只用于点击"浏览"按钮弹出的选择文件的对话框 */
class TxtFileFilter extends FileFilter {
@Override
public boolean accept(File f) {
if(f.isDirectory()) {
return true; // 显示文件夹
}
String nameString = f.getName();
return nameString.toLowerCase().endsWith(".txt"); // 显示txt文件
}
@Override
public String getDescription() {
return "文本文件 (*.txt)"; // 类型提示
}
}
3.Parser类(分析网页源文件,利用正则匹配等提取出需要的信息并输出到文件)(由每一个线程进行初始化,指定输出格式):
/* * To change this template, choose Tools | Templates * and open the template in the editor. */
package crawler;
import java.io.*;
import java.util.*;
import java.util.regex.*;
/** * * @author 1100012773, 1100012778 */
/** * Parser类 * 功能:分析网页源文件,提取需要的信息并输出 */
public class Parser {
private String url; // 网页链接
private String tempfilename; // 输出的临时文件名
private String content; // 网页源代码
private boolean need[]; // 对应DownloadPage的need
/* 构造函数 */
public Parser(String u, Integer tfi, String ct, boolean n[]) {
url = u;
tempfilename = "~"+tfi.toString()+"saveurls.txt";
content = ct;
int i;
need = new boolean[18];
for (i = 0; i < 17; i++)
need[i] = n[i];
}
/* 分析源代码内容,提取需要的信息并输出 */
public void parse(String userdefsource, String userdeftext, String continueurl, String saveformat) {
String title = gettitle();
try {
String text = content.replace("\n","").replace("\r","").replaceAll("<(s|S)(c|C)(r|R)(i|I)(p|P)(t|T)[^>]*?>.*?</(s|S)(c|C)(r|R)(i|I)(p|P)(t|T)>", "").replaceAll("<(s|S)(t|T)(y|Y)(l|L)(e|E)[^>]*?>.*?</(s|S)(t|T)(y|Y)(l|L)(e|E)>","").replaceAll("<.*?>", "").replaceAll("\\&((nbsp)|(\\#12288)|(\\#160))(\\;)?", " ").replaceAll("\\&((lt)|(\\#60))(\\;)?","<").replaceAll("\\&((gt)|(\\#62))(\\;)?",">").replaceAll("\\&((quot)|(#34))(\\;)?","\"").replaceAll("\\&((apos)|(\\#39))(\\;)?","'").replaceAll("\\©(\\;)?","©").replaceAll("\\®(\\;)?","®").replaceAll("\\&((amp)|(#38))(\\;)?","&");
/* regex[0]到regex[10]为URL、电子邮箱地址、ip地址、手机号码、电话号码、QQ号码、身份证号码、日期、时间、电驴链接、迅雷链接的正则表达式 */
String regex[] = new String[18];
regex[0] = new String("(http://|ftp://|https://|rstp://|telnet://|file://)([\\w-]+\\.)+[\\w-]+(/[\\w\\-\\_\\.\\/\\?\\%\\&\\=\\:\\+\\,]*)?");
regex[1] = new String("[\\w]+([\\.\\_\\-]*[\\w])*\\@([\\w]+[\\w\\-]*[\\w]+\\.)+[\\w]+");
regex[2] = new String("(((25)[0-5][0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9])|(\\*))\\.(((25)[0-5][0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9])|(\\*))\\.(((25)[0-5][0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9])|(\\*))\\.(((25)[0-5][0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9])|(\\*))");
regex[3] = new String("((\\+)?86(\\-)?)?(1)(((3|5|8)[0-9])|(47))[0-9]{8}");
regex[4] = new String("(((0?)|[1-9])(0?|[1-9])([0-9][0-9])\\-)?[1-9]([0-9]{6})[0-9]?((\\-)[0-9]{1,4})?");
regex[5] = new String("[1-9][0-9]{4,9}");
regex[6] = new String("(([1-5][1-9])|6[1-5]|(71)|(81)|(82))([0-9]{4})((18)|(19)|(20))([0-9]{2})((0[1-9])|(11)|(12))(([0-2][0-9])|30|31)[0-9]{3}([0-9]|x|X)");
regex[7] = new String("([0-9]{2,4}(\\-)((0?[1-9])|(10)|(11)|(12))(\\-)(([1-2][0-9])|(30)|(31)|((0)?[1-9])))|([0-9]{2,4}(\\.)((0?[1-9])|(10)|(11)|(12))(\\.)(([1-2][0-9])|(30)|(31)|((0)?[1-9])))|([0-9]{2,4}(\\/)((0?[1-9])|(10)|(11)|(12))(\\/)(([1-2][0-9])|(30)|(31)|((0)?[1-9])))|((([1-2][0-9])|(30)|(31)|((0)?[1-9]))\\-((0?[1-9])|(10)|(11)|(12))\\-([0-9]{2,4}))|((([1-2][0-9])|(30)|(31)|((0)?[1-9]))\\.((0?[1-9])|(10)|(11)|(12))\\.([0-9]{2,4}))|((([1-2][0-9])|(30)|(31)|((0)?[1-9]))\\/((0?[1-9])|(10)|(11)|(12))\\/([0-9]{2,4}))|(((0?[1-9])|(10)|(11)|(12))\\-(([1-2][0-9])|(30)|(31)|((0)?[1-9]))\\-([0-9]{2,4}))|(((0?[1-9])|(10)|(11)|(12))\\.(([1-2][0-9])|(30)|(31)|((0)?[1-9]))\\.([0-9]{2,4}))|(((0?[1-9])|(10)|(11)|(12))\\/(([1-2][0-9])|(30)|(31)|((0)?[1-9]))\\/([0-9]{2,4}))");
regex[8] = new String("(((1[0-9])|(2[0-3])|(0?[0-9]))\\:([0-5][0-9])(\\:[0-5][0-9])?)|(24\\:00(\\:00)?)");
regex[9] = new String("ed2k://\\|file\\|[\\w\\-\\%\\(\\)\\[\\]\\.\\!]*[\\w]+\\|[0-9]+\\|[0-9A-F]+\\|((p|h)\\=[0-9A-Z]+(\\|)?)?(\\/)?");
regex[10] = new String("thunder://[\\w\\+\\/\\=]+");
regex[11] = userdefsource; // 用户自定义的正则表达式1
regex[12] = userdeftext; // 用户自定义的正则表达式2
regex[13] = new String("(http://|ftp://|https://|rstp://|telnet://|file://)([\\w-]+\\.)+[\\w-]+(/[\\w\\-\\_\\.\\/\\?\\%\\&\\=\\:\\+\\,]*)?"); // 同为URL正则表达式
/* 输出文件的前缀以及保存的文件夹的名称 */
String filetitleprefix[] = new String[18];
filetitleprefix[0] = new String("URL");
filetitleprefix[1] = new String("电子邮箱地址");
filetitleprefix[2] = new String("ip地址");
filetitleprefix[3] = new String("手机号码");
filetitleprefix[4] = new String("电话号码");
filetitleprefix[5] = new String("QQ号码");
filetitleprefix[6] = new String("身份证号码");
filetitleprefix[7] = new String("日期");
filetitleprefix[8] = new String("时间");
filetitleprefix[9] = new String("电驴链接");
filetitleprefix[10] = new String("迅雷链接");
filetitleprefix[11] = new String("自定义从源代码提取");
filetitleprefix[12] = new String("自定义在正文中提取");
int i;
for (i = 0; i <= 13; i++) {
if (need[i]) {
Pattern pattern = Pattern.compile(regex[i], Pattern.CASE_INSENSITIVE);
String matchstr;
if ((i >= 3 && i <= 6) || (i >= 9 && i <= 10) || (i == 12)) matchstr = text; // 手机号码、电话号码、QQ号码、身份证号码、电驴链接、迅雷链接、自定义1在正文中提取
else matchstr = content; // 其余从源代码中提取
Matcher matcher = pattern.matcher(matchstr);
Set<String> set = new HashSet<String>();
while (matcher.find()) {
String newitem = matchstr.substring(matcher.start(), matcher.end());
set.add(newitem);
}
/* 额外分析形如"<a href="的相对链接 */
if (i == 0 || i == 13) {
Pattern patternrelativelink = Pattern.compile("\\<a\\shref\\=\"\\/[\\w\\-\\_\\.\\/\\?\\%\\&\\=\\:\\+\\,]*", Pattern.CASE_INSENSITIVE);
Matcher matcherrelativelink = patternrelativelink.matcher(content);
while (matcherrelativelink.find()) {
String newitem = content.substring(matcherrelativelink.start(), matcherrelativelink.end());
int slashpos = newitem.indexOf("/");
newitem = newitem.substring(slashpos);
slashpos = url.indexOf("://");
slashpos = url.indexOf("/", slashpos+5);
if (slashpos == -1) newitem = url+newitem;
else newitem = url.substring(0, slashpos)+newitem;
set.add(newitem);
}
}
if (i != 13) new File(filetitleprefix[i]).mkdir();
File file;
if (i != 13) file = new File(filetitleprefix[i]+"\\"+SameFileName.newfilename(filetitleprefix[i]+"\\", filetitleprefix[i]+" - "+title+".txt"));
else file = new File(tempfilename);
/* 输出提取的结果(i!=13)或临时文件(i==13) */
OutputStream os = null;
FileOutputStream fos = new FileOutputStream(file, false);
Writer out = new OutputStreamWriter(fos, "UTF-8");
Iterator<String> iter = set.iterator();
while (iter.hasNext()) {
out.write(iter.next()+"\r\n");
}
out.close();
fos.close();
}
}
} catch (PatternSyntaxException ex) {
System.out.println("自定义正则表达式语法错误");
} catch (FileNotFoundException ex) {
System.out.println("输出失败");
} catch (UnsupportedEncodingException ex) {
System.out.println("无法识别的编码方式");
} catch (IOException ex) {
System.out.println("输出失败");
}
}
/* 从源代码的<title>...</title>段中获取网页标题 */
public String gettitle() {
String contentwithoutline = content;
contentwithoutline = contentwithoutline.replace("\n", "").replace("\r", "").replaceAll("[\\s]+"," ");
String regex = "<title>[\\s\\S]*?</title>";
String title = "";
Pattern pattern = Pattern.compile(regex, Pattern.CANON_EQ);
Matcher matcher = pattern.matcher(contentwithoutline);
if (matcher.find()) {
title = contentwithoutline.substring(matcher.start(), matcher.end()).replaceAll("<.*?>", "").replace(":", "").replace("<","").replace(">","").replace("?","").replace("|","").replace("*","").replace("/","").replace("\\","").replace("\"", "");
if (title.startsWith(" ")) title = title.substring(1);
return title;
}
return "";
}
}