直接上代码
目前还没写更改IP跳点的操作 ,爬到1400多条就被豆瓣服务器给BAN了,后续会慢慢地更新版本
TIP:BFS可无限爬取直至被BAN,DFS的话即使是换成尾递归也只能爬出400多条
TIPTIP:我正则表达式用的很烂,后面会把String操作全部转移到正则表达式中去,否则算法复杂度降不下来,大量异常的抛出可能也与String操作有关
package com;
/**
* 孙煜晗爬虫魔改 version 1.3
* sunYuhan
*/
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.regex.*;
public class exe {
//提取的数据存放到该目录下
//为html转化为的TXT文件
private static String savepath="C:/Users/54781/Desktop/爬虫文件/";
//等待爬取的url
private static List<String> allwaiturl=new ArrayList<>();
//记录爬取过的url
private static Set<String> alloverurl=new HashSet<>();
//记录所有url的深度进行爬取判断
private static Map<String,Integer> allurldepth=new HashMap<>();
//爬取的深度
private static int maxdepth=10;
public static void main(String args[]){
//确定爬取的网页地址
String strurl="https://book.douban.com";
workurl(strurl,1);
while(true)
{
String nexturl=allwaiturl.get(0);//获取list第一个元素
allwaiturl.remove(0);//移除list第一个元素
workurl(nexturl,allurldepth.get(nexturl)); //广搜
}
}
public static void workurl(String strurl,int depth){
//判断当前url是否爬取过
if(!(alloverurl.contains(strurl)||depth>maxdepth)){
//建立url爬取核心对象
try {
URL url=new URL(strurl);
//通过url建立与网页的连接
URLConnection conn=url.openConnection();
//通过链接取得网页返回的数据
InputStream is=conn.getInputStream();
System.out.println(conn.getContentEncoding());
//一般按行读取网页数据,并进行内容分析
//因此用BufferedReader和InputStreamReader把字节流转化为字符流的缓冲流
//进行转换时,需要处理编码格式问题
BufferedReader br=new BufferedReader(new InputStreamReader(is,"UTF-8"));
//按行读取并打印
String line=null;
// String line2=null;
//正则表达式的匹配规则提取该网页的链接
Pattern p2=Pattern.compile("(?<=<span class=\"short\">).*?(?=</span>)");//找到评论
Pattern p=Pattern.compile("<a .*href=.+</a>");//找到url
Pattern p3=Pattern.compile("(?<=<a class=\" tag\").*?(?=</a>)");//找到标签
Pattern p4=Pattern.compile("(?<=<span property=\"v:itemreviewed\">).*?(?=</span>)");//找到书名
// while()
//建立一个输出流,用于保存文件,文件名为执行时间,以防重复
// PrintWriter pw=new PrintWriter(new File(savepath+System.currentTimeMillis()+".txt"));
PrintWriter writer2 = null;//用于写评论
PrintWriter writer3=null;//用于写标签
boolean flag=false;
String word=null;
String tag=null;
while((line=br.readLine())!=null){
//System.out.println(line);
//编写正则,匹配超链接地址
// pw.println(line);
Matcher m=p.matcher(line);//url
Matcher m2=p2.matcher(line);//评论
Matcher m3=p3.matcher(line);//标签
Matcher m4=p4.matcher(line);//书名
String bookname;
if(m4.find()&&!flag)//找到书名即可开始找标签和评论
{
bookname=m4.group();
writer2=new PrintWriter(new File(savepath+"豆瓣评论/"+bookname+".txt"));
writer3=new PrintWriter(new File(savepath+"豆瓣标签/"+bookname+".txt"));
flag=true;
}
while(m3.find()&&flag)//爬标签
{
tag=m3.group();
tag=tag.substring(tag.indexOf(">")+1, tag.length());//对tag的string处理
writer3.println(tag);
writer3.flush();
}
while(m2.find()&&flag)//爬评论
{
word=m2.group();
writer2.println(word);
writer2.flush();
}
while(m.find()){//爬url
String href=m.group();
//找到超链接地址并截取字符串
//有无引号
href=href.substring(href.indexOf("href="));
if(href.charAt(5)=='\"'){
href=href.substring(6);
}else{
href=href.substring(5);
}
//除去HTTP协议那部分
try{
href=href.substring(0,href.indexOf("\""));
}catch(Exception e){
try{
href=href.substring(0,href.indexOf(" "));
}catch(Exception e1){
href=href.substring(0,href.indexOf(">"));
}
}
if(href.charAt(0)=='.'&&strurl.endsWith("/"))//判断简写URL问题
href=strurl+href.substring(2,href.length()-1);
else if(href.charAt(0)=='.')
href=strurl+href.substring(1,href.length()-1);
if(href.startsWith("https://book.douban.com/subject/")){
//保证在站内访问
//将url地址放到队列中
allwaiturl.add(href);
allurldepth.put(href,depth+1);
}
}
}
//writer2.flush();
writer2.close();
// pw.close();
br.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//将当前url归列到alloverurl中
alloverurl.add(strurl);
System.out.println(strurl+"网页爬取完成,已爬取数量:"+alloverurl.size()+",剩余爬取数量:"+allwaiturl.size());
}
//用递归的方法继续爬取其他链接
// String nexturl=allwaiturl.get(0);
// allwaiturl.remove(0);
// workurl(nexturl,allurldepth.get(nexturl));
}
}