找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 2908|回复: 1

ReactOS爬虫改进版

[复制链接]
发表于 2014-2-28 13:20:24 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
  1. import java.io.File;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.net.URL;
  6. import java.net.URLConnection;
  7. import java.util.Stack;

  8. import org.jsoup.Jsoup;
  9. import org.jsoup.nodes.Document;
  10. import org.jsoup.nodes.Element;
  11. import org.jsoup.select.Elements;

  12. public class ReactOSDownloader
  13. {
  14.         public static String url="http://svn.reactos.org/";
  15.         public static String path="k:/reactos/";
  16.         public static int filethreadnum=0;

  17.         public static boolean setinit=false;//是否强制初始化
  18.         public static String[] initstring={};//初始化目录位要开始更新的目录,按深度顺序
  19.         public static int curdepth=0;//当前初始化深度
  20.         public static Stack<FolderClass> folders=new Stack<FolderClass>();

  21.         public static class FileThread extends Thread
  22.         {
  23.                 String filepath;
  24.                 String curnode;

  25.                 FileThread(String filepath,String curnode)
  26.                 {
  27.                         this.filepath=filepath;
  28.                         this.curnode=curnode;
  29.                 }

  30.                 @Override
  31.                 public void run()
  32.                 {
  33.                         try
  34.                         {
  35.                                 while(filethreadnum>30)
  36.                                 {
  37.                                         sleep(1000);
  38.                                 }
  39.                                 filethreadnum++;
  40.                                 int byteread=0;
  41.                                 int bytesum=0;
  42.                                 URL weburl=new URL(url+filepath+curnode);
  43.                                 URLConnection con=weburl.openConnection();
  44.                                 InputStream instream=con.getInputStream();
  45.                                 FileOutputStream fs=new FileOutputStream(escape((path+filepath+curnode).replace("%20"," ")));
  46.                                 byte[] buffer=new byte[65536];
  47.                                 while((byteread=instream.read(buffer)) != -1)
  48.                                 {
  49.                                         bytesum+=byteread;
  50.                                         fs.write(buffer,0,byteread);
  51.                                         System.out.println("\t\t当前下载文件:"+filepath+curnode+"\t当前大小:"+bytesum);
  52.                                 }
  53.                                 fs.close();
  54.                                 instream.close();
  55.                                 filethreadnum--;
  56.                         }
  57.                         catch(Exception e)
  58.                         {
  59.                                 System.out.println("error");
  60.                                 filethreadnum--;
  61.                                 new File(path+filepath+curnode).deleteOnExit();;
  62.                         }
  63.                 }
  64.         }

  65.         public static String escape(String src)
  66.         {
  67.                 StringBuffer sbuf=new StringBuffer();
  68.                 int len=src.length();

  69.                 for(int i=3;i<len;i++)
  70.                 {
  71.                         char ch=src.charAt(i);
  72.                         if(ch == '\\' || ch == ':' || ch == '*' || ch == '?' || ch == '"' || ch == '<' || ch == '>' || ch == '|')
  73.                                 ;
  74.                         else
  75.                                 sbuf.append(ch);
  76.                 }
  77.                 return src.substring(0,3)+formatpath(sbuf.toString());
  78.         }

  79.         public static String formatpath(String src)
  80.         {
  81.                 if(!src.contains("http"))
  82.                         return src;
  83.                 String newstr=src.substring(0,10)+src.substring(10).replaceAll("/{2,}", "/");
  84.                 return newstr;
  85.         }

  86.         public static String createFolder(String folderPath)
  87.         {
  88.                 String txt = folderPath;
  89.                 try
  90.                 {
  91.                         File myFilePath = new File(txt);
  92.                         txt = folderPath;
  93.                         if (!myFilePath.exists())
  94.                         {
  95.                                 myFilePath.mkdir();
  96.                         }
  97.                 }
  98.                 catch (Exception e)
  99.                 {
  100.                         System.out.println("错误!");
  101.                 }
  102.                 return txt;
  103.         }

  104.         public static class FolderClass
  105.         {
  106.                 String filepath;
  107.                 Element e;
  108.                   
  109.                 FolderClass(Element e,String filepath)
  110.                 {
  111.                         this.filepath=filepath;
  112.                         this.e=e;
  113.                 }
  114.                   
  115.                 public void ResolveFolder()
  116.                 {
  117.                         try
  118.                         {                    
  119.                                 String curnode=e.attr("href");
  120.                                 if(curnode.indexOf(';') != -1 || curnode.charAt(0) == '/' || curnode.equals("../") || curnode.equals("svn/"))
  121.                                         return;
  122.                                 System.out.println(curnode+"\t"+filepath);
  123.                                 if(setinit)
  124.                                 {
  125.                                         if(!curnode.equals(initstring[curdepth]))
  126.                                                 return;
  127.                                         else
  128.                                                 curdepth++;
  129.                                         if(curdepth >= initstring.length)
  130.                                                 setinit=false;
  131.                                 }
  132.                                   
  133.                                 if(curnode.charAt(curnode.length()-1) == '/')
  134.                                 {//目录
  135.                                         createFolder(escape((path+filepath+curnode).replace("%20"," ")));
  136.                                         Document doc=Jsoup.connect(formatpath(url+filepath+curnode)).timeout(0).get();
  137.                                         System.out.println("当前目录:"+url+formatpath(filepath)+curnode);
  138.                                         Elements items=doc.select("tbody tr a");
  139.                                         for(Element ele1:items)
  140.                                         {
  141.                                                 folders.push(new FolderClass(ele1,filepath+curnode));
  142.                                         }
  143.                                         items.clear();
  144.                                         items=doc.select("ul li a");
  145.                                         for(Element ele2:items)
  146.                                         {
  147.                                                 folders.push(new FolderClass(ele2,filepath+curnode));
  148.                                         }
  149.                                 }
  150.                                 else
  151.                                 {//文件
  152.                                         File curfile=new File((path+filepath+curnode).replace("%20"," "));
  153.                                         if(curfile.exists())
  154.                                                 return;
  155.                                         (new FileThread(filepath,curnode)).start();
  156.                                 }
  157.                         }
  158.                         catch(Exception e)
  159.                         {
  160.                                 System.out.println("error");
  161.                         }
  162.                 }
  163.         }

  164.         public static void main(String[] args) throws IOException
  165.         {
  166.                 try
  167.                 {
  168.                         Document doc = Jsoup.connect(url).timeout(0).get();
  169.                         Elements items=doc.select("tbody tr a");
  170.                         createFolder(path);
  171.                         for(Element e1:items)
  172.                         {
  173.                                 folders.push(new FolderClass(e1,""));
  174.                         }
  175.                         items=doc.select("ul li a");
  176.                         for(Element e2:items)
  177.                         {
  178.                                 folders.push(new FolderClass(e2,""));
  179.                         }
  180.                        
  181.                         new Thread()
  182.                         {
  183.                                 @Override
  184.                                 public void run()
  185.                                 {
  186.                                         while(!folders.empty())
  187.                                         {
  188.                                                 int searchonce=30;
  189.                                                 while(searchonce-- > 0)
  190.                                                 {
  191.                                                         folders.pop().ResolveFolder();
  192.                                                 }
  193.                                         }
  194.                                 }
  195.                         }.start();
  196.                           
  197.                         while(filethreadnum != 0 || folders.size() != 0)
  198.                         {
  199.                                 Thread.sleep(1000);
  200.                         }
  201.                 }
  202.                 catch(Exception exc)
  203.                 {
  204.                         System.out.println("错误!");
  205.                 }
  206.         }
  207. }
复制代码

以前那个是只能多线程文件下载,现在支持多线程文件夹解析,为了实现这个用到了栈这种数据结构,之所以用栈是有原因的,我先考虑的是队列,因为写搜索工具用的是这个数据结构。
现在来分析为什么要用栈而不用队列,假设目录情况是这样的,从上到下为父子关系树:
                                          A
                       B                                    C
          D                      E                 F                   G
   H            I          J         K        L       M        N          O
P  Q        R   S    T  U     V  W   X  Y    Z  A    B  C      D  E   
目录只能逐层遍历,且只能按照先序遍历,这是因为作为下载器,磁盘上只有建立了父文件夹才能建立子文件夹,本身是递归的。
遍历顺序如下;ABDHPQIRSEJTUKVWCFLXYMZAGNBCODE
因为目录众多,因此多线程需要设定一个线程数量上限,多线程也就是多任务,现在得目的是在解析完当前文件夹时将子文件夹加入任务,那么顺序问题是值得考虑的,因为搞不好,会导致2种情况:1.任务太多,占用内存过多,2.由于设定了上限,会造成死锁,也就是任务等待加入自己的子任务以后才能结束,也就是等这个上限值低于阈值时结束,而该阈值要等该任务结束才能降低。针对这种情况,可以选择2种数据结构:栈和队列

使用队列和栈栈解析目录的时候,把所有子目录加入任务,相应地主函数启动线程用于定时取出一定数量文件夹进行解析,这样的好处是,取出的一定是子文件夹,这样递归以后的结果是先递归完子文件夹再递归其他兄弟节点,不至于栈溢出。
下面是同时进行的任务数为2的推演:
使用栈的结果为:A->CB->GFED->ONMLED->DECBMLED->AZYXED->KJIH->WVUTIH->SRQP->结束
使用队列的结果为:A->BC->DEFG->HIJKFG->PQRSJKFG->TUVWFG->LMNO->XYZANO->BCDE->结束

经测试,速度很快

问题1:上面代码是栈实现的,请自己写出队列版代码
问题2:代码中实现了一种功能,它允许你今天下载了一部分reactos代码,然后结束java程序,第二天开电脑的时候只需要设置以下参数,就可以从昨天开始处继续运行,请问代码中如何实现的

回复

使用道具 举报

发表于 2014-3-26 16:23:50 | 显示全部楼层
爬ReactOs的。学习了
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-24 13:13 , Processed in 0.039462 second(s), 21 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表