1. 程式人生 > >HttpClient模擬使用者登入,抓取伺服器檔案

HttpClient模擬使用者登入,抓取伺服器檔案

需求說明:將兩個不相關的系統中的電子檔案合併,包含資料庫資訊(資料庫表格式各不相同,而且不能修改專案原始碼),並且每隔一段時間可以自動同步一次。之前是通過人工手動錄入,效率低而且容易遺漏。現在決定用HttpClient開發一個小專案來實現上述功能。

一、HttpClient簡單的介紹一下

  HttpClient 是 Apache Jakarta Common 下的子專案,可以用來提供高效的、最新的、功能豐富的支援 HTTP 協議的客戶端程式設計工具包,並且它支援 HTTP 協議最新的版本和建議。官方站點:http://hc.apache.org/   

  Maven地址:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5
.5</version> </dependency>

  HTTP 協議可能是現在 Internet 上使用得最多、最重要的協議了,越來越多的 Java 應用程式需要直接通過 HTTP 協議來訪問網路資源。雖然在 JDK 的 java net包中

  已經提供了訪問 HTTP 協議的基本功能,但是對於大部分應用程式來說,JDK 庫本身提供的功能還不夠豐富和靈活。HttpClient 是 Apache Jakarta Common 下的子

  專案,用來提供高效的、最新的、功能豐富的支援 HTTP 協議的客戶端程式設計工具包,並且它支援 HTTP 協議最新的版本和建議。HttpClient 已經應用在很多的專案中,

  比如 Apache Jakarta 上很著名的另外兩個開源專案 Cactus 和 HTMLUnit 都使用了 HttpClient。現在HttpClient最新版本為 HttpClient 4.5.5(2018-06-14)。

二、使用HttpClient獲取網頁內容

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;


import java.io.IOException;


public class GetWebPageContent {
    /**
     * 抓取網頁資訊使用get請求
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        //建立httpClient例項
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //建立httpGet例項
        HttpGet httpGet = new HttpGet("http://www.baidu.com");
        CloseableHttpResponse response = httpClient.execute(httpGet);
        if (response != null){
            HttpEntity entity =  response.getEntity();  //獲取網頁內容
            String result = EntityUtils.toString(entity, "UTF-8");
            System.out.println("網頁內容:"+result);
        }
        if (response != null){
            response.close();
        }
        if (httpClient != null){
            httpClient.close();
        }
    }
}

  通過上述程式碼就可以抓取到baidu主頁的內容了,這裡需要注意的是抓取的部分網頁可能帶有中文會產生亂碼,在抓取到內容之後要進行相對應的編碼轉換

三、模擬瀏覽器登入獲取到登入後的Session值

  先通過瀏覽器F12在網頁中擷取到登入的請求地址,以及所需的引數列表List<NameValuePair>,這裡我專案用到的是地址是公司的內部的伺服器所以不需要驗證碼,如果需要驗證碼登入的話還需要解析驗證碼等操作,這裡就不詳細介紹了。

    /**
     * 獲得JesessioneID
     * @param loginUrl  登入地址
     * @param username  使用者名稱
     * @param password  密碼
     * @return  JesessioneID
     * @throws IOException IO異常
     */
    public static String getJeseeion(String loginUrl, String username, String password) throws IOException {

        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httpost = new HttpPost(loginUrl);
        List<NameValuePair> nvp = new ArrayList<NameValuePair>();
        nvp.add(new BasicNameValuePair("username", username));
        nvp.add(new BasicNameValuePair("password", password));
        String sCharSet = "UTF-8";
        httpost.setEntity(new UrlEncodedFormEntity(nvp,sCharSet));
        httpost.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        httpost.setHeader("Accept-Encoding", "gzip, deflate, sdch");
        httpost.setHeader("Accept-Language", "zh-CN,zh;q=0.8");
        httpost.setHeader("Connection", "keep-alive");
        httpost.setHeader("Cache-Control", "max-age=0");
        httpost.setHeader("Upgrade-Insecure-Requests", "1");
        httpost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.61 Safari/537.36");
        HttpResponse response = httpclient.execute(httpost);
        httpost.abort();
        if(response!=null)
        {
            String cookie = response.getFirstHeader("Set-Cookie").getValue();
            String[] cookies = cookie.split(";");
            String jession = cookies[0];    //本系統許可權只需要jessionid即可
            System.out.println(jession);
            return jession;
        }
        return null;
    }

四、下載伺服器的檔案儲存到本地硬碟

  將剛剛請求到的jesession值模擬儲存到請求頭中然後訪問伺服器中的檔案

    /**
     * 根據url下載檔案,儲存到filepath中
     * @param strUrl    檔案在伺服器中的地址
     * @param filepath    儲存本地路徑
     * @param jession    要模擬的Cookie值
     * @return
     */
    public static String download(String strUrl, String filepath, String jession) {
        try {
            HttpClient client = new DefaultHttpClient();
            HttpGet httpget = new HttpGet(strUrl);
            if(jession!=null && !jession.equals("")){
                httpget.setHeader("Cookie",jession);
            }
            HttpResponse response = client.execute(httpget);
            HttpEntity entity = response.getEntity();
            InputStream is = entity.getContent();
            if (filepath == null)
                filepath = getFilePath(response);
            File file = new File(filepath);
            file.getParentFile().mkdirs();
            FileOutputStream fileout = new FileOutputStream(file);
            /**
             * 根據實際執行效果 設定緩衝區大小
             */
            byte[] buffer=new byte[cache];
            int ch = 0;
            while ((ch = is.read(buffer)) != -1) {
                fileout.write(buffer,0,ch);
            }
            is.close();
            fileout.flush();
            fileout.close();
            System.out.println("檔案儲存成功,儲存路徑為:"+filepath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 獲取response要下載的檔案的預設路徑
     * @param response
     * @return
     */
    public static String getFilePath(HttpResponse response) {
        String filepath = root + splash;
        String filename = getFileName(response);

        if (filename != null) {
            filepath += filename;
        } else {
            filepath += getRandomFileName();
        }
        return filepath;
    }

    /**
     * 獲取response header中Content-Disposition中的filename值
     * @param response HttpResponse
     * @return filename
     */
    public static String getFileName(HttpResponse response) {
        Header contentHeader = response.getFirstHeader("Content-Disposition");
        String filename = null;
        if (contentHeader != null) {
            HeaderElement[] values = contentHeader.getElements();
            if (values.length == 1) {
                NameValuePair param = values[0].getParameterByName("filename");
                if (param != null) {
                    try {
                        //filename = new String(param.getValue().toString().getBytes(), "utf-8");
                        //filename=URLDecoder.decode(param.getValue(),"utf-8");
                        filename = param.getValue();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return filename;
    }
    /**
     * 獲取隨機檔名
     * @return 檔名
     */
    public static String getRandomFileName() {
        return String.valueOf(System.currentTimeMillis());
    }

  執行一遍看看效果

    public static void main(String[] args) throws IOException, URISyntaxException {
        //登入地址
        String loginUrl = "http://192.168.3.215:8080/system/login/loginUserAjax";

        //檔案下載連結
        String strUrl = "http://192.168.3.215:8080/system/report/projectFileManage/downLoadFileAjax?aliasName=20180611223232.xlsx&directory=201806&fileName=1126.xlsx&r=1528778758118";

        strUrl = new String(strUrl.getBytes("gbk"),"utf-8");

        //存放路徑
        String filepath = "D:\\test\\111.xlsx";

        String username = "admin";

        String password = "123456";

        String sessionId = getJeseeion(loginUrl,username,password);

        download(strUrl,filepath,sessionId);

    }

  控制檯輸出

JSESSIONID=D812E3E4E6E4A124079F154ADD160095
檔案儲存成功,儲存路徑為:D:\test\111.xlsx

  本地檔案


  模擬管理員登陸並從伺服器抓取電子檔案的功能大致實現了。