1. 程式人生 > >Java爬蟲高階版(今日頭條)

Java爬蟲高階版(今日頭條)

宣告:浙大java課程小作業
作者:GeSq

功能描述

爬取今日頭條文章的圖片和正文文字。僅適用與頭條文章版網頁,不支援相簿版網頁。

UI介面

這裡寫圖片描述

匯出目錄:自己填寫匯出目錄。如果不填,預設是當前目錄。

點選按鈕進行爬取。

結果

這裡寫圖片描述
這裡寫圖片描述

這裡寫圖片描述

邏輯:

輸入url,爬取對應url裡的HTML檔案,從中篩選出image的url放入List中,然後逐個下載到本地資料夾。爬取對應文字,然後寫入本地文件。

程式碼

Main.java

import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class Main{ public static void main(String[] args) { SwingDemo demo = new SwingDemo(); } }

SwingDemo.java

import sun.java2d.loops.FillPath;

import
javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; /** * Created by geshuaiqi on 2017/11/9. */ public class SwingDemo extends JFrame { private String mHttpurl; // 網路url private String mLocalurl;// 本地url private String mFilePath; public
String getmLocalurl(){ return mLocalurl; } public String getmHttpurl(){ return mHttpurl; } public String getmFilePath(){ return mFilePath; } public SwingDemo() { super("頭條爬蟲助手"); JFrame frame =new JFrame("頭條爬蟲助手"); //設定標題 frame.setSize(300,120); //設定視窗大小 JPanel panel_up=new JPanel(); // JFrame 裡上下兩個部分 JPanel panel_bottom=new JPanel(); frame.setLayout(new BorderLayout()); frame.add(panel_up,BorderLayout.CENTER); // 輸入內容居中 frame.add(panel_bottom,BorderLayout.SOUTH); // 按鍵在下方 panel_up.setLayout(new GridLayout(2,2)); // 上方panel 2*2佈局 JLabel HttpLabel =new JLabel("網址"); JPanel panel_http_content =new JPanel(); JLabel catalog =new JLabel("匯出目錄"); JPanel panel_content =new JPanel(); panel_up.add(HttpLabel); panel_up.add(panel_http_content); panel_up.add(catalog); panel_up.add(panel_content); JTextField LocalUrl=new JTextField(10); // 本地儲存位置輸入 panel_content.setLayout(new GridLayout()); panel_content.add(LocalUrl); JTextField HttpUrl=new JTextField(10); // 網頁http url panel_http_content.setLayout(new GridLayout()); panel_http_content.add(HttpUrl); panel_bottom.setLayout(new FlowLayout()); // 按鈕佈局 JButton btn_pic = new JButton("匯出圖片/文字"); //JButton btn_text = new JButton("匯出文字"); panel_bottom.add(btn_pic); //panel_bottom.add(btn_text); frame.setVisible(true); btn_pic.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { mHttpurl = HttpUrl.getText().trim(); // 獲取輸入內容 mLocalurl = LocalUrl.getText().trim(); if(mLocalurl.length() == 0){ mLocalurl = "./"; } CreateFile(mLocalurl); Crawler my = new Crawler(mHttpurl, mFilePath); Thread t = new Thread(my); t.start(); } }); // btn_text.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent arg1) { // System.out.println("Text"); // } // }); } // 建立資料夾 void CreateFile(String FilePath){ File file = null; File textfile = null; File picfile = null; FilePath = FilePath + "/頭條爬蟲助手"; String tmpPath = FilePath; file = new File(tmpPath); int count = 1; while(file.exists()){ // 為避免檔名重複 tmpPath = FilePath + "_" + Integer.toString(count); count++; file = new File(tmpPath); } FilePath = tmpPath; mFilePath = FilePath; String textdir = FilePath + "/文字庫"; String picdir = FilePath + "/圖片庫"; // 建立資料夾 try { file = new File(FilePath); if (!file.exists()) { System.out.println("成功建立資料夾: "+FilePath); file.mkdirs(); } else{ System.out.println("資料夾已經存在: "+FilePath); } file = new File(picdir); if (!file.exists()) { System.out.println("成功建立資料夾: "+picdir); file.mkdirs(); } else{ System.out.println("資料夾已經存在: "+picdir); } file = new File(textdir); if (!file.exists()) { System.out.println("成功建立資料夾: "+textdir); file.mkdirs(); } else{ System.out.println("資料夾已經存在: "+textdir); } } catch (Exception e) { System.out.println("建立資料夾失敗: "+FilePath); } finally { file = null; } } public static void main(String[] args) { SwingDemo t = new SwingDemo(); } }

Crawler.java

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;

/**
 * Created by geshuaiqi on 2017/11/9.
 */
public class Crawler implements Runnable {
    private String mHttpurl;
    private String mLocalurl;
    List<String> mPicUrlList;
    private String Article;

    // 傳入網址url,以及本地匯出目錄。如果不填目錄,則預設為當下目錄
    Crawler(String url,String address_url){
        mHttpurl = url;
        mLocalurl = address_url;

        GetWebContent Content = new GetWebContent(mHttpurl);
        mPicUrlList = Content.GetPicUrl(); // 從網頁中抽取目標圖表的url
        for(int i = 0; i< mPicUrlList.size(); i++){
            System.out.println(mPicUrlList.get(i));
        }
        Article = Content.getText();
    }


    // 執行緒執行檔案
    public void run(){
        System.out.println("開始下載圖片");

        for(int i=0;i<mPicUrlList.size();i++){
            String pathname = mLocalurl + "/圖片庫/"+(i+1)+".jpg";
            getPic(mPicUrlList.get(i),pathname);
            System.out.println("已完成:"+(i+1)+".jpg , 共"+(i+1)+"/"+mPicUrlList.size()+"張");
        }
        System.out.println("全部下載完成,共" + mPicUrlList.size() + "張");

        String textpath = mLocalurl + "/文字庫/文字.txt";
        //System.out.println(Article);
        contentToTxt(textpath,Article); // 把文章輸入到指定文字檔案中
    }

    public static void contentToTxt(String filePath, String content) {
        try{
            BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filePath),true));
            writer.write("\n"+content);
            writer.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    // 下載圖片

    public void getPic(String strUrl,String pathname) {
        try {
            //構造URL
            URL url = new URL(strUrl);

            //構造連線
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            //這個網站要模擬瀏覽器才行
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko");

            //開啟連線
            conn.connect();
            //開啟這個網站的輸入流
            InputStream inStream = conn.getInputStream();

            //用這個做中轉站 ,把圖片資料都放在了這裡,再呼叫toByteArray()即可獲得資料的byte陣列
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            //用這個是很好的,不用一次就把圖片讀到了檔案中
            //要是需要把圖片用作其他用途呢?所以直接把圖片的資料弄成一個變數,十分有用
            //相當於操作這個變數就能操作圖片了

            byte[] buf = new byte[1024];
            //為什麼是1024?
            //1024Byte=1KB,分配1KB的快取
            //這個就是迴圈讀取,是一個臨時空間,多大都沒關係
            //這沒有什麼大的關係,你就是用999這樣的數字也沒有問題,就是每次讀取的最大位元組數。
            //byte[]的大小,說明你一次操作最大位元組是多少
            //雖然讀的是9M的檔案,其實你的記憶體只用1M來處理,節省了很多空間.
            //當然,設得小,說明I/O操作會比較頻繁,I/O操作耗時比較長,
            //這多少會有點效能上的影響.這看你是想用空間換時間,還是想用時間換空間了.
            //時間慢總比記憶體溢位程式崩潰強.如果記憶體足夠的話,我會考慮設大點.
            int len = 0;
            //讀取圖片資料
            while ((len = inStream.read(buf)) != -1) {
                outStream.write(buf, 0, len);
            }
            inStream.close();
            outStream.close();
            //把圖片資料填入檔案中
            File file = new File(pathname);  // 建立空的圖片檔案

            FileOutputStream op = new FileOutputStream(file); // 目標為圖片的輸出流

            op.write(outStream.toByteArray());

            op.close();
        } catch (Exception e) {
            System.out.println("Exception");
        }

    }


}

GetWebContent.java

/**
 * Created by geshuaiqi on 2017/11/10.
 */
import com.sun.org.apache.xerces.internal.xs.StringList;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GetWebContent {
    private static String Html;

    GetWebContent(String url){
        Html = getWebCon(url);
    }

    private static String getWebCon(String domain) {
        // System.out.println("開始讀取內容...("+domain+")");
        StringBuffer sb = new StringBuffer();
        try {
            java.net.URL url = new java.net.URL(domain);
            BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
            String line;
            while ((line = in.readLine()) != null) {
                sb.append(line);
            }
            //System.out.println(sb.toString());
            in.close();
        } catch (Exception e) { // Report any errors that arise
            sb.append(e.toString());
            System.err.println(e);
            System.err.println("Usage:   java   HttpClient   <URL>   [<filename>]");
        }
        return sb.toString();
    }

    private static String RegexString(String targetStr, String patternStr)
    {
        // 定義一個樣式模板,此中使用正則表示式,括號中是要抓的內容
        // 相當於埋好了陷阱匹配的地方就會掉下去
        Pattern pattern = Pattern.compile(patternStr);
        // 定義一個matcher用來做匹配
        Matcher matcher = pattern.matcher(targetStr);
        // 如果找到了
        if (matcher.find())
        {
            // 打印出結果
            return matcher.group(0);
        }
        return "Nothing";
    }

    public static String getText(){
        StringBuffer buffer = new StringBuffer();
        String regex="articleInfo(.*)commentInfo";
        String Article = RegexString(Html,regex);
        String Content = new String();

        String regexStr = "[\u4E00-\u9FA5]*";

        char[] t = Article.toCharArray();

        String text = new String();
        for(int i=0;i<Article.length();i++){
            if( (t[i] >= '\u4E00' && t[i]<='\u9FA5')  || t[i] == ',' || t[i] =='。' || t[i] =='~' || t[i] =='?' || t[i] =='!' || t[i] =='\n' ){
                text += t[i];
                if(t[i] == '。'){
                    text += '\n';
                }
            }
        }
//        Pattern pattern = Pattern.compile(regexStr);
//        // 定義一個matcher用來做匹配
//        Matcher matcher = pattern.matcher(Article);
//        while (matcher.find())
//        {
//           text += matcher.group(0);
//        }


        Content += text;
        return Content;
    }

    /*
        引數:今日頭角網址url
        返回:內容圖片的url list
     */
    public static List<String> GetPicUrl() {
        //String Html = getWebCon("https://www.toutiao.com/a6486290077252059661/");
        //String Html = getWebCon("https://www.toutiao.com/a6486288385974469134/");
        //String Html = getWebCon(url);

        StringBuffer buffer = new StringBuffer();
        String regex="articleInfo(.*)commentInfo";
        String Article = RegexString(Html,regex);
        Pattern pattern = Pattern.compile("//(.*?)&quot");
        // 定義一個matcher用來做匹配
        Matcher matcher = pattern.matcher(Article);

        List<String> urlList = new ArrayList(); // 圖片的url陣列
        while (matcher.find()){ // 找到所有相關圖片的url,然後幾種到list中
            String tmp = "http:" + matcher.group(0).replace("&quot",""); // 陣列做一下處理
            urlList.add(tmp);
        }

//        for(int i=0; i<urlList.size(); i++){
//            System.out.println(urlList.get(i));
//        }

        return urlList;

        //System.out.println(Html);

    }
}