網絡爬蟲框架Webmagic

1 談談網絡爬蟲css

 1.1 什麼是網絡爬蟲前端

在大數據時代,信息的採集是一項重要的工做,而互聯網中的數據是海量的,若是單純靠人力進行信息採集,不只低效繁瑣,蒐集的成本也會提升。如何自動高效地獲取互聯網中咱們感興趣的信息併爲咱們所用是一個重要的問題,而爬蟲技術就是爲了解決這些問題而生的。java

網絡爬蟲(Web crawler)也叫作網絡機器人,能夠代替人們自動地在互聯網中進行數據信息的採集與整理。它是一種按照必定的規則,自動地抓取萬維網信息的程序或者腳本,能夠自動採集全部其可以訪問到的頁面內容,以獲取或更新這些網站的內容和檢索方式。mysql

從功能上來說,爬蟲通常分爲數據採集,處理,儲存三個部分。爬蟲從一個或若干初始網頁的URL開始,得到初始網頁上的URL,在抓取網頁的過程當中,不斷從當前頁面上抽取新的URL放入隊列,直到知足系統的必定中止條件。web

 

1.2 網絡爬蟲能夠作什麼redis

咱們初步認識了網絡爬蟲,網絡爬蟲具體能夠作什麼呢?spring

 a.能夠實現搜索引擎sql

 b.大數據時代,可讓咱們獲取更多的數據源。數據庫

 c.快速填充測試和運營數據apache

 d.爲人工智能提供訓練數據集

 

1.3 網絡爬蟲經常使用的技術(Java)

1.3.1 底層實現 HttpClient + Jsoup

 HttpClient 是 Apache Jakarta Common 下的子項目,用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,而且它支持 HTTP 協議最新的版本和建議。 HttpClient 已經應用在不少的項目中,好比 Apache Jakarta 上很著名的另外兩個開源項目 Cactus 和 HTMLUnit 都使用了 HttpClient。更多信息請關注http://hc.apache.org/

  jsoup 是一款Java 的HTML解析器,可直接解析某個URL地址、HTML文本內容。它提供了一套很是省力的API,可經過DOM,CSS以及相似於jQuery的操做方法來取出和操做數據。

 

1.3.2 開源框架 Webmagic

 webmagic是一個開源的Java爬蟲框架,目標是簡化爬蟲的開發流程,讓開發者專一於邏輯功能的開發。webmagic的核心很是簡單,可是覆蓋爬蟲的整個流程,也是很好的學習爬蟲開發的材料。

 

 

​ webmagic的主要特點:

 a.徹底模塊化的設計,強大的可擴展性。

 b.核心簡單可是涵蓋爬蟲的所有流程,靈活而強大,也是學習爬蟲入門的好材料。

 c.提供豐富的抽取頁面API。

 d.無配置,可是可經過POJO+註解形式實現一個爬蟲。

 e. 支持多線程。

 f. 支持分佈式。

 g.支持爬取js動態渲染的頁面。

 h.無框架依賴,能夠靈活的嵌入到項目中去。

 

2 爬蟲框架Webmagic

 2.1 架構解析

 WebMagic項目代碼分爲核心和擴展兩部分。核心部分(webmagic-core)是一個精簡

 的、模塊化的爬蟲實現,而擴展部分則包括一些便利的、實用性的功能。擴展部分(webmagic-extension)提供一些便捷的功能,例如註解模式編寫爬蟲等。同時內置了一些經常使用的組件,便於爬蟲開發。

 WebMagic的設計目標是儘可能的模塊化,並體現爬蟲的功能特色。這部分提供很是簡單、靈活的API,在基本不改變開發模式的狀況下,編寫一個爬蟲。

 WebMagic的結構分爲Downloader、PageProcessor、Scheduler、Pipeline四大組件,並由Spider將它們彼此組織起來。這四大組件對應爬蟲生命週期中的下載、處理、管

 理和持久化等功能。而Spider則將這幾個組件組織起來,讓它們能夠互相交互,流程化的執行,能夠認爲Spider是一個大的容器,它也是WebMagic邏輯的核心。

 

 

四大組件

 a.Downloader

 Downloader負責從互聯網上下載頁面,以便後續處理。WebMagic默認使用了ApacheHttpClient做爲下載工具。

 

 b.PageProcessor

 PageProcessor負責解析頁面,抽取有用信息,以及發現新的連接。WebMagic使用Jsoup做爲HTML解析工具,並基於其開發瞭解析XPath的工具Xsoup。

 在這四個組件中,PageProcessor對於每一個站點每一個頁面都不同,是須要使用者定製的部分。

 

c.Scheduler

 Scheduler負責管理待抓取的URL,以及一些去重的工做。WebMagic默認提供了JDK的內存隊列來管理URL,並用集合來進行去重。也支持使用Redis進行分佈式管理。

 

d.Pipeline

 Pipeline負責抽取結果的處理,包括計算、持久化到文件、數據庫等。WebMagic默認提供了「輸出到控制檯」和「保存到文件」兩種結果處理方案。

 

 

2.2 PageProcessor

 需求:編寫爬蟲程序,爬取csdn中博客--工人智能的內容

 

2.2.1 爬取頁面所有內容

 

https://blog.csdn.net/nav/ai

 

(1)建立工程,引入依賴

 

<dependency>

<groupId>us.codecraft</groupId>

<artifactId>webmagic‐core</artifactId>

<version>0.7.3</version>

</dependency>

<dependency>

<groupId>us.codecraft</groupId>

<artifactId>webmagic‐extension</artifactId>

<version>0.7.3</version>

</dependency>

 

(2)編寫類實現網頁內容的爬取

 

import us.codecraft.webmagic.Page;

import us.codecraft.webmagic.Site;

import us.codecraft.webmagic.Spider;

import us.codecraft.webmagic.processor.PageProcessor; /**
*爬取類

*/

public class MyProcessor implements PageProcessor {



public void process(Page page) {

System.out.println(page.getHtml().toString());

}


public Site getSite() {

return Site.me().setSleepTime(100).setRetryTimes(3);

}


public static void main(String[] args) {

Spider.create( new MyProcessor() ).addUrl("https://blog.csdn.net").run();

}

}

 

​ Spider是爬蟲啓動的入口。在啓動爬蟲以前,咱們須要使用一個PageProcessor建立一個Spider對象,而後使用run()進行啓動。

 方法**                                說明**                        示例** 
create(PageProcessor)      建立Spider             Spider.create(new GithubRepoProcessor())

 

 同時Spider的其餘組件(Downloader、Scheduler、Pipeline)均可以經過set方法來進行設置。

 Page表明了從Downloader下載到的一個頁面——多是HTML,也多是JSON或者其餘文本格式的內容。Page是WebMagic抽取過程的核心對象,它提供一些方法可供抽取、結果保存等。

 Site用於定義站點自己的一些配置信息,例如編碼、HTTP頭、超時時間、重試策略等、代理等,均可以經過設置Site對象來進行配置。

 方法**                 說明**       示例**

setCharset(String)   設置編碼      site.setCharset("utf-8")

 

2.2.2 爬取指定內容(XPath)

 

​ 若是咱們想爬取網頁中部分的內容,須要指定xpath。

 XPath,即爲XML路徑語言(XMLPathLanguage),它是一種用來肯定XML文檔中某部分位置的語言。XPath 使用路徑表達式來選取 XML 文檔中的節點或者節點集。這些路徑表達式和咱們在常規的電腦文件系統中看到的表達式很是類似。 

 咱們經過指定xpath來抓取網頁的部份內容

 

System.out.println(page.getHtml().xpath("//* [@id=\"nav\"]/div/div/ul/li[5]/a").toString());

以上代碼的含義:id爲nav的節點下的div節點下的div節點下的ul下的第5個li節點下的a節點

 

看一下輸出結果

 

<a href="/nav/ai">人工智能</a>

 

2.2.3 添加目標地址

 

咱們能夠經過添加目標地址,從種子頁面爬取到更多的頁面

 

 

 

public void process(Page page) {

 

page.addTargetRequests( page.getHtml().links().all() );//將當前頁面

 

裏的全部連接都添加到目標頁面中

 

public void process(Page page) {
        page.addTargetRequests( page.getHtml().links().all() );//將當前頁面
裏的全部連接都添加到目標頁面中
        System.out.println(page.getHtml().xpath("//*
[@id=\"nav\"]/div/div/ul/li[5]/a").toString());
    }

 

運行後發現好多地址都出如今控制檯

 

2.2.4 目標地址正則匹配

 需求:只提取csdn的文章詳細頁內容,並提取標題

 

import us.codecraft.webmagic.Page;

import us.codecraft.webmagic.Site;

import us.codecraft.webmagic.Spider;

import us.codecraft.webmagic.processor.PageProcessor; /**
*爬取類

*/

public class MyProcessor implements PageProcessor {


public void process(Page page) {

//page.addTargetRequests( page.getHtml().links().all() );//將當前頁

面裏的全部連接都添加到目標頁面中

//

page.addTargetRequests(

page.getHtml().links().regex("https://blog.csdn.net/[a‐z 0‐9

‐]+/article/details/[09]{8}").all() );

System.out.println(page.getHtml().xpath("//* [@id=\"mainBox\"]/main/div[1]/div[1]/h1/text()").toString());

}


public Site getSite() {

return Site.me().setSleepTime(100).setRetryTimes(3);

}


public static void main(String[] args) {

Spider.create( new MyProcessor()

).addUrl("https://blog.csdn.net/nav/ai").run();

}

}

 

 

2.3 Pipeline

2.3.1 ConsolePipeline 控制檯輸出

 

/**
 * 爬取類
 */
public class MyProcessor implements PageProcessor {
    public void process(Page page) {
        //page.addTargetRequests( page.getHtml().links().all() );//將當前頁
面裏的全部連接都添加到目標頁面中
        //
        page.addTargetRequests(
page.getHtml().links().regex("https://blog.csdn.net/[a‐z 0‐9
‐]+/article/details/[09]{8}").all() );
        //System.out.println(page.getHtml().xpath("//*
[@id=\"mainBox\"]/main/div[1]/div[1]/h1/text()").toString());
        page.putField("title",page.getHtml().xpath("//*
[@id=\"mainBox\"]/main/div[1]/div[1]/h1/text()").toString());
    }
    public Site getSite() {
        return Site.me().setSleepTime(100).setRetryTimes(3);
    }
    public static void main(String[] args) {
        Spider.create( new MyProcessor() )
                .addUrl("https://blog.csdn.net")
                .addPipeline(new ConsolePipeline())
                .run();
    }
}

 

 

2.3.2 FilePipeline 文件保存

 

public static void main(String[] args) {
        Spider.create( new MyProcessor() )
                .addUrl("https://blog.csdn.net")
                .addPipeline(new ConsolePipeline())
                .addPipeline(new FilePipeline("e:/data"))//以文件方式保存
                .run();
    }

 

2.3.3 JsonFilePipeline

 以json方式保存

 

public static void main(String[] args) {
        Spider.create( new MyProcessor() )
                .addUrl("https://blog.csdn.net")
                .addPipeline(new ConsolePipeline())
                .addPipeline(new FilePipeline("e:/data"))
                .addPipeline(new JsonFilePipeline("e:/json"))// 以json方式保
存
                .run();
    }

 

2.3.4 定製Pipeline

 若是以上Pipeline都不能知足你的須要,你能夠定製Pipeline

(1)建立類MyPipeline實現接口Pipeline

 

import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;
public class MyPipeline implements Pipeline {
    public void process(ResultItems resultItems, Task task) {
        String title=resultItems.get("title");
        System.out.println("個人定製的 title:"+title);
    }

(2)修改main方法

public static void main(String[] args) {
        Spider.create( new MyProcessor() )
                .addUrl("https://blog.csdn.net")
                .addPipeline(new ConsolePipeline())
                .addPipeline(new FilePipeline("e:/data"))
                .addPipeline(new JsonFilePipeline("e:/json"))
                .addPipeline(new MyPipeline())//定製化輸出
                .run();
    }

 

2.4 Scheduler

咱們剛纔完成的功能,每次運行可能會爬取重複的頁面,這樣作是沒有任何意義的。Scheduler(URL管理) 最基本的功能是實現對已經爬取的URL進行標示。能夠實現URL的增量去重。

 目前scheduler主要有三種實現方式:

 1)內存隊列 QueueScheduler

 2)文件隊列 FileCacheQueueScheduler

 3) Redis隊列 RedisScheduler

 

2.4.1 內存隊列

 使用setScheduler來設置Scheduler

 

public static void main(String[] args) {
        Spider.create( new MyProcessor() )
                .addUrl("https://blog.csdn.net")
                .setScheduler(new QueueScheduler())
                .run();
    }

 

2.4.2 文件隊列

 使用文件保存抓取URL,能夠在關閉程序並下次啓動時,從以前抓取到的URL繼續抓取

(1)建立文件夾E:\scheduler

 (2)修改代碼

public static void main(String[] args) {
        Spider.create( new MyProcessor() )
                .addUrl("https://blog.csdn.net")
                //.setScheduler(new QueueScheduler())//設置內存隊列
                .setScheduler(new
FileCacheQueueScheduler("E:\\scheduler"))//設置文件隊列
                .run();
    }

運行後文件夾E:\scheduler會產生兩個文件blog.csdn.net.urls.txt和 blog.csdn.net.cursor.txt

 

2.4.3 Redis隊列

 使用Redis保存抓取隊列,可進行多臺機器同時合做抓取

 (1)運行redis服務端

 (2)修改代碼

 

public static void main(String[] args) {
        Spider.create( new MyProcessor() )
                .addUrl("https://blog.csdn.net")
                //.setScheduler(new QueueScheduler())//設置內存隊列
                //.setScheduler(new
FileCacheQueueScheduler("E:\\scheduler"))//設置文件隊列
                .setScheduler(new RedisScheduler("127.0.0.1"))//設置Redis隊
列
                .run();
    }

 

3 csdn文章爬取

 3.1 需求分析

 每日某時間段整從CSDN博客中爬取文檔,存入文章數據庫中。

 3.2 頻道設置

  資訊    https://blog.csdn.net/nav/news

人工智能  https://blog.csdn.net/nav/ai

 區塊鏈 https://blog.csdn.net/nav/blockchain

數據庫 https://blog.csdn.net/nav/db

前端 https://blog.csdn.net/nav/web

編程語言 https://blog.csdn.net/nav/lang

 

向數據庫tensquare_article的tb_channel表中添加記錄

 

 

3.3 代碼編寫

 3.3.1 模塊搭建

 (1)建立模塊tensquare_article_crawler ,引入依賴

 

<dependency>
            <groupId>us.codecraft</groupId>
            <artifactId>webmagic‐core</artifactId>
            <version>0.7.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j‐log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>us.codecraft</groupId>
            <artifactId>webmagic‐extension</artifactId>
            <version>0.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring‐boot‐starter‐data‐jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql‐connector‐java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.tensquare</groupId>
            <artifactId>tensquare_common</artifactId>
            <version>1.0‐SNAPSHOT</version>
        </dependency>

 

 

(2)建立配置文件application.yml

server:
  port: 9014
spring:
  application: 
    name: tensquare‐crawler #指定服務名
  datasource: 
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/tensquare_article?
characterEncoding=UTF8
    username: root
    password: 123456
  jpa:
    database: MySQL
    show‐sql: true
redis:
  host: 127.0.0.1

 

(3)建立啓動類

 

@SpringBootApplication
@EnableScheduling
public class CrawlerApplication {
   @Value("${redis.host}")  
private String redis_host;    
 
public static void main(String[] args) {    
SpringApplication.run(CrawlerApplication.class, args);        
}    
@Bean    
public IdWorker idWorkker(){    
return new IdWorker(11);        
}    
 
   @Bean  
public RedisScheduler redisScheduler(){    
return new RedisScheduler(redis_host);        
}    
}

 

(4)實體類及數據訪問接口

 

3.3.2 爬取類

 建立文章爬取類ArticleProcessor

package com.tensquare.crawler.processor;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;
/**
 * 文章爬取類
 */
@Component
public class ArticleProcessor implements PageProcessor {
   
    @Override
    public void process(Page page) {
       
page.addTargetRequests(page.getHtml().links().regex("https://blog.csdn.net/
[a‐z 09 ‐]+/article/details/[09]{8}").all());
        String title= page.getHtml().xpath("//*
[@id=\"mainBox\"]/main/div[1]/div[1]/h1/text()").get();
        String content= page.getHtml().xpath("//*
[@id=\"article_content\"]/div/div[1]").get();
        //獲取頁面須要的內容
        System.out.println("標題:"+title );
        System.out.println("內容:"+content );
        if(title!=null && content!=null){  //若是有標題和內容
            page.putField("title",title);
            page.putField("content",content);
        }else{
            page.setSkip(true);//跳過
        }
    }
    @Override
    public Site getSite() {
        return Site.me().setRetryTimes(3000).setSleepTime(100);
    }
}

 

 3.3.3 入庫類

 建立文章入庫類ArticleDbPipeline ,負責將爬取的數據存入數據庫

 

package com.tensquare.crawler.pipeline;
import com.tensquare.crawler.dao.ArticleDao;
import com.tensquare.crawler.pojo.Article;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;
import util.IdWorker;
import java.util.Map;
/**
 * 入庫類
 */
@Component
public class ArticleDbPipeline implements Pipeline {
    @Autowired
    private ArticleDao articleDao;
    @Autowired
    private IdWorker idWorker;
    public void setChannelId(String channelId) {
        this.channelId = channelId;
    }
    private String channelId;//頻道ID
    @Override
    public void process(ResultItems resultItems, Task task) {    
        String title = resultItems.get("title");
        String content= resultItems.get("content");
        Article article=new Article();
        article.setId(idWorker.nextId()+"");
        article.setChannelid(channelId);
        article.setTitle(title);
        article.setContent(content);
        articleDao.save(article);
    }
}

 

ReusltItems 至關於一個Map,它保存PageProcessor處理的結果,供Pipeline使用。它的API與Map很相似,值得注意的是它有一個字段 skip ,若設置爲true,則不該被Pipeline處理。

 

3.3.4 任務類

 建立任務類

 

package com.tensquare.crawler.task;
import com.tensquare.crawler.pipeline.ArticleDbPipeline;
import com.tensquare.crawler.pipeline.ArticleTxtPipeline;
import com.tensquare.crawler.processor.ArticleProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.scheduler.RedisScheduler;
/**
 * 文章任務類
 */
@Component
public class ArticleTask {
    @Autowired
    private ArticleDbPipeline articleDbPipeline;
    @Autowired
    private ArticleTxtPipeline articleTxtPipeline;
    @Autowired
    private RedisScheduler redisScheduler;
    @Autowired
    private ArticleProcessor articleProcessor;
    /**
     * 爬取ai數據
     */
    @Scheduled(cron="0 54 21 * * ?")
    public void aiTask(){
        System.out.println("爬取AI文章");
        Spider spider = Spider.create(articleProcessor);
        spider.addUrl("https://blog.csdn.net/nav/ai");
        articleTxtPipeline.setChannelId("ai");
        articleDbPipeline.setChannelId("ai");
        spider.addPipeline(articleDbPipeline);
        spider.addPipeline(articleTxtPipeline);
        spider.setScheduler(redisScheduler);
        spider.start();
 }
    /**
     * 爬取db數據
     */
    @Scheduled(cron="20 17 11 * * ?")
    public void dbTask(){
        System.out.println("爬取DB文章");
        Spider spider = Spider.create(articleProcessor);
        spider.addUrl("https://blog.csdn.net/nav/db");
        articleTxtPipeline.setChannelId("db");
        spider.addPipeline(articleTxtPipeline);
        spider.setScheduler(redisScheduler);
        spider.start();
    }
    /**
     * 爬取web數據
     */
    @Scheduled(cron="20 27 11 * * ?")
    public void webTask(){
        System.out.println("爬取WEB文章");
        Spider spider = Spider.create(articleProcessor);
        spider.addUrl("https://blog.csdn.net/nav/web");
        articleTxtPipeline.setChannelId("web");
        spider.addPipeline(articleTxtPipeline);
        spider.setScheduler(redisScheduler);
        spider.start();
    }
}

 

 

4 CSDN用戶數據爬取

 4.1 需求分析

 從csdn中爬取用戶暱稱和頭像,存到用戶表,頭像圖片存儲到本地

 4.2 代碼編寫

 4.2.1 模塊搭建

 (1)建立工程tensquare_user_crawler。pom.xml引入依賴

 

<dependency>
            <groupId>us.codecraft</groupId>
            <artifactId>webmagic‐core</artifactId>
            <version>0.7.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j‐log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>us.codecraft</groupId>
            <artifactId>webmagic‐extension</artifactId>
            <version>0.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring‐boot‐starter‐data‐jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql‐connector‐java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.tensquare</groupId>
            <artifactId>tensquare_common</artifactId>
            <version>1.0‐SNAPSHOT</version>
        </dependency>

 

(2)建立配置文件application.yml

 

server:
  port: 9015
spring:
  application: 
    name: tensquare‐user‐crawler #指定服務名
  datasource: 
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/tensquare_user?characterEncoding=UTF8
    username: root
    password: 123456
  jpa:
    database: MySQL
    show‐sql: true
redis:
  host: 127.0.0.1

 

(3)建立啓動類

 

@SpringBootApplication
@EnableScheduling
public class UserCrawlerApplication {
   @Value("${redis.host}")  
private String redis_host;    
 
public static void main(String[] args) {    
SpringApplication.run(CrawlerApplication.class, args);        
}    
@Bean    
public IdWorker idWorkker(){    
return new IdWorker(11);        
}    
 
   @Bean  
public RedisScheduler redisScheduler(){    
return new RedisScheduler(redis_host);        
}    
}

 

(4)實體類及數據訪問接口

 

4.2.2 爬取類

 

package com.tensquare.usercrawler.processor;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;
/**
 * 文章爬取類
 */
@Component
public class UserProcessor implements PageProcessor {
    @Override
    public void process(Page page) {
       
page.addTargetRequests(page.getHtml().links().regex("https://blog.csdn.net/
[a‐z 09 ‐]+/article/details/[09]{8}").all());
        String nickname= page.getHtml().xpath("//*
[@id=\"uid\"]/text()").get();
        String image= page.getHtml().xpath("//*
[@id=\"asideProfile\"]/div[1]/div[1]/a").css("img","src").toString();
        if(nickname!=null && image!=null){  //若是有暱稱和頭像
            page.putField("nickname",nickname);
            page.putField("image",image);
        }else{
            page.setSkip(true);//跳過
        }
    }
    @Override
    public Site getSite() {
        return Site.me().setRetryTimes(3000).setSleepTime(100);
    }
}

 

4.2.3 下載工具類

 將工具類拷貝至tensquare_common工程的util包下

 

package util;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
/**
 * 下載工具類
 */
public class DownloadUtil {
    public static void download(String urlStr,String filename,String
savePath) throws IOException {
        URL url new URL(urlStr);
        //打開url鏈接
        URLConnection connection = url.openConnection();
        //請求超時時間
        connection.setConnectTimeout(5000);
        //輸入流
        InputStream in = connection.getInputStream();
        //緩衝數據
        byte [] bytes = new byte[1024];
        //數據長度
        int len;
        //文件
        File file = new File(savePath);
        if(!file.exists())
            file.mkdirs();
        OutputStream out  = new
FileOutputStream(file.getPath()+"\\"+filename);
        //先讀到bytes中
        while ((len=in.read(bytes))!=‐1){
            //再從bytes中寫入文件
            out.write(bytes,0,len);
        }
        //關閉IO
        out.close();
        in.close();
    }
}

 

4.2.4 入庫類

 

 

package com.tensquare.usercrawler.pipeline;
import com.tensquare.usercrawler.dao.UserDao;
import com.tensquare.usercrawler.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;
import util.DownloadUtil;
import util.IdWorker;
import java.io.IOException;
@Component
public class UserPipeline implements Pipeline {
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private UserDao userDao;
    @Override
    public void process(ResultItems resultItems, Task task) {
        User user=new User();
        user.setId(idWorker.nextId()+"");
        user.setNickname(resultItems.get("nickname"));
        String image = resultItems.get("image");//圖片地址
        String fileName = image.substring(image.lastIndexOf("/")+1);
        user.setAvatar(fileName);
        userDao.save(user);
        //下載圖片
        try {
            DownloadUtil.download(image,fileName,"e:/userimg");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

4.2.5 任務類

 

package com.tensquare.usercrawler.task;
import com.tensquare.usercrawler.pipeline.UserPipeline;
import com.tensquare.usercrawler.processor.UserProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.scheduler.RedisScheduler;
/**
 * 用戶爬取任務類
 */
@Component
public class UserTask {
    @Autowired
    private RedisScheduler redisScheduler;
    @Autowired
    private UserPipeline userPipeline;
    @Autowired
    private UserProcessor userProcessor;
    /**
     * 爬取用戶數據
     */
    @Scheduled(cron="0 56 22 * * ?")
    public void userTask(){
        System.out.println("爬取用戶");
        Spider spider = Spider.create(userProcessor);
        spider.addUrl("https://blog.csdn.net");
        spider.addPipeline(userPipeline);
        spider.setScheduler(redisScheduler);
        spider.start();
    }
}
相關文章
相關標籤/搜索