1. 程式人生 > >java爬取頭條文章中名字圖片

java爬取頭條文章中名字圖片

背景描述:

       前段時間,我哥讓我給侄女想一個好名字,作為一個工科生,這倒有點難倒我了。隱約記得以前刷頭條的時候刷到過一些好聽的名字,於是便去搜了一下。這一搜不要緊,接下來給我推送的都是關於這方面的文章,而我就毫不客氣地全都收藏了。剛好這兩天閒下來了,便想著把儲存下來。但一看,都收藏了幾十篇文章,且都是圖片,如果一篇篇地去看,然後下載,這無疑就是搬磚。這讓我這種懶人無疑是不能接受了。於是便想著寫一個爬蟲吧,把全部都爬下來。

       當然,有的磚必須得搬,比如各個文章的URL地址,這個以目前的能力還不能智慧獲取。首先手動獲取了各篇文章的URL地址,如下圖所示。

                                

在得到文章的URL之後,便開始文章中各個圖片爬取工作了。話不多說,直接放碼。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

import org.apache.commons.io.FileUtils;

import cn.cxd.tools.FileTools;

public class DownLoadToutiaoPicture {

	public static void main(String[] args) throws Exception {

		String srcPath = "D:/name/url.txt";// 儲存了各個文章URL地址
		String dstPath = "D:/name/content.txt";// 儲存了文章中各個圖片的URL
		String dstDir = "D:/name/";// 最終圖片存放的目錄
		File srcFile = new File(srcPath);
		File dstFile = new File(dstPath);

		BufferedReader br = new BufferedReader(new FileReader(srcFile));
		BufferedWriter bw = new BufferedWriter(new FileWriter(dstFile));

		String line = null;

		while ((null) != (line = br.readLine())) {
			getContent(bw, line);
		}

		line = null;

		BufferedReader br1 = new BufferedReader(new FileReader(dstFile));
		ArrayList<String> totalPicUrlList = new ArrayList<>();// 存放各個圖片的URL
		while ((null) != (line = br1.readLine())) {
			ArrayList<String> tmpList = parse(line);// 一篇文章中圖片的URL地址。
			totalPicUrlList.addAll(tmpList);// 加入到總list裡面。
		}

		for (int index = 0; index < totalPicUrlList.size(); index++) {
			// 使用了Apache第三方的common io,既然別人把輪子都造好了,那就發揚拿來主義吧!哈哈哈。。。
			FileUtils.copyURLToFile(new URL(totalPicUrlList.get(index)), new File(dstDir + index + ".jpg"));
		}

		FileTools.close(br1, bw, br);
	}

	/**
	 * 根據文章的URL地址獲取各個圖片的URL。通過分析網頁的原始碼可知,一個圖片的URL完整地址可能分行顯示。而全部圖片的URL都包含在articleInfo裡面,
	 * 因此,本文的方案是把articleInfo裡面的內容全部獲取到本地,然後再解析,即後面的parse()函式。
	 * 
	 * @param bw
	 * @param line
	 *            文章的URL地址連結
	 * @throws Exception
	 */
	private static void getContent(BufferedWriter bw, String line) throws Exception {

		URL url = new URL(line);
		// 頭條做了反爬機制,必須將程式偽裝成瀏覽器訪問才行。
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod("GET");
		conn.setRequestProperty("user-agent",
				"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36");

		BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

		// 將articleInfo裡面的內容組裝成一行,方便後面的解析工作。
		StringBuilder sb = new StringBuilder();
		boolean flag = false;
		// 這裡建議不要用while((null) !=
		// (line=br.readLine()))來做,極有可能還沒有讀到articleInfo時就為空,導致程式退出。
		for (int i = 0; i < 2000; i++) {
			String input = br.readLine();

			if (null != input) {
				System.out.println(input);
				if (input.contains("articleInfo")) {
					System.out.println(input);
					flag = true;
				}

				if (flag == true) {
					sb.append(input);
					System.out.println(input);
				}

				if (input.contains("groupId")) {// groupId為articleInfo結束後的第一行內容,讀到這表示articleInfo內容已經讀完,則將i置為200以退出迴圈。
					i = 2000;
				}
			}
		}
		bw.write(sb.toString());

		bw.newLine();
		sb = new StringBuilder();
		FileTools.close(br);
	}

	/**
	 * 解析出裡面的URL地址,存入list並返回。
	 * 
	 * @param line
	 *            上面提到的articleInfo裡面的內容。
	 * @return
	 */
	private static ArrayList<String> parse(String line) {

		int len = line.length();
		char[] ch = line.toCharArray();

		StringBuilder sb = new StringBuilder();

		ArrayList<String> picUrlList = new ArrayList<>();
		for (int i = 0; i < len - 4; i++) {
			String tmp = line.substring(i, i + 4);
			if (tmp.equals("http")) {
				for (int j = i; j < len; j++) {
					if (ch[j] != '&') {
						sb.append(ch[j]);
					} else {
						j = len;
					}
				}

				picUrlList.add(sb.toString());
				sb = new StringBuilder();
			}

		}
		return picUrlList;
	}
}

關於遇到的坑已經在程式碼註釋中做了說明。

另外,在程式最後也出現了異常,如下圖所示:

這個還得日後再去深扒。

最後爬取的結果如下圖所示: