ECM
ECM
总版主
总版主
  • 社区居民
  • 忠实会员
  • 原创写手
阅读:795回复:0

抓取煎蛋ooxx图(HttpClient,Jsoup)

楼主#
更多 发布于:2016-01-02 12:25
有人说,程序员注定是孤单的,只能与IDE之类为伍,但是利用IDE之徒,能编制出我们想要的hello word,这次hello ooxx吧
代码作用很简单,就是批量抓取jandan.net/ooxx的图片.多线程下载图片.请大家慎重执行,代码仅供学习之用.


亲修改   苦逼的线程池->第33行   的目录为你自己机器上合适的目录



package my.projects.jandan.main;
 
import my.projects.jandan.thread.ThreadPoolMananger;
 
public class Main {
 
    public static void main(String[] args) {
        // System.out.println(Integer.MAX_VALUE);
        new ThreadPoolMananger();
    }
}
3. [代码]苦逼的线程池    
package my.projects.jandan.thread;
 
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
 
import my.projects.jandan.utils.HtmlParser;
import my.projects.jandan.utils.SimpleHttpClient;
 
public class ThreadPoolMananger {
    final int DOWNLOAD_THREAD = 30;
    final int PAGE_THREAD = 2;
    // 定义一个页面导航的队列,大概看了一下估计有200多页吧
    final BlockingQueue<String> naviQueue = new LinkedBlockingQueue<String>(3);
    // 定义一个图片网址的队列,这个估计很多
    final BlockingQueue<String> imgQueue = new LinkedBlockingQueue<String>(100);
    final ExecutorService exec = Executors
            .newFixedThreadPool((DOWNLOAD_THREAD + PAGE_THREAD));
    // 定义一个开始的倒数锁
    final CountDownLatch begin = new CountDownLatch(1);
    // 定义一个结束的倒数锁
    final CountDownLatch end = new CountDownLatch(
            (DOWNLOAD_THREAD + PAGE_THREAD));
 
    public ThreadPoolMananger() {
        int i = 1;
        for (; i <= PAGE_THREAD; i++) {
            exec.submit(new PageThread(i, begin, end));
        }
        for (; i <= (DOWNLOAD_THREAD + PAGE_THREAD); i++) {
            exec.submit(new ImageThread(i, "D:\\ooxx_0304", begin, end));
        }
 
        HtmlParser parser = new HtmlParser();
        SimpleHttpClient client = new SimpleHttpClient();
        parser.setHtml(client.get("http://jandan.net/ooxx"));
        System.out.println("====开始抓取首页");
        try {
            naviQueue.put(parser.getPageNavi());
            parser.handleImgs(imgQueue);
        } catch (InterruptedException e) {
        }
        client.close();
        System.out.println("首页结束,开始执行多线程抓取");
        begin.countDown();
    }
 
    class ImageThread implements Runnable {
        private final CountDownLatch startSignal;
        private final CountDownLatch stopSignal;
        private int threadIdx;
        private String dest;
 
        public ImageThread(int index, String dest, CountDownLatch start,
                CountDownLatch end) {
            this.threadIdx = index;
            this.dest = dest;
            this.startSignal = start;
            this.stopSignal = end;
        }
 
        @Override
        public void run() {
            try {
                // 等待初始的线程结束
                startSignal.await();
            } catch (Exception e) {
            }
            System.out.println("[" + threadIdx + "]线程开始");
            SimpleHttpClient client = new SimpleHttpClient();
            String picurl = "";
            int left = 0;
            // 这个线程不断的从图片队列里面取出图片的地址
            while (true) {
                // 取出一个图片地址
                try {
                    picurl = imgQueue.take();
                    left = imgQueue.size();
                } catch (InterruptedException e1) {
                    System.err
                            .println("[" + threadIdx + "]:" + e1.getMessage());
                }
                if ("".equals(picurl)) {
                    try {
                        // 结束标志,丢回去,其他的线程要根据这个判断结束
                        imgQueue.put("");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    // 如果说,取到图片地址为空而且页面的已经解析完毕,这个就应该要结束了。
                    break;
                }
                try {
                    System.out.println("[" + threadIdx + "][图片left:" + left
                            + "]线程开始抓取image-->" + picurl);
                    client.downloadFile(picurl, dest);
                } catch (Exception e) {
                    System.err.println("[" + threadIdx + "]:" + e.getMessage());
                }
            }
            client.close();
            stopSignal.countDown();
        }
    }
 
    class PageThread implements Runnable {
        private final CountDownLatch startSignal;
        private final CountDownLatch stopSignal;
        private int index;
 
        public PageThread(int index, CountDownLatch start, CountDownLatch end) {
            this.startSignal = start;
            this.stopSignal = end;
            this.index = index;
        }
 
        @Override
        public void run() {
            try {
                startSignal.await();
                System.out.println("[" + index + "]线程开始");
            } catch (Exception e) {
            }
            System.out.println("[" + index + "]线程开始");
            String html = "";
            String url = "";
            int left = 0;
            HtmlParser parser = new HtmlParser();
            SimpleHttpClient client = new SimpleHttpClient();
            while (true) {
                try {
                    url = naviQueue.take();
                    left = naviQueue.size();
                    if ("".equals(url)) {
                        // 把结束的标志放回去,其他的线程也应该要调用
                        naviQueue.put("");
                        break;
                    }
                } catch (Exception e) {
                    System.err.println("[" + index + "]:" + e.getMessage());
                }
                System.out.println("[" + index + "][页面left:" + left
                        + "]线程抓取html-->" + url);
                try {
                    html = client.get(url);
                } catch (Exception e1) {
                }
                parser.setHtml(html);
                String next = parser.getPageNavi();
                try {
                    if (next == null) {
 
                        naviQueue.put("");
                        parser.handleImgs(imgQueue);
                        // 在图片队列的最后也放上一个""作为结束的标志吧
                        imgQueue.put("");
 
                    } else {
                        naviQueue.put(next);
                        parser.handleImgs(imgQueue);
                    }
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            client.close();
            stopSignal.countDown();
        }
 
    }
 
}
4. [代码]HttpClient连接管理类    


package my.projects.jandan.utils;
  
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
  
public class HttpClientConnectionManager {
  
    private static ThreadSafeClientConnManager cm;
  
    public final static int MAX_TOTAL_CONNECTIONS = 800;
    public final static int MAX_ROUTE_CONNECTIONS = 400;
    public final static int CONNECT_TIMEOUT = 10000;
    static {
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory
                .getSocketFactory()));
        schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory
                .getSocketFactory()));
        ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(
                schemeRegistry);
        // Increase max total connection to 200
        cm.setDefaultMaxPerRoute(MAX_ROUTE_CONNECTIONS);
    }
  
    public static DefaultHttpClient getHttpClient() {
        return new DefaultHttpClient(cm);
    }
  
}
5. [代码]简易的HttpClient    


package my.projects.jandan.utils;
  
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
  
import javax.net.ssl.SSLHandshakeException;
  
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
  
public class SimpleHttpClient {
  
    private ThreadLocal<DefaultHttpClient> httpclient = new ThreadLocal<DefaultHttpClient>();
  
    public static int imageName = 0;
  
    public SimpleHttpClient() {
        DefaultHttpClient client = HttpClientConnectionManager.getHttpClient();
        // 模拟浏览器,解决一些服务器程序只允许浏览器访问的问题
        client.getParams()
                .setParameter(CoreProtocolPNames.USER_AGENT,
                        "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");
        client.getParams().setParameter(
                CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8");
  
        client.setHttpRequestRetryHandler(requestRetryHandler);
        httpclient.set(client);
    }
  
    /**
     *
     * @param url
     * @return
     */
    public String get(String url) {
        HttpGet hg = new HttpGet(url);
        hg.addHeader("Referer", "http://jandan.net/ooxx");
        hg.addHeader(
                "Accept",
                "application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */*");
        String resposne = "";
        try {
            synchronized (responseHandler) {
                resposne = httpclient.get().execute(hg, responseHandler);
            }
        } catch (Exception e) {
            resposne = "";
        } finally {
            hg.abort();
        }
        return resposne;
    }
  
    /**
     * 下载文件
     *
     * @param url
     *            文件http地址
     * @param dir
     *            目标文件
     * @throws IOException
     */
    public synchronized void downloadFile(String url, String dir)
            throws Exception {
        if (url == null || "".equals(url)) {
            return;
        }
        if (dir == null || "".equals(dir)) {
            return;
        }
        if (!dir.endsWith(File.separator)) {
            dir += File.separator;
        }
        File desPathFile = new File(dir);
        if (!desPathFile.exists()) {
            desPathFile.mkdirs();
        }
        String fullPath = dir + (imageName++);
  
        HttpGet httpget = new HttpGet(url);
        httpget.addHeader("Referer", "http://jandan.net/ooxx");
  
        HttpResponse response = httpclient.get().execute(httpget);
        String type = null;
        try {
  
            type = response.getHeaders("Content-Type")[0].getValue();
  
            if (type == null || "".equals(type)) {
                type = "jpg";
            } else {
                type = type.substring(type.lastIndexOf("/") + 1, type.length());
            }
        } catch (Exception e) {
            type = "jpg";
        }
  
        fullPath = fullPath + "." + type;
  
        HttpEntity entity = response.getEntity();
        InputStream input = null;
        try {
            input = entity.getContent();
  
            File file = new File(fullPath);
            FileOutputStream output = FileUtils.openOutputStream(file);
            try {
                IOUtils.copy(input, output);
            } finally {
                IOUtils.closeQuietly(output);
            }
  
            EntityUtils.consume(entity);
        } finally {
            IOUtils.closeQuietly(input);
            if (httpget != null) {
                httpget.abort();
            }
        }
    }
  
    public void close() {
        this.httpclient.get().getConnectionManager().shutdown();
    }
  
    // 异常自动恢复处理, 使用HttpRequestRetryHandler接口实现请求的异常恢复
    private static HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() {
        // 自定义的恢复策略
        public boolean retryRequest(IOException exception, int executionCount,
                HttpContext context) {
            // 设置恢复策略,在发生异常时候将自动重试5次
            if (executionCount >= 3) {
                // Do not retry if over max retry count
                return false;
            }
            if (exception instanceof NoHttpResponseException) {
                // Retry if the server dropped connection on us
                return true;
            }
            if (exception instanceof SSLHandshakeException) {
                // Do not retry on SSL handshake exception
                return false;
            }
            HttpRequest request = (HttpRequest) context
                    .getAttribute(ExecutionContext.HTTP_REQUEST);
            boolean idempotent = (request instanceof HttpEntityEnclosingRequest);
            if (!idempotent) {
                // Retry if the request is considered idempotent
                return true;
            }
            return false;
        }
    };
    // 使用ResponseHandler接口处理响应,HttpClient使用ResponseHandler会自动管理连接的释放,解决了对连接的释放管理
    private static ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
        // 自定义响应处理
        public String handleResponse(HttpResponse response)
                throws ClientProtocolException, IOException {
  
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String charset = EntityUtils.getContentCharSet(entity) == null ? "UTF-8"
                        : EntityUtils.getContentCharSet(entity);
                return new String(EntityUtils.toByteArray(entity), charset);
            } else {
                return null;
            }
        }
    };
  
    /*
     * //
     * 使用ResponseHandler接口处理响应,HttpClient使用ResponseHandler会自动管理连接的释放,解决了对连接的释放管理
     * private static ResponseHandler<byte[]> responseHandlerToByte = new
     * ResponseHandler<byte[]>() { // 自定义响应处理 public byte[]
     * handleResponse(HttpResponse response) throws ClientProtocolException,
     * IOException { StatusLine statusLine = response.getStatusLine(); int
     * statucode = statusLine.getStatusCode(); if (statucode ==
     * HttpStatus.SC_MOVED_TEMPORARILY || statucode ==
     * HttpStatus.SC_MOVED_PERMANENTLY || statucode == HttpStatus.SC_SEE_OTHER
     * || statucode == HttpStatus.SC_TEMPORARY_REDIRECT) {
     * System.out.println("Redirect:"); Header header =
     * response.getFirstHeader("location"); if (header != null) { String newuri
     * = header.getValue(); if ((newuri == null) || (newuri.equals(""))) newuri
     * = "/"; System.out.println("To:" + newuri); return null; }
     * System.out.println("Invalid redirect"); }
     *
     * HttpEntity entity = response.getEntity(); if (entity != null) { return
     * EntityUtils.toByteArray(entity); } else { return null; } } };
     */
}
6. [代码]解析ooxx的链接     跳至 [2] [3] [4] [5] [6] [全屏预览]


package my.projects.jandan.utils;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
 
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
 
public class HtmlParser {
 
    private String html = "";
 
    public HtmlParser() {
    }
 
    public HtmlParser(String html) {
        this.html = html;
    }
 
    public HtmlParser(File file) {
        BufferedReader br;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(
                    file), "utf-8"));
 
            StringBuilder sb = new StringBuilder();
            String tmp;
            while ((tmp = br.readLine()) != null) {
                sb.append(tmp);
            }
            this.html = sb.toString();
        } catch (Exception e) {
            this.html = "";
            e.printStackTrace();
        }
    }
 
    public String getPageNavi() {
        // ArrayList<String> imgList = null;
        if (this.html == null || "".equals(this.html)) {
            return null;
        }
        Document doc = Jsoup.parse(this.html);
        Element comments = doc.select("p.cp-pagenavi").first();
        // 第一步获得这里上一页的地址:
        Element pageNavi = comments.select("a.previous-comment-page").first();
        if (pageNavi == null) {
            return null;
        }
        String tmp=pageNavi.attr("href");
        String nextPage =tmp .substring(0, tmp.lastIndexOf('#'));
        return nextPage;
    }
 
    public void handleImgs(BlockingQueue<String> imageQueue) {
        Document doc = Jsoup.parse(this.html);
        Element commentlist = doc.select("ol.commentlist").first();
        Elements comments = commentlist.select("p>img");
        if (comments.size() < 1) {
            return;
        }
        String src = "";
        for (Element img : comments) {
            src = img.attr("src");
            try {
                imageQueue.put(src);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
 
    public LinkedList<String> handleImgs() {
        Document doc = Jsoup.parse(this.html);
        Element commentlist = doc.select("ol.commentlist").first();
        Elements comments = commentlist.select("p>img");
        if (comments.size() < 1) {
            return null;
        }
        LinkedList<String> imgs = new LinkedList<String>();
        String src = "";
        for (Element img : comments) {
            src = img.attr("src");
            imgs.add(src);
        }
        return imgs;
    }
 
    public String getHtml() {
        return html;
    }
 
    public void setHtml(String html) {
        this.html = html;
    }
 
}
举报

 

 

 

 

 

 

 

异常中心网是一家专门收集整理程序员编程过程中遇到的常见异常(exception)以及各种异常问答中心的网站。异常中心网旨在,减少程序员在编码遇到异常,处理各种异常时间和痛苦,让程序员能更愉快的、快速的定位异常并查找对应的异常解决方案。异常中心网诚心打造最完美的编程社区为程序员用户服务,努力成为最好的程序员乐园程序员社区程序异常中心程序bug中心异常问答中心

 

喜欢0 评分0
游客

返回顶部