Java爬蟲高階版(今日頭條)
阿新 • • 發佈:2019-02-18
宣告:浙大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("//(.*?)"");
// 定義一個matcher用來做匹配
Matcher matcher = pattern.matcher(Article);
List<String> urlList = new ArrayList(); // 圖片的url陣列
while (matcher.find()){ // 找到所有相關圖片的url,然後幾種到list中
String tmp = "http:" + matcher.group(0).replace(""",""); // 陣列做一下處理
urlList.add(tmp);
}
// for(int i=0; i<urlList.size(); i++){
// System.out.println(urlList.get(i));
// }
return urlList;
//System.out.println(Html);
}
}