Java爬虫实践
Java_spider_實(shí)戰(zhàn)
源碼及資料點(diǎn)這里!!!
爬蟲的執(zhí)行流程: 1) 確定首頁url 2) 發(fā)送請(qǐng)求, 獲取數(shù)據(jù) 3) 解析數(shù)據(jù) 4) 保存數(shù)據(jù)
爬蟲的三大核心模塊:
1發(fā)送請(qǐng)求獲取數(shù)據(jù) : httpClient
* 1)獲取httpClient對(duì)象:
* 2) 創(chuàng)建請(qǐng)求方式的對(duì)象
* 3) 設(shè)置請(qǐng)求參數(shù), 請(qǐng)求頭
* 4) 發(fā)送請(qǐng)求, 獲取響應(yīng)對(duì)象
* 5) 獲取數(shù)據(jù):
* 6) 釋放資源
2解析數(shù)據(jù) : Jsoup
* 常見方法 :
* static parse(String html) ; 根據(jù)html字符串轉(zhuǎn)換成document對(duì)象
* select(“選擇器”) ; 根據(jù)選擇器獲取對(duì)應(yīng)的元素
* text()/html() ; 獲取指定元素的內(nèi)容體中數(shù)據(jù)
* attr(String name) ; 根據(jù)屬性的名稱獲取屬性的值
3保存數(shù)據(jù) :
0. 梳理整個(gè)爬蟲的流程
0.1 163娛樂爬蟲的流程
0.2 騰訊娛樂爬蟲的流程
1.1 準(zhǔn)備工作 :
- 1)創(chuàng)建項(xiàng)目 : gossip-spider-news (maven jar工程)
[外鏈圖片轉(zhuǎn)存失敗(img-zvL8ETKt-1563093902027)(assets/1557621834394.png)]
- 2)添加pom依賴:
- 3)加入工具類:
[外鏈圖片轉(zhuǎn)存失敗(img-wkct0RYO-1563093902031)(assets/1557623438827.png)]
1.2 確定首頁url
[外鏈圖片轉(zhuǎn)存失敗(img-5PjuFk4c-1563093902031)(assets/1557624105019.png)]
結(jié)論: 新聞數(shù)據(jù), 不是通過同步請(qǐng)求, 獲取到, 而是通過異步請(qǐng)求, 悄悄獲取的
如何獲取異步請(qǐng)求的url :
首頁的url : https://ent.163.com/special/000380VU/newsdata_index.js?callback=data_callback 分頁的url : https://ent.163.com/special/000380VU/newsdata_index_02.js?callback=data_callback1.3 發(fā)送請(qǐng)求, 獲取數(shù)據(jù)
public class News163Spider {public static void main(String[] args ) throws Exception{//1. 確定首頁url:String indexUrl = "https://ent.163.com/special/000380VU/newsdata_index.js?callback=data_callback";//2. 發(fā)送請(qǐng)求, 獲取數(shù)據(jù)// 此處獲取的json的數(shù)據(jù), 并不是一個(gè)非標(biāo)準(zhǔn)的jsonString jsonStr = HttpClientUtils.doGet(indexUrl);jsonStr = splitJson(jsonStr);System.out.println(jsonStr);//3. 解析數(shù)據(jù)(json) :/*** 1) json格式一共有幾種: 二種 一般復(fù)合格式認(rèn)為是前二種的擴(kuò)展格式* 一種: [value1,value2,value3 ....] ---數(shù)組格式* 二種: {key1:value1,key2:value2}* 三種: {key1:[value1,value2]}* 四種: [{},{}]** 2) 如何區(qū)分一個(gè)json的格式是一個(gè)對(duì)象呢, 還是一個(gè)數(shù)組呢?* 查看最外層的符號(hào)即可, 如果是[] 那就是數(shù)組, 如果{}那就是對(duì)象* [{key,[{key,value}]}] : 轉(zhuǎn)回對(duì)應(yīng)的類型* List<Map<String,List<Map<String,String>>>>** 3) json格式本質(zhì)上就是一個(gè)字符串: 在js 和 java中表示的類型有所不同的:* js java* [] 數(shù)組 數(shù)組/List/set* {} 對(duì)象 javaBean對(duì)象/Map** js中如何定義一個(gè)對(duì)象: var persion = {username:'張三'}; persion.username*/}// 將非標(biāo)準(zhǔn)的json轉(zhuǎn)換為標(biāo)準(zhǔn)的json字符串private static String splitJson(String jsonStr) {int firstIndex = jsonStr.indexOf("(");int lastIndex = jsonStr.lastIndexOf(")");return jsonStr.substring(firstIndex+1,lastIndex);} }1.4 解析數(shù)據(jù)(json)
- 解析新聞的列表頁:
- 創(chuàng)建news類(pojo):
- 解析新聞的詳情頁的內(nèi)容:
1.5 保存數(shù)據(jù)
- 準(zhǔn)備工作: 創(chuàng)建對(duì)應(yīng)的庫 和 對(duì)應(yīng)的表
- 1)創(chuàng)建一個(gè)NewsDao類:
-
2)在news163Spider類中, 執(zhí)行保存即可
- 在成員位置創(chuàng)建dao對(duì)象
[外鏈圖片轉(zhuǎn)存失敗(img-i3Eqox0a-1563093902031)(assets/1557633998099.png)]
- 在parseJson方法中添加一下內(nèi)容
[外鏈圖片轉(zhuǎn)存失敗(img-Y7Cn3KOr-1563093902031)(assets/1557634046293.png)]
如果將創(chuàng)建dao的代碼放置到了方法中, 后續(xù)可能會(huì)出現(xiàn)這個(gè)異常信息:
[外鏈圖片轉(zhuǎn)存失敗(img-iH44cMAk-1563093902034)(assets/1557633247460.png)]
錯(cuò)誤異常原因: 太多的連接,超過mysql的最大連接數(shù)了由于創(chuàng)建了太多的連接池了, 每一次創(chuàng)建一個(gè)連接池就會(huì)初始化一些連接創(chuàng)建了多次Dao對(duì)象, 每創(chuàng)建一次dao, 執(zhí)行一下dao中構(gòu)造方法, 構(gòu)造方法中創(chuàng)建連接池對(duì)象1.6 分頁獲取數(shù)據(jù)
// 執(zhí)行分頁的方法public static void page(String indexUrl) throws Exception{String page = "02";while(true) {//1. 發(fā)送請(qǐng)求獲取數(shù)據(jù)// 此處獲取的json的數(shù)據(jù), 并不是一個(gè)非標(biāo)準(zhǔn)的jsonString jsonStr = HttpClientUtils.doGet(indexUrl);if(jsonStr==null){System.out.println("數(shù)據(jù)獲取完成");break;}jsonStr = splitJson(jsonStr);//2. 解析數(shù)據(jù), 3 保存數(shù)據(jù)parseJson(jsonStr);//4. 獲取下一頁的urlindexUrl = "https://ent.163.com/special/000380VU/newsdata_index_" + page + ".js?callback=data_callback";//5. page ++int pageNum = Integer.parseInt(page);pageNum++;if(pageNum <10){page = "0"+pageNum;}else{page = pageNum+"";}}}1.7 去重操作
[外鏈圖片轉(zhuǎn)存失敗(img-VBK124xP-1563093902034)(assets/1557634429779.png)]
[外鏈圖片轉(zhuǎn)存失敗(img-rS2aGC8J-1563093902035)(assets/1557635122858.png)]
清空數(shù)據(jù)的時(shí)候, 一定要注意: 除了清空mysql中數(shù)據(jù)外, 還的清空redis中的數(shù)據(jù)
[外鏈圖片轉(zhuǎn)存失敗(img-4JZLuLjH-1563093902035)(assets/1557635191819.png)]
1.8 獲取整個(gè)網(wǎng)易新聞中所有的娛樂信息
明星欄目首頁url: https://ent.163.com/special/000380VU/newsdata_star.js?callback=data_callback 明星欄目分頁url: https://ent.163.com/special/000380VU/newsdata_star_02.js?callback=data_callback電影欄目首頁url: https://ent.163.com/special/000380VU/newsdata_movie.js?callback=data_callback 電影欄目分頁url : https://ent.163.com/special/000380VU/newsdata_movie_02.js?callback=data_callback電視劇欄目首頁url: https://ent.163.com/special/000380VU/newsdata_tv.js?callback=data_callback 電視劇欄目分頁url: https://ent.163.com/special/000380VU/newsdata_tv_02.js?callback=data_callback綜藝欄目首頁url: https://ent.163.com/special/000380VU/newsdata_show.js?callback=data_callback 綜藝欄目分頁url: https://ent.163.com/special/000380VU/newsdata_show_02.js?callback=data_callback音樂欄目首頁url: https://ent.163.com/special/000380VU/newsdata_music.js?callback=data_callback 音樂欄目分頁url: https://ent.163.com/special/000380VU/newsdata_music_02.js?callback=data_callback- 1)在main方法中, 將所有的首頁的url放置到集合中
[外鏈圖片轉(zhuǎn)存失敗(img-wZqPj6he-1563093902036)(assets/1557644149947.png)]
- 2)在分頁的方法中, 執(zhí)行分頁的時(shí)候, 也需要根據(jù)不同的地址進(jìn)行分頁
[外鏈圖片轉(zhuǎn)存失敗(img-yuHIfNSS-1563093902036)(assets/1557644179735.png)]
1.9 將整體的爬蟲:
package com.itheima.spider.news163Spider;import com.google.gson.Gson; import com.itheima.spider.dao.NewsDao; import com.itheima.spider.pojo.News; import com.itheima.spider.utils.HttpClientUtils; import com.itheima.spider.utils.IdWorker; import com.itheima.spider.utils.JedisUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; import redis.clients.jedis.Jedis;import java.util.ArrayList; import java.util.List; import java.util.Map;public class News163Spider {private static IdWorker idWorker = new IdWorker(0,1);private static NewsDao newsDao = new NewsDao();public static void main(String[] args) throws Exception {//2. 發(fā)送請(qǐng)求, 獲取數(shù)據(jù)// 此處獲取的json的數(shù)據(jù), 并不是一個(gè)非標(biāo)準(zhǔn)的json//String jsonStr = HttpClientUtils.doGet(indexUrl);//jsonStr = splitJson(jsonStr);// System.out.println(jsonStr);//3. 解析數(shù)據(jù)(json) :/*** 1) json格式一共有幾種: 二種 一般見復(fù)合格式認(rèn)為是前二種的擴(kuò)展格式* 一種: [value1,value2,value3 ....] ---數(shù)組格式* 二種: {key1:value1,key2:value2}* 三種: {key1:[value1,value2]}* 四種: [{},{}]** 2) 如何區(qū)分一個(gè)json的格式是一個(gè)對(duì)象呢, 還是一個(gè)數(shù)組呢?* 查看最外層的符號(hào)即可, 如果是[] 那就是數(shù)組, 如果{}那就是對(duì)象* [{key,[{key,value}]}] : 轉(zhuǎn)回對(duì)應(yīng)的類型* List<Map<String,List<Map<String,String>>>>** 3) json格式本質(zhì)上就是一個(gè)字符串: 在js 和 java中表示的類型有所不同的:* js java* [] 數(shù)組 數(shù)組/List/set* {} 對(duì)象 javaBean對(duì)象/Map** js中如何定義一個(gè)對(duì)象: var persion = {username:'張三'}; persion.username*///parseJson(jsonStr);//1. 確定首頁url://String indexUrl = "https://ent.163.com/special/000380VU/newsdata_index.js?callback=data_callback";List<String> urlList = new ArrayList<String>();urlList.add("https://ent.163.com/special/000380VU/newsdata_index.js?callback=data_callback");urlList.add("https://ent.163.com/special/000380VU/newsdata_star.js?callback=data_callback");urlList.add("https://ent.163.com/special/000380VU/newsdata_movie.js?callback=data_callback");urlList.add("https://ent.163.com/special/000380VU/newsdata_tv.js?callback=data_callback");urlList.add("https://ent.163.com/special/000380VU/newsdata_show.js?callback=data_callback");urlList.add("https://ent.163.com/special/000380VU/newsdata_music.js?callback=data_callback");//5. 分頁獲取數(shù)據(jù)while(!urlList.isEmpty()) {String indexUrl = urlList.remove(0);System.out.println("獲取了下一個(gè)欄目的數(shù)據(jù)#######################################");page(indexUrl);}}// 執(zhí)行分頁的方法public static void page(String indexUrl) throws Exception{String page = "02";while(true) {//1. 發(fā)送請(qǐng)求獲取數(shù)據(jù)// 此處獲取的json的數(shù)據(jù), 并不是一個(gè)非標(biāo)準(zhǔn)的jsonString jsonStr = HttpClientUtils.doGet(indexUrl);if(jsonStr==null){System.out.println("數(shù)據(jù)獲取完成");break;}jsonStr = splitJson(jsonStr);//2. 解析數(shù)據(jù), 3 保存數(shù)據(jù)parseJson(jsonStr);//4. 獲取下一頁的urlif(indexUrl.contains("newsdata_index")){indexUrl = "https://ent.163.com/special/000380VU/newsdata_index_" + page + ".js?callback=data_callback";}if(indexUrl.contains("newsdata_star")){indexUrl = "https://ent.163.com/special/000380VU/newsdata_star_" + page + ".js?callback=data_callback";}if(indexUrl.contains("newsdata_movie")){indexUrl = "https://ent.163.com/special/000380VU/newsdata_movie_" + page + ".js?callback=data_callback";}if(indexUrl.contains("newsdata_tv")){indexUrl = "https://ent.163.com/special/000380VU/newsdata_tv_" + page + ".js?callback=data_callback";}if(indexUrl.contains("newsdata_show")){indexUrl = "https://ent.163.com/special/000380VU/newsdata_show_" + page + ".js?callback=data_callback";}if(indexUrl.contains("newsdata_music")){indexUrl = "https://ent.163.com/special/000380VU/newsdata_music_" + page + ".js?callback=data_callback";}//5. page ++int pageNum = Integer.parseInt(page);pageNum++;if(pageNum <10){page = "0"+pageNum;}else{page = pageNum+"";}}}// 解析json的方法private static void parseJson(String jsonStr) throws Exception{//3.1 將json字符串轉(zhuǎn)換成 指定的對(duì)象Gson gson = new Gson();List<Map<String, Object>> newsList = gson.fromJson(jsonStr, List.class);// 3.2 遍歷整個(gè)新聞的結(jié)合, 獲取每一個(gè)新聞的對(duì)象for (Map<String, Object> newsObj : newsList) {// 新聞 : 標(biāo)題, 時(shí)間,來源 , 內(nèi)容 , 新聞編輯 , 新聞的url//3.2.1 獲取新聞的url , 需要根據(jù)url, 獲取詳情頁中新聞數(shù)據(jù)String docUrl = (String) newsObj.get("docurl");// 過濾掉一些不是新聞數(shù)據(jù)的urlif(docUrl.contains("photoview")){continue;}if(docUrl.contains("v.163.com")){continue;}if(docUrl.contains("c.m.163.com")){continue;}if(docUrl.contains("dy.163.com")){continue;}// ###################去重處理代碼######################Jedis jedis = JedisUtils.getJedis();Boolean flag = jedis.sismember("bigData:spider:163spider:docurl", docUrl);jedis.close();//一定一定一定不要忘記關(guān)閉, 否則用著用著沒了, 導(dǎo)致程序卡死不動(dòng)if(flag){// 代表存在, 表示已經(jīng)爬取過了continue;}// ###################去重處理代碼######################//System.out.println(docUrl);//3.3 獲取新聞詳情頁的數(shù)據(jù)News news = parseNewsItem(docUrl);// 4. 保存數(shù)據(jù) ---- 一會(huì) 會(huì)有問題的//System.out.println(news);newsDao.saveNews(news);// ###################去重處理代碼######################// 將保存到數(shù)據(jù)庫中的docurl添加到redis的set集合中jedis = JedisUtils.getJedis();jedis.sadd("bigData:spider:163spider:docurl",news.getDocurl());jedis.close();// ###################去重處理代碼######################}}// 根據(jù)url 解析新聞詳情頁:private static News parseNewsItem(String docUrl) throws Exception {System.out.println(docUrl);// 3.3.1 發(fā)送請(qǐng)求, 獲取新聞詳情頁數(shù)據(jù)String html = HttpClientUtils.doGet(docUrl);//3.3.2 解析新聞詳情頁:Document document = Jsoup.parse(html);//3.3.2.1 : 解析新聞的標(biāo)題:News news = new News();Elements h1El = document.select("#epContentLeft h1");String title = h1El.text();news.setTitle(title);//3.3.2.2 : 解析新聞的時(shí)間:Elements timeAndSourceEl = document.select(".post_time_source");String timeAndSource = timeAndSourceEl.text();String[] split = timeAndSource.split(" 來源: ");// 請(qǐng)各位一定一定一定要復(fù)制, 否則會(huì)切割失敗news.setTime(split[0]);//3.3.2.3 : 解析新聞的來源:news.setSource(split[1]);//3.3.2.4 : 解析新聞的正文:Elements ps = document.select("#endText p");String content = ps.text();news.setContent(content);//3.3.2.5 : 解析新聞的編輯:Elements spanEl = document.select(".ep-editor");// 責(zé)任編輯:陳少杰_b6952String editor = spanEl.text();// 一定要接收返回值, 否則白寫了editor = editor.substring(editor.indexOf(":")+1,editor.lastIndexOf("_"));news.setEditor(editor);//3.3.2.6 : 解析新聞的url:news.setDocurl(docUrl);//3.3.2.7: idlong id = idWorker.nextId();news.setId(id+"");return news;}// 將非標(biāo)準(zhǔn)的json轉(zhuǎn)換為標(biāo)準(zhǔn)的json字符串private static String splitJson(String jsonStr) {int firstIndex = jsonStr.indexOf("(");int lastIndex = jsonStr.lastIndexOf(")");return jsonStr.substring(firstIndex + 1, lastIndex);} }2. 爬取騰訊新聞娛樂數(shù)據(jù)
2.1 確定首頁url
熱點(diǎn)url : https://pacaio.match.qq.com/irs/rcd?cid=137&token=d0f13d594edfc180f5bf6b845456f3ea&ext=ent&num=60非熱點(diǎn)的首頁url : https://pacaio.match.qq.com/irs/rcd?cid=146&token=49cbb2154853ef1a74ff4e53723372ce&ext=ent&page=0非熱點(diǎn)的分頁url :https://pacaio.match.qq.com/irs/rcd?cid=146&token=49cbb2154853ef1a74ff4e53723372ce&ext=ent&page=02.2 發(fā)送請(qǐng)求, 獲取數(shù)據(jù)
// 騰訊娛樂新聞的爬蟲 public class TencentNewsSpider {public static void main(String[] args) throws Exception{//1. 確定首頁urlString topNewsUrl = "https://pacaio.match.qq.com/irs/rcd?cid=137&token=d0f13d594edfc180f5bf6b845456f3ea&ext=ent&num=60";String noTopNewsUrl = "https://pacaio.match.qq.com/irs/rcd?cid=146&token=49cbb2154853ef1a74ff4e53723372ce&ext=ent&page=0";//2. 發(fā)送請(qǐng)求, 獲取數(shù)據(jù)String topNewsJsonStr = HttpClientUtils.doGet(topNewsUrl);String noTopNewsJsonStr = HttpClientUtils.doGet(noTopNewsUrl);System.out.println(topNewsJsonStr);System.out.println(noTopNewsJsonStr);//3. 解析數(shù)據(jù) :parseJson(topNewsJsonStr);parseJson(noTopNewsJsonStr);}// 解析新聞數(shù)據(jù)private static void parseJson(String newsJsonStr) {} }2.3 解析新聞數(shù)據(jù)(json)
// 解析新聞數(shù)據(jù)private static List<News> parseJson(String newsJsonStr) {//3.1 將字符串json數(shù)據(jù)轉(zhuǎn)換為指定的類型: mapGson gson = new Gson();Map<String,Object> map = gson.fromJson(newsJsonStr, Map.class);//3.2 獲取data中數(shù)據(jù) : 列表頁中數(shù)據(jù)List<Map<String,Object>> newsList = (List<Map<String, Object>>) map.get("data");//3.3 遍歷這個(gè)列表, 獲取每一個(gè)新聞的數(shù)據(jù)List<News> tencentNewList = new ArrayList<News>();for (Map<String, Object> newsMap : newsList) {//3.3.1 封裝news對(duì)象News news = new News();news.setTitle((String)newsMap.get("title"));news.setTime((String)newsMap.get("update_time"));news.setSource((String)newsMap.get("source"));news.setContent((String)newsMap.get("intro"));news.setEditor((String)newsMap.get("source"));news.setDocurl((String)newsMap.get("vurl"));news.setId(idWorker.nextId() +"");tencentNewList.add(news);}return tencentNewList;}2.4 保存數(shù)據(jù)
- 1)創(chuàng)建一個(gè)saveNews的方法:
- 2)在main方法中, 添加保存數(shù)據(jù)的操作
[外鏈圖片轉(zhuǎn)存失敗(img-QqZpQhCN-1563093902039)(assets/1557647802086.png)]
2.5 分頁獲取數(shù)據(jù)
// 執(zhí)行分頁的方法public static void page(String topNewsUrl,String noTopNewsUrl) throws Exception{//1. 熱點(diǎn)新聞數(shù)據(jù)的獲取: 只有一頁數(shù)據(jù)//1.1 發(fā)送請(qǐng)求, 獲取數(shù)據(jù)String topNewsJsonStr = HttpClientUtils.doGet(topNewsUrl);//1.2 解析數(shù)據(jù)List<News> topNewsList = parseJson(topNewsJsonStr);//1.3 保存數(shù)據(jù)saveNews(topNewsList);//2. 處理非熱點(diǎn)數(shù)據(jù)int page = 1;while(true){//2.1 發(fā)送請(qǐng)求, 獲取數(shù)據(jù)String noTopNewsJsonStr = HttpClientUtils.doGet(noTopNewsUrl);//2.2 解析數(shù)據(jù)List<News> noTopNewsList = parseJson(noTopNewsJsonStr);if(noTopNewsList == null){break;}//2.3 保存數(shù)據(jù)saveNews(noTopNewsList);//2.4 獲取下一頁urlnoTopNewsUrl = "https://pacaio.match.qq.com/irs/rcd?cid=146&token=49cbb2154853ef1a74ff4e53723372ce&ext=ent&page="+page;//2.5 自增 +1page++;System.out.println(page);}}- 過濾一些視頻的鏈接: 在parseJson的方法中過濾的
[外鏈圖片轉(zhuǎn)存失敗(img-2w8NM4Ey-1563093902040)(assets/1557648803513.png)]
2.6 去重處理
- 1)在獲取docurl后, 需要判斷, 這個(gè)url是否已經(jīng)爬取過: parseJson方法中
- 不需要在執(zhí)行封裝的代碼了
[外鏈圖片轉(zhuǎn)存失敗(img-VMMqN2G9-1563093902040)(assets/1557649544185.png)]
- 2)在保存數(shù)據(jù)之前, 再次進(jìn)行判斷, 在保存之后, 將爬取過的url存儲(chǔ)到redis中
[外鏈圖片轉(zhuǎn)存失敗(img-D2GGal1g-1563093902040)(assets/1557649615117.png)]
2.7 整體騰訊爬蟲:
package com.itheima.spider.tencent;import com.google.gson.Gson; import com.itheima.spider.dao.NewsDao; import com.itheima.spider.pojo.News; import com.itheima.spider.utils.HttpClientUtils; import com.itheima.spider.utils.IdWorker; import com.itheima.spider.utils.JedisUtils; import redis.clients.jedis.Jedis;import java.util.ArrayList; import java.util.List; import java.util.Map;// 騰訊娛樂新聞的爬蟲 public class TencentNewsSpider {private static IdWorker idWorker = new IdWorker(0,2);private static NewsDao newsDao = new NewsDao();public static void main(String[] args) throws Exception{//1. 確定首頁urlString topNewsUrl = "https://pacaio.match.qq.com/irs/rcd?cid=137&token=d0f13d594edfc180f5bf6b845456f3ea&ext=ent&num=60";String noTopNewsUrl = "https://pacaio.match.qq.com/irs/rcd?cid=146&token=49cbb2154853ef1a74ff4e53723372ce&ext=ent&page=0";//2. 執(zhí)行分頁:page(topNewsUrl,noTopNewsUrl);}// 執(zhí)行分頁的方法public static void page(String topNewsUrl,String noTopNewsUrl) throws Exception{//1. 熱點(diǎn)新聞數(shù)據(jù)的獲取: 只有一頁數(shù)據(jù)//1.1 發(fā)送請(qǐng)求, 獲取數(shù)據(jù)String topNewsJsonStr = HttpClientUtils.doGet(topNewsUrl);//1.2 解析數(shù)據(jù)List<News> topNewsList = parseJson(topNewsJsonStr);//1.3 保存數(shù)據(jù)saveNews(topNewsList);//2. 處理非熱點(diǎn)數(shù)據(jù)int page = 1;while(true){//2.1 發(fā)送請(qǐng)求, 獲取數(shù)據(jù)String noTopNewsJsonStr = HttpClientUtils.doGet(noTopNewsUrl);//2.2 解析數(shù)據(jù)List<News> noTopNewsList = parseJson(noTopNewsJsonStr);if(noTopNewsList == null){break;}//2.3 保存數(shù)據(jù)saveNews(noTopNewsList);//2.4 獲取下一頁urlnoTopNewsUrl = "https://pacaio.match.qq.com/irs/rcd?cid=146&token=49cbb2154853ef1a74ff4e53723372ce&ext=ent&page="+page;//2.5 自增 +1page++;System.out.println(page);}}// 保存數(shù)據(jù)的操作 : 騰訊返回?cái)?shù)據(jù)的時(shí)候, 就會(huì)有重復(fù)的數(shù)據(jù)public static void saveNews(List<News> newsList) {Jedis jedis = JedisUtils.getJedis();for (News news : newsList) {// ###################去重處理########################Boolean flag = jedis.sismember("bigData:spider:tencentSpider:docurl", news.getDocurl());if(flag){// 如果為true, 表示已經(jīng)存在, 已經(jīng)爬取過了continue;}// ###################去重處理########################newsDao.saveNews(news);// 保存數(shù)據(jù)之后, 將url保存到redis中//###################去重處理########################jedis.sadd("bigData:spider:tencentSpider:docurl",news.getDocurl());//###################去重處理########################}jedis.close();}// 解析新聞數(shù)據(jù)private static List<News> parseJson(String newsJsonStr) {//3.1 將字符串json數(shù)據(jù)轉(zhuǎn)換為指定的類型: mapGson gson = new Gson();Map<String,Object> map = gson.fromJson(newsJsonStr, Map.class);//獲取一下, 本次獲取了多少條數(shù)據(jù)Double datanum = (Double) map.get("datanum");if(datanum.intValue() == 0){return null;}//3.2 獲取data中數(shù)據(jù) : 列表頁中數(shù)據(jù)List<Map<String,Object>> newsList = (List<Map<String, Object>>) map.get("data");//3.3 遍歷這個(gè)列表, 獲取每一個(gè)新聞的數(shù)據(jù)List<News> tencentNewList = new ArrayList<News>();for (Map<String, Object> newsMap : newsList) {String docurl = (String) newsMap.get("vurl");if(docurl.contains("video")){continue;}//######################去重處理############################33Jedis jedis = JedisUtils.getJedis();Boolean flag = jedis.sismember("bigData:spider:tencentSpider:docurl", docurl);jedis.close();if(flag){// 如果為true, 表示已經(jīng)存在, 已經(jīng)爬取過了continue;}//######################去重處理############################33//3.3.1 封裝news對(duì)象News news = new News();news.setTitle((String)newsMap.get("title"));news.setTime((String)newsMap.get("update_time"));news.setSource((String)newsMap.get("source"));news.setContent((String)newsMap.get("intro"));news.setEditor((String)newsMap.get("source"));news.setDocurl(docurl);news.setId(idWorker.nextId() +"");tencentNewList.add(news);System.out.println(docurl);}return tencentNewList;} }3. 梳理整個(gè)爬蟲的流程
3.1 163娛樂爬蟲的流程
[外鏈圖片轉(zhuǎn)存失敗(img-w1tjv4By-1563093902041)(assets/1557652264866.png)]
3.2 騰訊娛樂爬蟲的流程
[外鏈圖片轉(zhuǎn)存失敗(img-je6CPrCj-1563093902041)(assets/1557652742929.png)]
jedis.close();if(flag){// 如果為true, 表示已經(jīng)存在, 已經(jīng)爬取過了continue;}//######################去重處理############################33//3.3.1 封裝news對(duì)象News news = new News();news.setTitle((String)newsMap.get("title"));news.setTime((String)newsMap.get("update_time"));news.setSource((String)newsMap.get("source"));news.setContent((String)newsMap.get("intro"));news.setEditor((String)newsMap.get("source"));news.setDocurl(docurl);news.setId(idWorker.nextId() +"");tencentNewList.add(news);System.out.println(docurl);}return tencentNewList;} }總結(jié)
- 上一篇: wxFormBuilder摸索--小白上
- 下一篇: java 定时器 倒计时_Java:多种