java爬取app_Java实现爬虫给App提供数据(Jsoup 网络爬虫)
需求 ##
近期基于 Material Design 重構了自己的新聞 App,數據來源是個問題。
有前人分析了知乎日報、鳳凰新聞等 API,依據相應的 URL 能夠獲取新聞的 JSON 數據。為了鍛煉寫代碼能力,筆者打算爬蟲新聞頁面,自己獲取數據構建 API。
效果圖
下圖是原站點的頁面
爬蟲獲取了數據,展示到 APP 手機端
爬蟲思路
Created with Rapha?l 2.1.0開始基于Get請求獲取URL對于的網頁Html利用Jsoup把Html解析為Document利用Dom的getElementsById等方法獲取標題、公布時間、內容等依據標題、公布時間、內容構建javabean給APP使用結束
關于 App 的實現過程能夠參看這幾篇文章,本文主要解說一下怎樣爬蟲數據。
Jsoup 簡單介紹
Jsoup 是一個 Java 的開源HTML解析器,可直接解析某個URL地址、HTML文本內容。
Jsoup主要有以下功能:
- 從一個URL,文件或字符串中解析HTML。
- 使用DOM或CSS選擇器來查找、取出數據;
- 對HTML元素、屬性、文本進行操作;
- 清除不受信任的HTML (來防止XSS攻擊)
爬蟲過程
Get 請求獲取網頁 HTML
新聞網頁Html的DOM樹例如以下所看到的:
以下這段代碼依據指定的 url,用代碼獲取get 請求返回的 html 源碼。
public static String doGet(String urlStr) throws CommonException {
URL url;
String html = "";
try {
url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setDoInput(true);
connection.setDoOutput(true);
if (connection.getResponseCode() == 200) {
InputStream in = connection.getInputStream();
html = StreamTool.inToStringByByte(in);
} else {
throw new CommonException("新聞服務器返回值不為200");
}
} catch (Exception e) {
e.printStackTrace();
throw new CommonException("get請求失敗");
}
return html;
}
InputStream in = connection.getInputStream();將得到輸入流轉化為字符串是個普遍需求,我們將其抽象出來,寫一個工具方法。
public class StreamTool {
public static String inToStringByByte(InputStream in) throws Exception {
ByteArrayOutputStream outStr = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
StringBuilder content = new StringBuilder();
while ((len = in.read(buffer)) != -1) {
content.append(new String(buffer, 0, len, "UTF-8"));
}
outStr.close();
return content.toString();
}
}
解析 HTML 獲取標題
利用 google 瀏覽器的審查元素,找出新聞標題對于的html 代碼:
關于舉辦《經典音樂作品贊賞與人文審美》講座的通知
我們須要從上面的 HTML 中找出id="article_title"的部分,使用 getElementById(String id) 方法
String htmlStr = HttpTool.doGet(urlStr);
// 將獲取的網頁 HTML 源碼轉化為 Document
Document doc = Jsoup.parse(htmlStr);
Element articleEle = doc.getElementById("article");
// 標題
Element titleEle = articleEle.getElementById("article_title");
String titleStr = titleEle.text();
獲取公布日期、信息來源
相同找出對于的 HTML 代碼
2015-05-28
來源:
瀏覽次數: 477
思路也和上面相似。使用 getElementById(String id) 方法找出id="article_detail"為Element。再利用getElementsByTag獲取span 部分。由于一共同擁有3個 ... ,所以返回的是Elements而不是Element。
// article_detail包含了 2016-01-15 來源: 瀏覽次數:177
Element detailEle = articleEle.getElementById("article_detail");
Elements details = detailEle.getElementsByTag("span");
// 公布時間
String dateStr = details.get(0).text();
// 新聞來源
String sourceStr = details.get(1).text();
解析瀏覽次數
假設打印出上面的details.get(2).text(),僅僅會得到
瀏覽次數:
沒有瀏覽次數?為什么呢?
由于瀏覽次數是JavaScript 渲染出來的。 Jsoup爬蟲可能僅僅提取HTML內容,得不到動態渲染出的數據。
解決方法有兩種
在爬蟲的時候,內置一個瀏覽器內核,運行js渲染頁面后。再抓取。
所以分析JS請求,找到相應數據的請求url
假設你訪問上面的 urlhttp://see.xidian.edu.cn/index.php/news/click/id/7428。會得到以下的結果
document.write(478)
這個478就是我們須要的瀏覽次數。我們對上面的url做get 請求,得到返回的字符串。利用正則找出當中的數字。
// 訪問這個新聞頁面。瀏覽次數會+1,次數是 JS 渲染的
String jsStr = HttpTool.doGet(COUNT_BASE_URL + currentPage);
int readTimes = Integer.parseInt(jsStr.replaceAll("\\D+", ""));
// 或者使用以下這個正則方法
// String readTimesStr = jsStr.replaceAll("[^0-9]", "");
解析新聞內容
筆者本來是獲取新聞內容純文字的形式,但后來發現 Android 端也能夠顯示 CSS 格式,所以后來內容保留了 HTML 格式。
Element contentEle = articleEle.getElementById("article_content");
// 新聞主體內容
String contentStr = contentEle.toString();
// 假設用 text()方法。新聞主體內容的 html 標簽會丟失
// 為了在 Android 上用 WebView 顯示 html,用toString()
// String contentStr = contentEle.text();
解析圖片 Url
注意一個網頁上大大小小的圖片非常多,為了僅僅獲取新聞正文中的內容。我們最好首先定位到新聞內容的Element。然后再利用getElementsByTag(“img”)篩選出圖片。
Element contentEle = articleEle.getElementById("article_content");
// 新聞主體內容
String contentStr = contentEle.toString();
// 假設用 text()方法,新聞主體內容的 html 標簽會丟失
// 為了在 Android 上用 WebView 顯示 html,用toString()
// String contentStr = contentEle.text();
Elements images = contentEle.getElementsByTag("img");
String[] imageUrls = new String[images.size()];
for (int i = 0; i < imageUrls.length; i++) {
imageUrls[i] = images.get(i).attr("src");
}
新聞實體類 JavaBean
上面獲取了新聞的標題、公布日期、閱讀次數、新聞內容等等,我們自然須要構造一個 javabean。把獲取的內容封裝進實體類中。
public class ArticleItem {
private int index;
private String[] imageUrls;
private String title;
private String publishDate;
private String source;
private int readTimes;
private String body;
public ArticleItem(int index, String[] imageUrls, String title, String publishDate, String source, int readTimes,
String body) {
this.index = index;
this.imageUrls = imageUrls;
this.title = title;
this.publishDate = publishDate;
this.source = source;
this.readTimes = readTimes;
this.body = body;
}
@Override
public String toString() {
return "ArticleItem [index=" + index + ",\n imageUrls=" + Arrays.toString(imageUrls) + ",\n title=" + title
+ ",\n publishDate=" + publishDate + ",\n source=" + source + ",\n readTimes=" + readTimes + ",\n body=" + body
+ "]";
}
}
測試
public static ArticleItem getNewsItem(int currentPage) throws CommonException {
// 依據后綴的數字,拼接新聞 url
String urlStr = ARTICLE_BASE_URL + currentPage + ".html";
String htmlStr = HttpTool.doGet(urlStr);
Document doc = Jsoup.parse(htmlStr);
Element articleEle = doc.getElementById("article");
// 標題
Element titleEle = articleEle.getElementById("article_title");
String titleStr = titleEle.text();
// article_detail包含了 2016-01-15 來源: 瀏覽次數:177
Element detailEle = articleEle.getElementById("article_detail");
Elements details = detailEle.getElementsByTag("span");
// 公布時間
String dateStr = details.get(0).text();
// 新聞來源
String sourceStr = details.get(1).text();
// 訪問這個新聞頁面。瀏覽次數會+1,次數是 JS 渲染的
String jsStr = HttpTool.doGet(COUNT_BASE_URL + currentPage);
int readTimes = Integer.parseInt(jsStr.replaceAll("\\D+", ""));
// 或者使用以下這個正則方法
// String readTimesStr = jsStr.replaceAll("[^0-9]", "");
Element contentEle = articleEle.getElementById("article_content");
// 新聞主體內容
String contentStr = contentEle.toString();
// 假設用 text()方法,新聞主體內容的 html 標簽會丟失
// 為了在 Android 上用 WebView 顯示 html。用toString()
// String contentStr = contentEle.text();
Elements images = contentEle.getElementsByTag("img");
String[] imageUrls = new String[images.size()];
for (int i = 0; i < imageUrls.length; i++) {
imageUrls[i] = images.get(i).attr("src");
}
return new ArticleItem(currentPage, imageUrls, titleStr, dateStr, sourceStr, readTimes, contentStr);
}
public static void main(String[] args) throws CommonException {
System.out.println(getNewsItem(7928));
}
輸出信息
ArticleItem [index=7928,
imageUrls=[/uploads/image/20160114/20160114225911_34428.png],
title=電院2014級開展“讓誠信之花開遍冬日校園”教育活動,
publishDate=2016-01-14,
source=來源: 電影新聞網,
readTimes=200,
body=
西電新聞網訊?(通訊員 丁彤 王朱丹...)
展望
本文解說了怎樣實現Jsoup 網絡爬蟲。假設文章對您有幫助,感謝捐贈。
近期用 Material Design 重構了自己的新聞 App,新聞數據是利用 Jsoup 實現的。
第1版爬蟲是在手機端實現的(我承認這設計非常不好,既費流量又添加client負擔),后來在新浪云上實現了一個簡單的 JSP 。過濾了原網頁的圖片、一級欄目等,僅僅返回新聞標題、閱讀次數、新聞內容等等。
后期的打算是把爬蟲這步移到新浪云上,返回格式化的 JSON 數據給client使用。
可能的話,圖片使用七牛CDN(Content Delivery Network 內容分發網絡)。在云上利用 Mysql 數據庫緩存新聞信息。
參考文章
總結
以上是生活随笔為你收集整理的java爬取app_Java实现爬虫给App提供数据(Jsoup 网络爬虫)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL数据库实战(含建表数据和查询案例)
- 下一篇: java美元兑换,(Java实现) 美元