最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

教你如何用Java簡(jiǎn)單爬取WebMagic

 更新時(shí)間:2021年06月30日 10:55:58   作者:小新沒(méi)有蠟筆的  
今天給大家?guī)?lái)的是關(guān)于Java爬蟲的相關(guān)知識(shí),文章圍繞著Java如何爬取WebMagic展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下

一、Java爬蟲——WebMagic

 1.1 WebMagic總體架構(gòu)圖

WebMagic總體架構(gòu)圖

1.2 WebMagic核心組件

1.2.1 Downloader

該組件負(fù)責(zé)從互聯(lián)網(wǎng)上下載頁(yè)面。WebMagic默認(rèn)使用Apache HttpClient作為下載工具。

1.2.2 PageProcessor

該組件負(fù)責(zé)解析頁(yè)面,根據(jù)我們的業(yè)務(wù)進(jìn)行抽取信息。WebMagic使用Jsoup作為HTML解析工具,并基于其開發(fā)了解析Xpath的工具Xsoup。

1.2.3 Scheduler

該組件負(fù)責(zé)管理待抓取的URL,以及去重的工作。WebMagic默認(rèn)使用JDK內(nèi)存隊(duì)列管理URL,通過(guò)集合進(jìn)行去重。

支持使用Redis進(jìn)行分布式管理。

1.2.4 Pipeline

該組件負(fù)責(zé)抽取結(jié)果的處理,包括計(jì)算、持久化到文件、數(shù)據(jù)庫(kù)等等。

1.2.5 數(shù)據(jù)流轉(zhuǎn)對(duì)象

 1. Request

Request是對(duì)URL地址的一層封裝,一個(gè)Request對(duì)應(yīng)一個(gè)URL地址。

它是PageProcessor與Downloader交互的載體,也是PageProcessor控制Downloader唯一方式。

除了URL本身外,它還包含一個(gè)Key-Value結(jié)構(gòu)的字段extra。你可以在extra中保存一些特殊的屬性,然后在其他地方讀取,以完成不同的功能。例如附加上一個(gè)頁(yè)面的一些信息等。

2. Page

Page代表了從Downloader下載到的一個(gè)頁(yè)面——可能是HTML,也可能是JSON或者其他文本格式的內(nèi)容。

Page是WebMagic抽取過(guò)程的核心對(duì)象,它提供一些方法可供抽取、結(jié)果保存等。

3. ResultItems

ResultItems相當(dāng)于一個(gè)Map,底層使用了LinkedHashMap進(jìn)行存儲(chǔ),它保存PageProcessor處理的結(jié)果,供Pipeline使用。它的API與Map很類似,值得注意的是它有一個(gè)字段skip,若設(shè)置為true,則不被Pipeline處理,跳過(guò)。

1.2.6 Spider——WebMagic核心引擎

Spider是WebMagic內(nèi)部流程的核心。Downloader、PageProcessor、Scheduler、Pipeline都是Spider的一個(gè)屬性,這些屬性是可以自由設(shè)置的,通過(guò)設(shè)置這個(gè)屬性可以實(shí)現(xiàn)不同的功能。Spider也是WebMagic操作的入口,它封裝了爬蟲的創(chuàng)建、啟動(dòng)、停止、多線程等功能。

1.3 練習(xí)Demo

需求是爬取一篇廈門限行文章,文章來(lái)源:http://xm.bendibao.com/traffic/2018116/54311.shtm,具體需求如下:

1.刪除文章中超鏈接

2.文章中的圖片下載至本地

3.刪除文章末尾:溫馨提示...

1.3.1 定制Downloader

為預(yù)防頁(yè)面失效,定制一個(gè)Downloader,當(dāng)鏈接地址不存在時(shí),打印日志。

public class MyHttpClientDownloader extends HttpClientDownloader {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 提示頁(yè)面獲取狀態(tài)碼
     */
    @Override
    protected Page handleResponse(Request request, String charset, HttpResponse httpResponse, Task task) throws IOException {
        Page page = super.handleResponse(request, charset, httpResponse, task);
        if(httpResponse.getStatusLine().getStatusCode()!= ConstantsField.PAGE_STATUS_200){
            page.setDownloadSuccess(false);
            logger.warn("頁(yè)面獲取狀態(tài)碼錯(cuò)誤,正在重試!");
        }
        return page;
    }
}

1.3.2 定制PageProcessor

該頁(yè)面處理器實(shí)現(xiàn)了對(duì)頁(yè)面的抽取,符合上面的需求。

將處理完成的數(shù)據(jù)添加進(jìn)入:Page對(duì)象,并設(shè)置鍵分別為:imgListcontent。

public class XmPageProcessor implements PageProcessor {

    /**
     * 抓取網(wǎng)站的相關(guān)配置,包括編碼、抓取間隔、重試次數(shù)等
     */
    private Site site = Site.me().setCycleRetryTimes(3).setSleepTime(1000);

    /**
     * 核心:編寫抽取邏輯
     */
    @Override
    public void process(Page page) {
        // 抽取頁(yè)面文本數(shù)據(jù)
        Selectable selectable = page.getHtml().css(ConstantsField.PAGE_CSS_CONTENT);

        //處理圖片
        List<String> pImgList = selectable.xpath(ConstantsField.XPATH_IMG).all();
        List<String> imgUrl = new ArrayList<>();
        if(pImgList.size()>0){
            Pattern compile = Pattern.compile(ConstantsField.REX_IMG_SRC);
            for (String img : pImgList) {
                Matcher matcher = compile.matcher(img);
                while (matcher.find()){
                    imgUrl.add(matcher.group(1));
                }
            }
        }
        if(imgUrl.size()>0){
            page.putField("imgList",imgUrl);
        }else {
            page.putField("imgList",null);
        }

        //對(duì)內(nèi)容轉(zhuǎn)換為StringBuilder
        String content = selectable.toString();
        StringBuilder stringBuilder = new StringBuilder(content);

        //處理超鏈接
        StringBuilder newString = dealLink(stringBuilder);

        //處理末尾
        int startIndex = newString.indexOf(ConstantsField.END_CONTENT);
        if(startIndex>0) {
            newString.delete(startIndex, stringBuilder.length());
            newString.append("</div>");
        }

        page.putField("content",newString.toString());
    }

    @Override
    public Site getSite() {
        return site;
    }

    /**
     * 處理超鏈接
     */
    private static StringBuilder dealLink(StringBuilder stringBuilder){
        StringBuilder newString = new StringBuilder(stringBuilder);
        int aIndex = newString.indexOf("<a href");
        while (aIndex != -1){
            int pStart = newString.lastIndexOf("<p>", aIndex);
            int pEnd = (newString.indexOf("</p>", aIndex) + 4);
            newString.delete(pStart,pEnd);
            aIndex = newString.indexOf("<a href");
        }
        return newString;
    }
}

1.3.3 定制Pipeline

Pipeline是處理結(jié)果的地方,這里我們對(duì)結(jié)果進(jìn)行存儲(chǔ)文件的處理。網(wǎng)站文本存儲(chǔ)為:stm格式,圖片文本存儲(chǔ)為其網(wǎng)站源文件的格式。

public class MyFilePipeline extends FilePersistentBase implements Pipeline {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private StringBuilder filepath;

    private MyFilePipeline() {
        this.setPath(ConstantsField.DEFAULT_SAVE_LOCATION);
    }

    public MyFilePipeline(String path) {
        if(path!=null){
            this.setPath(path);
        }else {
            new MyFilePipeline();
        }
        filepath = new StringBuilder().append(this.path).
                append(PATH_SEPERATOR).append(ConstantsField.FILE_NAME)
                .append(ConstantsField.FILE_POSTFIX);

    }

    @Override
    public void process(ResultItems resultItems, Task task) {
        //文件內(nèi)容覆蓋
        try(PrintWriter printWriter = new PrintWriter(new FileWriter(getFile(filepath.toString()),false))) {
            printWriter.write(resultItems.get("content").toString());
            logger.info("文件生成成功,存儲(chǔ)地址為:"+filepath);

            //下載圖片
            List<String> imgList = resultItems.get("imgList");
            if(imgList!=null&&imgList.size()>0){
                boolean dowload = DownloadImgUtils.download(imgList, this.getPath());
                if(dowload){
                    logger.info("圖片下載成功,存儲(chǔ)地址為:" + this.getPath());
                }
            }

        } catch (IOException e) {
            logger.error("輸出文件出錯(cuò):" + e.getCause().toString());
        }
    }
}

這里實(shí)現(xiàn)了網(wǎng)頁(yè)存儲(chǔ)為stm格式與圖片存儲(chǔ),圖片存儲(chǔ)使用了如下工具類DownloadImgUtils

public class DownloadImgUtils {

    /**
     * 下載圖片
     * @param imgList 圖片列表
     * @param savePath 保存地址
     * @return 成功返回true
     */
    public static boolean download(List<String> imgList, String savePath) throws IOException {
        URL url;
        DataInputStream dataInputStream = null;
        FileOutputStream fileOutputStream = null;
        File file;
        try {
            for (String imgUrl : imgList) {
                //截取文件名
                Pattern pat=Pattern.compile(ConstantsField.REX_IMG_SUFFIX);
                Matcher mc=pat.matcher(imgUrl);
                while(mc.find()) {
                    String fileName= mc.group();
                    file = new File(savePath + fileName);
                    file.createNewFile();
                    fileOutputStream = new FileOutputStream(savePath + fileName);
                }

                url = new URL(imgUrl);
                dataInputStream = new DataInputStream(url.openStream());

                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int length;
                while ((length = dataInputStream.read(buffer))>0){
                    outputStream.write(buffer,0,length);
                }
                fileOutputStream.write(outputStream.toByteArray());
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            dataInputStream.close();
            fileOutputStream.close();
        }

        return false;
    }
}

1.3.4 啟動(dòng)類

public class WebMagicApplication {

    private String url;
    private String saveUrl;

    /**
     * 無(wú)參構(gòu)造使用默認(rèn)值
     */
    public WebMagicApplication() {
        this.url = ConstantsField.XM_BDB_URL;
        this.saveUrl = ConstantsField.DEFAULT_SAVE_LOCATION;
    }

    public WebMagicApplication(String url, String saveUrl) {
        this.url = url;
        this.saveUrl = saveUrl;
    }

    public void start(){
        Spider.create(new XmPageProcessor()).addUrl(this.url).addPipeline(new MyFilePipeline(this.saveUrl)).setDownloader(new MyHttpClientDownloader()).run();
    }

    public static void main(String[] args) {
        WebMagicApplication webMagicApplication = new WebMagicApplication("http://xm.bendibao.com/traffic/2018116/5431122.shtm","C:\\");
        webMagicApplication.start();
    }
}

這里啟動(dòng)類可以使用帶參構(gòu)造或無(wú)參構(gòu)造,無(wú)參構(gòu)造默認(rèn)使用URL與存儲(chǔ)地址為ConstantsField類中的XM_BDB_URL屬性和DEFAULT_SAVE_LOCATION

練習(xí)中的ConstantsField具體如下:

public final class ConstantsField {
    /**
     * 爬取的CSS的文本
     */
    public static final String PAGE_CSS_CONTENT = "div.content";

    /**
     * 結(jié)束文本起始位置
     */
    public static final String END_CONTENT = "<div id=\"adInArticle\"></div>";

    /**
     * 廈門本地寶URL
     */
    public static final String XM_BDB_URL = "http://xm.bendibao.com/traffic/2018116/54311.shtm";

    /**
     * 默認(rèn)文件保存地址
     */
    public static final String DEFAULT_SAVE_LOCATION = "C:\\";

    /**
     * 文件名
     */
    public static final String FILE_NAME = "2021廈門限行最新消息(持續(xù)更新)";

    /**
     * 文件后綴
     */
    public static final String FILE_POSTFIX = ".stm";

    /**
     * 頁(yè)面訪問(wèn)狀態(tài)碼
     */
    public static final int PAGE_STATUS_200 = 200;

    /**
     * 正則匹配src
     */
    public static final String REX_IMG_SRC = "src\\s*=\\s*\"?(.*?)(\"|>|\\s+)";

    /**
     * 正則匹配文件后綴
     */
    public static final String REX_IMG_SUFFIX = "[\\w]+[\\.](jpeg|jpg|png)";

    /**
     * 處理圖片XPATH
     */
    public static final String XPATH_IMG = "http://*[@id=\"bo\"]/*/img";
}

1.3.5 源碼地址

練習(xí)Demo源碼地址: https://gitee.com/Xiaoxinnolabi/web-magic/settings
WebMagic中文文檔: http://webmagic.io/docs/zh/
WebMagic源碼地址: https://github.com/code4craft/webmagic/

到此這篇關(guān)于教你如何用Java簡(jiǎn)單爬取WebMagic的文章就介紹到這了,更多相關(guān)Java爬取WebMagic內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM 堆和棧的區(qū)別

    JVM 堆和棧的區(qū)別

    本文主要介紹了JVM堆和棧的區(qū)別。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • Java中i++的一些問(wèn)題總結(jié)

    Java中i++的一些問(wèn)題總結(jié)

    這篇文章主要給大家介紹了關(guān)于Java中i++的一些問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • MyBatis Generator介紹及使用方法

    MyBatis Generator介紹及使用方法

    MyBatis Generator 是一款針對(duì) MyBatis 或 iBATIS 設(shè)計(jì)的代碼生成器,由 MyBatis 官方提供,這篇文章主要介紹了MyBatis Generator介紹及使用方法,需要的朋友可以參考下
    2023-06-06
  • spring MVC中傳遞對(duì)象參數(shù)示例詳解

    spring MVC中傳遞對(duì)象參數(shù)示例詳解

    這篇文章主要給大家介紹了在spring MVC中傳遞對(duì)象參數(shù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看吧。
    2017-06-06
  • springboot使用ThreadPoolTaskExecutor多線程批量插入百萬(wàn)級(jí)數(shù)據(jù)的實(shí)現(xiàn)方法

    springboot使用ThreadPoolTaskExecutor多線程批量插入百萬(wàn)級(jí)數(shù)據(jù)的實(shí)現(xiàn)方法

    這篇文章主要介紹了springboot利用ThreadPoolTaskExecutor多線程批量插入百萬(wàn)級(jí)數(shù)據(jù),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-02-02
  • Spring Boot之FilterRegistrationBean-自定義Filter詳解

    Spring Boot之FilterRegistrationBean-自定義Filter詳解

    這篇文章主要介紹了Spring Boot之FilterRegistrationBean-自定義Filter詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java.lang.annotation包詳細(xì)介紹

    java.lang.annotation包詳細(xì)介紹

    java.lang.annotation?包是 Java 標(biāo)準(zhǔn)庫(kù)中的一個(gè)核心包,專門用于定義和支持 Java 注解(Annotation),這篇文章主要介紹了java.lang.annotation包介紹,需要的朋友可以參考下
    2024-07-07
  • Netty解決 TCP 粘包拆包的方法

    Netty解決 TCP 粘包拆包的方法

    處理粘包的唯一方法就是制定應(yīng)用層的數(shù)據(jù)通訊協(xié)議,通過(guò)協(xié)議來(lái)規(guī)范現(xiàn)有接收的數(shù)據(jù)是否滿足消息數(shù)據(jù)的需要,本文給大家介紹Netty解決 TCP 粘包拆包的方法,需要的朋友一起看看吧
    2021-07-07
  • Android?Studio中創(chuàng)建java工程的完整步驟

    Android?Studio中創(chuàng)建java工程的完整步驟

    Android?Studio創(chuàng)建java工程是非常麻煩的,因?yàn)锳ndroid?Studio沒(méi)有提供直接創(chuàng)建java工程的方法,下面這篇文章主要給大家介紹了關(guān)于Android?Studio中創(chuàng)建java工程的完整步驟,需要的朋友可以參考下
    2024-01-01
  • 詳解java中面向?qū)ο笤O(shè)計(jì)模式類與類的關(guān)系

    詳解java中面向?qū)ο笤O(shè)計(jì)模式類與類的關(guān)系

    這篇文章主要介紹了java面向?qū)ο笤O(shè)計(jì)模式中類與類之間的關(guān)系,下面小編和大家一起來(lái)學(xué)習(xí)一下吧
    2019-05-05

最新評(píng)論

仙游县| 玛沁县| 周口市| 通辽市| 桐乡市| 陈巴尔虎旗| 方山县| 改则县| 道孚县| 呼伦贝尔市| 乌拉特后旗| 成都市| 水富县| 绥化市| 汕头市| 贵阳市| 麻江县| 延边| 玉龙| 昆明市| 丁青县| 兴文县| 平果县| 通州市| 太仓市| 奎屯市| 贞丰县| 翼城县| 韶关市| 巨鹿县| 凭祥市| 通辽市| 易门县| 吉安市| 龙陵县| 灵寿县| 蒙山县| 麦盖提县| 隆安县| 华池县| 滦南县|