WebMagic爬蟲框架(爬取前程無憂網站的招聘信息保存到mysql數據庫)


@


WebMagic框架包含四個組件, PageProcessorSchedulerDownloaderPipeline
這四大組件對應爬蟲生命周期中的處理、管理、下載和持久化等功能。
這四個組件都是 Spider中的屬性,爬蟲框架通過 Spider啟動和管理。
WebMagic總體架構圖
在這里插入圖片描述

一,WebMagic的四大組件

PageProcessor 負責解析頁面,抽取有用信息,以及發現新的鏈接。需要自己定義。
Scheduler 負責管理待抓取的URL,以及一些去重的工作。一般無需自己定制Scheduler。
Pipeline 負責抽取結果的處理,包括計算、持久化到文件、數據庫等。
Downloader 負責從互聯網上下載頁面,以便后續處理。一般無需自己實現。

二,用於數據流轉的對象

Request 是對URL地址的一層封裝,一個Request對應一個URL地址。
Page 代表了從Downloader下載到的一個頁面——可能是HTML,也可能是JSON或者其他文本格式的內容。
ResultItems 相當於一個Map,它保存PageProcessor處理的結果,供Pipeline使用。

三,項目開始前的熱身(解析頁面的方式)

項目maven添加了下面要求的maven坐標之后就可以寫下面的測試代碼了。
下面的測試很清楚的講解了解析頁面的方式,以及爬蟲的執行。

  • page.putField()是把爬取到的數據添加到了ResultItems中,默認在控制台打印出來。
public class JobProcessor implements PageProcessor {
    //解析頁面
    public void process(Page page) {
        //解析返回的數據page,並且把解析的結果放在resultItems中

        //css選擇器解析
        //page.putField("爬取內容",page.getHtml().css("span.service_txt").all());//all()是返回所有數據,get()是返回第一條數據

        //XPath解析
        //page.putField("xpath方法解析結果",page.getHtml().xpath("//div[@id=J_cate]/ul/li/a").all());

        //正則表達式解析(篩選內容帶“裝”字的所有信息)
        page.putField("正則",page.getHtml().css("div#J_cate ul li a").regex(".*裝.*").all());

        //獲取鏈接
//        page.addTargetRequests(page.getHtml().css("div#shortcut-2014 div.w ul.fl li#ttbar-home a").links().all());
//        page.putField("url",page.getHtml().css("div#shortcut div ul li a span").all());
    }

    private Site site=Site.me()
            .setCharset("utf8") //設置編碼
            .setTimeOut(10000)  //設置超時時間 單位是ms毫秒
            .setRetrySleepTime(3000)  //設置重試的時間間隔
            .setSleepTime(3);  //設置重試次數
    public Site getSite() {
        return site;
    }
/*設置request請求方式
Request requests=new Request("http://www.12371.cn/cxsm/gzbs/");
        requests.setMethod(HttpConstant.Method.GET);

        Spider.create(new JobProcessor())
                //.addUrl(url)
                .addRequest(requests)
                .setScheduler(new QueueScheduler().setDuplicateRemover(new BloomFilterDuplicateRemover(100000)))
                .thread(5)
                .addPipeline(this.newsData)
                .run();
*/
    //主函數,執行爬蟲
    public static void main(String[] args) {
        Spider spider=Spider.create(new JobProcessor()).addUrl("https://www.jd.com")//設置爬取數據的頁面
//                .addPipeline(new FilePipeline("D:\\result"))//使用Pipeline保存數據到指定文件夾中,自動生成文件
                .thread(5) //多線程進行爬取,5個多線程,速度更快
                .setScheduler(new QueueScheduler().setDuplicateRemover(new BloomFilterDuplicateRemover(10000000)));//設置布隆去重過濾器,指定最多對1000萬數據進行去重操作
                //默認HashSet去重
                //Scheduler scheduler=spider.getScheduler();
                spider.run();//run()執行爬蟲
    }
}

四,SpringBoot項目環境搭建

首先搭建好一個springboot項目,加入mysqlmybatiswebmagic的核心依賴以及擴展依賴,以及添加WebMagic對布隆過濾器的支持的依賴。

  <!--springmvc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>


        <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>
    <!--WebMagic對布隆過濾器的支持-->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>16.0</version>
        </dependency>
        <!--工具包 StringUtils-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>

五,配置文件

resources文件夾新建log4j.properties文件配置日志

log4j.rootLogger=INFO,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

在新建application.properties文件配置數據庫

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=1234

六,Let's go WebMagic!

1,啟動類

@SpringBootApplication
@MapperScan("com.qianlong.dao")	//掃描mapper文件
@EnableScheduling //開啟定時任務,定時抓取數據
@ComponentScan(value = "com.qianlong")//包掃描

public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }
}

2,實體類(存儲到數據庫表的字段)

public class JobInfo {
    private Integer id;
    private String companyName;
    private String companyAddr;
    private String companyInfo;
    private String jobName;
    private String jobAddr;
    private String salary;
    private String time;
    }

3,爬蟲類

package com.qianlong.task;

import com.qianlong.entity.JobInfo;
import org.jsoup.Jsoup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.scheduler.BloomFilterDuplicateRemover;
import us.codecraft.webmagic.scheduler.QueueScheduler;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;

import java.util.List;

@Component
public class JobProcessor implements PageProcessor {
    //前程無憂網站的職位列表地址
    private String url="https://search.51job.com/list/170200,000000,0000,00,9,99,%2B,2,1.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare=";
    @Override
    public void process(Page page) {
    //解析頁面,獲取招聘信息詳情的url地址
        List<Selectable> list = page.getHtml().css("div#resultList div.el").nodes();
        //判斷集合是否為空
        if(list.size()==0){
            //如果為空,表示這是招聘詳情頁,解析頁面,獲取招聘詳情信息,保存數據
            this.saveJobInfo(page);
        }else {
            //如果不為空,表示這是列表頁,解析出詳情頁的url地址,放到任務隊列中
            for(Selectable selectable:list){
                String jobInfoUrl = selectable.links().toString();
                //把獲取到的詳情頁的url地址放到任務隊列中
                page.addTargetRequest(jobInfoUrl);
            }
            //獲取下一頁按鈕的url
            String bkUrl=page.getHtml().css("div.p_in li.bk").nodes().get(1).links().toString();//get(1)拿到第二個
            //把下一頁的url放到任務隊列中
            page.addTargetRequest(bkUrl);
        }
    }

    //解析頁面,獲取招聘詳情信息,保存數據
    private void saveJobInfo(Page page) {
        //創建招聘詳情對象
        JobInfo jobInfo=new JobInfo();
        //拿到解析的頁面
        Html html = page.getHtml();
        //獲取數據,封裝到對象中
        //兩種獲取的方法,一種是直接html.css,另一種是使用Jsoup.parse解析html字符串
        jobInfo.setCompanyName(html.css("div.cn p.cname a","text").toString());
        String addrStr = Jsoup.parse(html.css("div.cn p.msg").toString()).text();
        String addr=addrStr.substring(0,addrStr.indexOf("|"));

        jobInfo.setCompanyAddr(addr);
        jobInfo.setCompanyInfo(html.css("div.tmsg","text").toString());
        jobInfo.setUrl(page.getUrl().toString());
        jobInfo.setJobName(Jsoup.parse(html.css("div.cn h1","title").toString()).text());
        jobInfo.setJobAddr(addr);
        jobInfo.setSalary(Jsoup.parse(html.css("div.cn strong").toString()).text());


        //把結果保存起來
        page.putField("jobInfo",jobInfo);
    }

    private Site site=Site.me()
            .setCharset("gbk")//設置編碼(頁面是什么編碼就設置成什么編碼格式的)
            .setTimeOut(10*1000)//設置超時時間
            .setRetrySleepTime(3000)//設置重試的間隔時間
            .setRetryTimes(3);//設置重試的次數
    @Override
    public Site getSite() {
        return site;
    }
	//這里注入SaveData
    @Autowired
    private SaveData saveData;
    //initialDelay當任務啟動后,等多久執行方法
    //fixedDelay每個多久執行方法
    @Scheduled(initialDelay = 1000,fixedDelay = 100*1000)
    public void process(){
        Spider.create(new JobProcessor())
                .addUrl(url)
                .setScheduler(new QueueScheduler().setDuplicateRemover(new BloomFilterDuplicateRemover(100000)))
                .thread(10)
                .addPipeline(this.saveData)//指定把爬取的數據保存到SaveData類的ResultItems中
                .run();
    }
}

4,獲取爬到的數據並保存到數據庫

前面爬取的數據(封裝到了實體類)都保存在了ResultItems 對象中
在這里插入圖片描述
這里取出前面保存的數據(實體類),然后把數據存到數據庫

package com.qianlong.task;
import com.qianlong.entity.JobInfo;
import com.qianlong.service.Service;
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;

@Component
public class SaveData implements Pipeline {
    @Autowired
    Service service;
    @Override
    public void process(ResultItems resultItems, Task task) {
        //獲取封裝好的招聘詳情對象
        JobInfo jobInfo=resultItems.get("jobInfo");
        if(jobInfo!=null){
            //保存數據到數據庫中
            service.saveJobInfo(jobInfo);
        }
    }
}

5,dao和service

public interface Dao {
    @Insert(value = "insert into jobinfo(companyName,companyAddr,companyInfo,jobName,jobAddr,salary,url) values(#{companyName},#{companyAddr},#{companyInfo},#{jobName},#{jobAddr},#{salary},#{url});")
    int saveJobInfo(JobInfo jobInfo);
}
public interface Service {
    int saveJobInfo(JobInfo jobInfo);
}
@Service
public class ServiceImpl implements Service {

    @Autowired
    private Dao dao;
    @Override
    public int saveJobInfo(JobInfo jobInfo) {
        int i = dao.saveJobInfo(jobInfo);
        return i;
    }
}

然后運行啟動類,控制台出現下圖就是爬取成功了
在這里插入圖片描述
爬取的數據保存到數據庫成功
在這里插入圖片描述

七,后話

至於WebMagic的完整使用,還需要涉及到代理服務器,因為有一些網站是禁止爬取的,它會查到你的ip地址並給你禁掉,所以這時就需要代理服務器。以及爬取數據的去重問題,還要借助一些其他的工具平台進行處理整合,所以,有待完善。
在這里插入圖片描述
每天進步一點點,有問題留言兄弟盟!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM