国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

GitHub爬蟲項(xiàng)目詳解

這篇具有很好參考價值的文章主要介紹了GitHub爬蟲項(xiàng)目詳解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

前言

閑來無事瀏覽GitHub的時候,看到一個倉庫,里邊列舉了Java的優(yōu)秀開源項(xiàng)目列表,包括說明、倉庫地址等,還是很具有學(xué)習(xí)意義的。但是大家也知道,國內(nèi)訪問GitHub的時候,經(jīng)常存在訪問超時的問題,于是就有了這篇文章,每日自動把這些數(shù)據(jù)爬取下來,隨時看到熱點(diǎn)排行。
倉庫地址:https://github.com/akullpp/awesome-java
倉庫頁面截圖:github 爬蟲,java,github,爬蟲,spring,java,后端

分析

根據(jù)以往爬蟲經(jīng)驗(yàn),先確定好思路,再開始開發(fā)代碼效率會更高。那么,第一步,找一下我們的數(shù)據(jù)來源。
具體步驟:先開啟F12,刷新網(wǎng)頁,根據(jù)關(guān)鍵詞搜索,看數(shù)據(jù)來源是哪個接口(此處以列表里的Maven為例,其他也可以)
github 爬蟲,java,github,爬蟲,spring,java,后端
可以看到,項(xiàng)目列表都是來源于這個.md文檔的1250行,可以看到,這是一個標(biāo)準(zhǔn)的JSON數(shù)據(jù),我們把這行數(shù)據(jù)復(fù)制出來進(jìn)行分析(由于數(shù)據(jù)太長,不做展示),繼續(xù)搜索后發(fā)現(xiàn),我們需要的項(xiàng)目列表和說明,都在其中richText字段里,如下:
github 爬蟲,java,github,爬蟲,spring,java,后端
而這個富文本數(shù)據(jù)都是Unicode編碼,為了方便查看結(jié)構(gòu),我們將其轉(zhuǎn)為中文,可以用如下的正則匹配,批量轉(zhuǎn)換

        richData = richData.replaceAll("/\\\\u([0-9a-f]{3,4})/i", "&#x\\1;");

轉(zhuǎn)換完之后繼續(xù)看這個富文本數(shù)據(jù)

github 爬蟲,java,github,爬蟲,spring,java,后端
我們需要的東西對應(yīng)的是一個一個的<li>標(biāo)簽和<a>標(biāo)簽,找到數(shù)據(jù)源之后就可以正式開始開發(fā)了。

項(xiàng)目開發(fā)

1、準(zhǔn)備工作

  • 開發(fā)框架選擇SpringBoot,持久層框架使用MyBatis。除必要的基礎(chǔ)依賴以外,還需要引入以下依賴:
    jsoup:對網(wǎng)頁結(jié)構(gòu)分析,解析數(shù)據(jù)
    okhttp:HTTP客戶端,訪問頁面使用。
    fastjson:解析JSON數(shù)據(jù)
  • 關(guān)系型數(shù)據(jù)庫選擇Mysql,非關(guān)系型數(shù)據(jù)庫選擇Redis
  • 編輯配置文件
    github 爬蟲,java,github,爬蟲,spring,java,后端

2、項(xiàng)目列表解析代碼開發(fā)

根據(jù)前期分析的思路,首先使用okhttp客戶端,訪問https://github.com/akullpp/awesome-java/blob/master/README.md頁面,獲取到響應(yīng)正文。

    public String getPage(String url) {
        try {
            // 1.創(chuàng)建okhttp客戶端對象
            OkHttpClient okHttpClient = new OkHttpClient();
            // 2.創(chuàng)建request對象 (用Request的靜態(tài)類創(chuàng)建)
            Request request = new Request.Builder().url(url).build();
            // 3.創(chuàng)建一個Call對象,負(fù)責(zé)進(jìn)行一次網(wǎng)絡(luò)訪問操作
            Call call = okHttpClient.newCall(request);
            // 4.發(fā)送請求到服務(wù)器,獲取到response對象
            Response response = call.execute();
            // 5.判斷響應(yīng)是否成功
            if (!response.isSuccessful()) {
                System.out.println("請求失?。?);
                return null;
            }
            return response.body().string();
        }catch (Exception e){
            log.error("請求頁面出錯:{}",e.getMessage());
            return null;
        }

    }

獲取到正文后如圖所示:
github 爬蟲,java,github,爬蟲,spring,java,后端

接著我們使用Jsoup對網(wǎng)頁結(jié)構(gòu)進(jìn)行解析,因?yàn)樾枰臄?shù)據(jù)處于<Script>標(biāo)簽,因此我們只提取這個標(biāo)簽數(shù)據(jù)即可,代碼為:

Document document = Jsoup.parse(html);
        // 2.使用 getElementsByTag,拿到所有的標(biāo)簽    elements相當(dāng)于集合類。每個element對應(yīng)一個標(biāo)簽
Elements elements = document.getElementsByTag("script");

提取之后效果如圖:
github 爬蟲,java,github,爬蟲,spring,java,后端
需要的數(shù)據(jù)在列表最后一位,取到之后因其是HTML語法,我們需要將其處理轉(zhuǎn)為標(biāo)準(zhǔn)JSON,然后根據(jù)第一步分析的結(jié)果,根據(jù)key提取richText所在的值,并將Unicode轉(zhuǎn)為中文。

String li = elements.get(elements.size()-1).toString()
                .replace("<script type=\"application/json\" data-target=\"react-app.embeddedData\">","")
                .replace("</script>","");
JSONObject pageRes = JSONObject.parseObject(li);
 String richData = pageRes.getJSONObject("payload").getJSONObject("blob").getString("richText");
richData = richData.replaceAll("/\\\\u([0-9a-f]{3,4})/i", "&#x\\1;");

處理結(jié)果為:
github 爬蟲,java,github,爬蟲,spring,java,后端
轉(zhuǎn)換完的字符串還是標(biāo)準(zhǔn)的HTML語法,繼續(xù)用Jsoup解析結(jié)構(gòu),獲取到所有的<li>標(biāo)簽和<a>標(biāo)簽

github 爬蟲,java,github,爬蟲,spring,java,后端
將需要的數(shù)據(jù)提取出來,再根據(jù)提取出來的數(shù)據(jù)繼續(xù)爬取項(xiàng)目詳情頁,格式為:https://github.com/作者名/倉庫名(因代碼基本一致,此處不再贅述),獲取項(xiàng)目對應(yīng)的StartCount、forkCount、IssuesCount,轉(zhuǎn)換為數(shù)據(jù)庫實(shí)體對象并存儲即可。

3、定時任務(wù)

編寫定時任務(wù)代碼,每天三點(diǎn)執(zhí)行爬取任務(wù),因?yàn)榭赡艽嬖谶B接超時,因此增加五十次失敗重試。執(zhí)行結(jié)束后不管成功失敗,微信推送執(zhí)行結(jié)果

 private static String PageUrl = "https://github.com/akullpp/awesome-java/blob/master/README.md";


    //[秒] [分] [小時] [日] [月] [周]
    @Scheduled(cron = "0 0 3 * * ?")
    public void crawlerTaskFunction() throws InterruptedException {
        // 1.獲取入口頁面
        int count = 1;
        String html = crawlerService.getPage(PageUrl);
        if(html == null){
            //如果失敗,重試五十次,間隔五秒
            for (int i = 0; i < 50; i++) {
                Thread.sleep(5000L);
                count++;
                log.error("抓取頁面失敗,正在第 {} 次重新嘗試",i+1);
                html = crawlerService.getPage(PageUrl);
                if(html != null){
                    break;
                }
            }
            if(html == null){
                log.error("抓取頁面失敗,正在發(fā)送失敗消息!");
                JSONObject re = new JSONObject();
                re.put("本次重試次數(shù):", 50);
                re.put("時間:", MyUtils.nowTime());
                //微信推送執(zhí)行結(jié)果消息
                System.out.println(MyUtils.sendMsgNoUrl(re,MsgToken,"今日任務(wù)執(zhí)行失敗,請手動調(diào)用接口重新爬取!"));
                return;
            }
        }
        // 2.解析入口頁面,獲取項(xiàng)目列表
        List<ProjectDTO> projects = crawlerService.parseProjectList(html);
        //發(fā)送成功消息
        log.info("抓取頁面完成,開始解析!");
        JSONObject re = new JSONObject();
        re.put("時間:", MyUtils.nowTime());
        re.put("本次重試次數(shù):", count);
        re.put("本次項(xiàng)目總數(shù):", projects.size());
        //微信推送執(zhí)行結(jié)果消息
        System.out.println(MyUtils.sendMsgNoUrl(re,MsgToken,"任務(wù)執(zhí)行成功,請去查看效果!"));
        
        if (CollectionUtils.isEmpty(projects)) {
            return;
        }
        // 3.遍歷項(xiàng)目列表,利用線程池實(shí)現(xiàn)多線程
        // executorService提交任務(wù):1)submit 有返回結(jié)果  2)execute 無返回結(jié)果
        // 此處使用submit是為了得知是否全部遍歷結(jié)束,方便進(jìn)行存到數(shù)據(jù)庫操作
        ExecutorService executorService = Executors.newFixedThreadPool(10);  //固定大小10的線程池

        List<Future<?>> taskResults = new ArrayList<>();
//        for (int i = 0; i < 10; i++) {
            for (int i = 0; i < projects.size(); i++) {
            ProjectDTO project = projects.get(i);
            Future<?> taskResult = executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("crawling " + project.getName() + ".....");
                        String repoName = getRepoName(project.getUrl());
                        String jsonString = crawlerService.getRepo(repoName);
                        // 解析項(xiàng)目數(shù)據(jù)
                        parseRepoInfo(jsonString, project);
                        System.out.println("crawling " + project.getName() + "done !");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
            taskResults.add(taskResult);
        }

        // 等待所有任務(wù)執(zhí)行結(jié)束,再進(jìn)行下一步
        for (Future<?> taskResult : taskResults) {
            try {
                // 調(diào)用get會阻塞,直到該任務(wù)執(zhí)行完畢,才會返回
                if (taskResult != null) taskResult.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        //代碼到這里,說明所有任務(wù)都執(zhí)行結(jié)束,結(jié)束線程池
        executorService.shutdown();
        // 4.保存到數(shù)據(jù)庫
        crawlerService.batchSave(projects);
    }

github 爬蟲,java,github,爬蟲,spring,java,后端

4、前端調(diào)用接口開發(fā)

對前端開放兩個接口,一個為數(shù)據(jù)庫數(shù)據(jù)的日期列表接口,一個根據(jù)日期查詢當(dāng)日數(shù)據(jù)接口,同時對參數(shù)進(jìn)行非空驗(yàn)證

    @GetMapping("/list")
    public JSONObject verifySign(@RequestParam("time") String time) {
        JSONObject resp = new JSONObject();
        if(StringUtils.isEmpty(time) || time.equals("null")){
            resp.put("code",400);
            resp.put("data",null);
            resp.put("msg","time 參數(shù)錯誤!");
            return resp;
        }
        resp.put("code",200);
        resp.put("msg","請求成功");
        resp.put("data",crawlerService.getListByTime(time));
        return resp;
    }

    @GetMapping("/timeList")
    public JSONObject timeList() {
        JSONObject resp = new JSONObject();
        resp.put("code",200);
        resp.put("msg","請求成功");
        resp.put("data",crawlerService.timeList());
        return resp;
    }

在根據(jù)日期查詢當(dāng)日數(shù)據(jù)的接口中,因其每日的數(shù)據(jù)都是固定的,因此添加redis緩存,提高性能

        String redisKey = "crawler_"+time;
        boolean containsKey = redisUtils.containThisKey(redisKey);
        if(containsKey){
            String value = redisUtils.get(redisKey);
            return JSONObject.parseArray(value,ProjectDTO.class);
        }
        List<ProjectDTO> list = crawlerMapper.getListByTime(time);
        redisUtils.set(redisKey,JSONObject.toJSONString(list));
        return list;

其中redisUtils為自己寫的Redis工具類,具體代碼如下:

package com.simon.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;



@Component
public class RedisUtils {

    @Autowired
    public StringRedisTemplate redisTemplate;

    public String get(String key){
        if(StringUtils.isEmpty(key)){
            return null;
        }
        return redisTemplate.opsForValue().get(key);
    }

    public boolean set(String key,String value){
        if(StringUtils.isEmpty(key) || StringUtils.isEmpty(value)){
            return false;
        }
        redisTemplate.opsForValue().set(key,value);
        return true;
    }

    public boolean setTimeOut(String key,String value,Long timeOut){
        if(StringUtils.isEmpty(key) || StringUtils.isEmpty(value)){
            return false;
        }
        redisTemplate.opsForValue().set(key,value,timeOut, TimeUnit.SECONDS);
        return true;
    }

    public boolean delete(String key){
        if(StringUtils.isEmpty(key) ){
            return false;
        }
        Boolean isDelete = redisTemplate.delete(key);
        return isDelete != null ? isDelete : false;
    }

    public boolean containThisKey(String key){
        if(StringUtils.isEmpty(key) ){
            return false;
        }
       Boolean hasKey = redisTemplate.hasKey(key);
        return hasKey != null && hasKey;
    }

}

因作者對前端不太熟練,只是實(shí)現(xiàn)了一些簡單的數(shù)據(jù)處理邏輯,前端效果展示:github 爬蟲,java,github,爬蟲,spring,java,后端文章來源地址http://www.zghlxwxcb.cn/news/detail-734018.html

到了這里,關(guān)于GitHub爬蟲項(xiàng)目詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Github標(biāo)星98k,企業(yè)級Spring Boot項(xiàng)目開發(fā)實(shí)戰(zhàn)筆記,太強(qiáng)了

    Github標(biāo)星98k,企業(yè)級Spring Boot項(xiàng)目開發(fā)實(shí)戰(zhàn)筆記,太強(qiáng)了

    準(zhǔn)備又快到了明年金三銀四招聘高峰期的時間,雖然這兩年因?yàn)橐咔橐约敖?jīng)濟(jì)環(huán)境不太好,互聯(lián)網(wǎng)行業(yè)的各大廠都在裁員,但是今年下半年Java行情在慢慢的復(fù)蘇,在慢慢的變好。 隨著上半年病態(tài)卷的常態(tài)在慢慢的退去,互聯(lián)網(wǎng)公司在經(jīng)過了一輪的裁員篩選篩選調(diào)整后,下半

    2024年02月05日
    瀏覽(40)
  • Github點(diǎn)贊接近 100k 的Spring Boot學(xué)習(xí)教程+實(shí)戰(zhàn)項(xiàng)目推薦

    Github點(diǎn)贊接近 100k 的Spring Boot學(xué)習(xí)教程+實(shí)戰(zhàn)項(xiàng)目推薦

    很明顯的一個現(xiàn)象,除了一些老項(xiàng)目,現(xiàn)在 Java 后端項(xiàng)目基本都是基于 Spring Boot 進(jìn)行開發(fā),畢竟它這么好用以及天然微服務(wù)友好。不夸張的說, Spring Boot 是 Java 后端領(lǐng)域最最最重要的技術(shù)之一,熟練掌握它對于 Java 程序員至關(guān)重要。 這篇文章我會推薦一些優(yōu)質(zhì)的? Spring Bo

    2024年02月03日
    瀏覽(27)
  • github上有哪些不錯的Java項(xiàng)目?

    github上有哪些不錯的Java項(xiàng)目?

    前言 找了一些沙雕的有趣的項(xiàng)目(后面也有正經(jīng)的),希望能對你的學(xué)習(xí)提供些許樂趣~ 1.吃豆人 一款經(jīng)典的游戲開發(fā)案例,包括地圖繪制、玩家控制、NPC根據(jù)玩家坐標(biāo)實(shí)時自動尋徑、吃豆積分系統(tǒng)、能量豆功能、多關(guān)卡(共12關(guān))、特殊物品記分功能的實(shí)現(xiàn),基于Javascript開發(fā)

    2024年02月08日
    瀏覽(16)
  • 精心整理了優(yōu)秀的GitHub開源項(xiàng)目,包含前端、后端、AI人工智能、游戲、黑客工具、網(wǎng)絡(luò)工具、AI醫(yī)療等等,空閑的時候方便看看提高自己的視野

    精心整理了優(yōu)秀的GitHub開源項(xiàng)目,包含前端、后端、AI人工智能、游戲、黑客工具、網(wǎng)絡(luò)工具、AI醫(yī)療等等,空閑的時候方便看看提高自己的視野

    精心整理了優(yōu)秀的GitHub開源項(xiàng)目,包含前端、后端、AI人工智能、游戲、黑客工具、網(wǎng)絡(luò)工具、AI醫(yī)療等等,空閑的時候方便看看提高自己的視野。 剛開源就變成新星的 igl,不僅獲得了 2k+ star,也能提高你開發(fā)游戲的效率,擺平一切和圖形有關(guān)的問題。如果這個沒有那么驚艷

    2024年02月10日
    瀏覽(102)
  • Github上最熱門的十大Java開源項(xiàng)目,springboot面試

    Github上最熱門的十大Java開源項(xiàng)目,springboot面試

    https://github.com/zhangdaiscott/jeecg-boot Star 7861 一款基于代碼生成器的Java快速開發(fā)平臺,開源界“小普元”超越傳統(tǒng)商業(yè)企業(yè)級開發(fā)平臺!采用前后端分離架構(gòu):SpringBoot 2.x,Ant DesignVue,Mybatis-plus,Shiro,JWT。強(qiáng)大的代碼生成器讓前后端代碼一鍵生成,無需寫任何代碼!號稱可以幫

    2024年04月17日
    瀏覽(27)
  • Git的使用--如何將本地項(xiàng)目上傳到Github(三種簡單、方便的方法)(二)(詳解)

    Git的使用--如何將本地項(xiàng)目上傳到Github(三種簡單、方便的方法)(二)(詳解)

    一、第一種方法: 1.首先你需要一個github賬號,所以還沒有的話先去注冊吧! https://github.com/ 我們使用git需要先安裝git工具,這里給出下載地址,下載后一路(傻瓜式安裝)直接安裝即可: https://git-for-windows.github.io/ 2.登陸后,進(jìn)入Github首頁,點(diǎn)擊New repository新建一個項(xiàng)目 ?

    2024年02月12日
    瀏覽(28)
  • 逛了五年GitHub,終于整理出七大java開源技術(shù)項(xiàng)目文檔,趕緊收藏

    逛了五年GitHub,終于整理出七大java開源技術(shù)項(xiàng)目文檔,趕緊收藏

    前言 大家都知道 Github 是一個程序員福地,這里有各種厲害的開源框架、軟件或者教程。這些東西對于我們學(xué)習(xí)和進(jìn)步有著莫大的進(jìn)步,所以將 Github 上非常棒的七大Java開源項(xiàng)目技術(shù)文檔整理下來供大家學(xué)習(xí)! 深入理解Spring Cloud與微服務(wù)構(gòu)建 由淺入深,全面講解Spring Cloud基

    2024年03月08日
    瀏覽(20)
  • 我把Github上最牛b的Java教程和實(shí)戰(zhàn)項(xiàng)目整合成了一個PDF文檔

    我把Github上最牛b的Java教程和實(shí)戰(zhàn)項(xiàng)目整合成了一個PDF文檔

    寫在前面 大家都知道 Github 是一個程序員福地,這里有各種厲害的開源框架、軟件或者教程。這些東西對于我們學(xué)習(xí)和進(jìn)步有著莫大的進(jìn)步,所以我有了這個將 Github 上非常棒的 Java 開源項(xiàng)目整理下來的想法。覺得不錯的話,歡迎小伙伴們?nèi)tar一波。 很多小伙伴都不知道學(xué)習(xí)

    2024年02月04日
    瀏覽(23)
  • GitHub上13個高贊Java項(xiàng)目推薦,會一個就能跟面試官談笑風(fēng)生

    GitHub上13個高贊Java項(xiàng)目推薦,會一個就能跟面試官談笑風(fēng)生

    我見過不少程序員面試的時候剛開始談的好好的,結(jié)果面試官一問到寫過哪些項(xiàng)目,瞬間就啞火了。 應(yīng)屆生還好,面試官還會更注重你的基礎(chǔ)方面,如果是一直CRUD的老碼農(nóng)跳槽被問到項(xiàng)目時沒有拿得出手的干貨,簡直分分鐘被pass掉,所以今天這篇文章給大家整理了GitHub上

    2024年02月16日
    瀏覽(36)
  • Netty是一個由JBOSS提供的開源Java框架,目前已經(jīng)成為Github上的獨(dú)立項(xiàng)目

    Netty是一個由JBOSS提供的開源Java框架,目前已經(jīng)成為Github上的獨(dú)立項(xiàng)目

    Netty是一個由JBOSS提供的開源Java框架,目前已經(jīng)成為Github上的獨(dú)立項(xiàng)目。它提供了一個異步、事件驅(qū)動的網(wǎng)絡(luò)應(yīng)用程序框架和工具,用于快速開發(fā)高性能、高可靠性的網(wǎng)絡(luò)服務(wù)器和客戶端程序。 Netty是一個基于NIO的客戶、服務(wù)器端的編程框架,使用Netty可以確??焖俸秃唵蔚亻_

    2024年01月16日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包