天天看點

使用webmagic抓取小說

學習webmagic已經好幾天了,抓取過小紅書的視訊,拉勾網的招聘資訊,這一次抓取一些小說,做一個收尾.

經過我的考慮,我決定先爬豆瓣讀書top250的榜單,然後根據榜單進行抓取小說,這樣下載下傳下來的小說我覺得還有一點價值.

然後我把豆瓣讀書top250抓下來了

這一點代碼就不上了

使用webmagic抓取小說

準備對網站網址進行分析,然後進行抽取,之後再比較是否為豆瓣榜單上的圖書

經過思考,決定代碼這樣寫,我直接對作者這一欄進行抽取,抽取到作者名之後,到資料庫中去查詢是否有對應的作者,如果有的話就抓取該作者下所有小說.

public class FictionProcessor implements PageProcessor {
    DouBan250Mapper douBan250Mapper = ApplicationContextProvider.getApplicationContext().getBean(DouBan250Mapper.class);

    private Site site = Site.me()
            .setRetryTimes(1002)
            .setSleepTime(1000);

    @Override
    public void process(Page page) {
        //添加路徑
        page.addTargetRequests(page.getHtml().regex("18-[0-9]+.html").all());
        page.addTargetRequests(page.getHtml().regex("/files/writer/[0-9]+.html").all());
        //取出作者名字,拿作者名去資料庫比對,如果比對成功,就下載下傳該作者下全部小說
        String authorName = page.getHtml().regex("align=\"center\"><h2><b>[\\w\\W]+</b></h2></Td>").get();
        if (authorName != null) {
            authorName = authorName.replace("align=\"center\"><h2><b>", "");
            authorName = authorName.replace("作品集</b></h2></td>", "");
        }
        System.out.println("作者名:" + authorName);
        if (authorName != null) {
            DouBan250 douBan250 = douBan250Mapper.selectByAuthorName("%" + authorName + "%");
            if (douBan250 != null) {
                //将路徑添加到隊列中,下載下傳所有的小說
                System.out.println("找到了一個************************************");
                //取出小說名,建立檔案夾 路徑是  D://作者名/小說名,如果存在就追加,否則就建立
                //為了避免多線程下出現章節排列順序錯誤的情況發生,是以,小說還是先存進資料庫吧

                //将抓取到的小說放入隊列
                page.addTargetRequests(page.getHtml().regex("/book[0-9]?/[0-9]+").all());

            }
        }
        if (page.getUrl().toString().contains("book") && !page.getUrl().toString().contains("html")) {
            //在這裡進行抓取章節資訊.如果能抓取到
            List<String> all = page.getHtml().regex("<td align=\"center\" colspan=\"4\"><strong>[\\w\\W]+<td height=\"30\" align=\"center\" valign=\"middle\">上一篇")
                    .regex("[0-9]+.html").all();
            //在這裡要處理一下,将章節位址添加進去,加一個标記,不然下面不好進行捕捉
            if (all != null) {
                for (int i = 0; i < all.size(); i++) {
                 
                    page.addTargetRequest(page.getUrl() + "/" + all.get(i) + "?huazai=huazaimz");
                }
            }
            //将資料儲存到pipeline中
            //小說id  路徑中擷取
            String id = page.getUrl().toString().replace("https://www.kanunu8.com/", "").split("/")[1];
            //小說名   //小說作者
            String author = page.getHtml().regex("<title>[\\w\\W]+</title>").get();
            author= author.replace("</title>","").replace("<title>","");
            String bookName = author.split("-")[0];
            String authorName2 = author.split("-")[1];
            page.putField("","");
            //小說簡介
//            String vintroduce = page.getHtml().regex("</strong><br />[\\w\\W]+</strong></td>").get();
//            vintroduce= vintroduce.replace("</strong><br />","").split("</td>")[0];
            System.out.println("小說資訊::"+id+"作者::"+authorName2+"書名::"+bookName );

            page.putField("vId",id);
            page.putField("author",authorName2);
            page.putField("vName",bookName);
        }
        //如果是章節,就進行抓取

        if (page.getUrl().toString().contains("huazai=huazaimz")) {

            //取出正文
            String content = page.getHtml().regex("<td width=\"820\" align=\"left\" bgcolor=\"#FFFFFF\">[\\w\\W]+ <td width=\"30\" align=\"center\" bgcolor=\"#FFFFFF\"></td>").get();
           content = content.replace("<td width=\"820\" align=\"left\" bgcolor=\"#FFFFFF\"> <p>","")
                    .replace("<td width=\"30\" align=\"center\" bgcolor=\"#FFFFFF\"></td>","");
            //取出章節名
            String sectionName = page.getHtml().regex("<title>[\\w\\W]+</title>").get();
            sectionName= sectionName.replace("</title>","").replace("<title>","");
            //取出id
            String[] ids = page.getUrl().toString().replace(".html?huazai=huazaimz", "")
                    .replace("https://www.kanunu8.com/", "").split("/");

            page.putField("novelId",ids[1]);
            page.putField("sId",ids[2]);
            page.putField("sContent",content);
            page.putField("sName",sectionName);

        }


    }

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

    @GetMapping("/book")
    public void book() {
        Spider.create(new FictionProcessor()).setDownloader(new HttpClientDownloader())
                .addUrl("https://www.kanunu8.com/files/writer/18-1.html")
                .addPipeline(new FictionPipeline())
                .thread(10).run();
    }
}
### webmagic管道

public class FictionPipeline implements Pipeline {
    NovelMapper novelMapper = ApplicationContextProvider.getApplicationContext().getBean(NovelMapper.class);
    SectionMapper sectionMapper = ApplicationContextProvider.getApplicationContext().getBean(SectionMapper.class);

    @Override
    public void process(ResultItems resultItems, Task task) {
        String vId = resultItems.get("vId");
        String author = resultItems.get("author");
        String vName = resultItems.get("vName");
        if (vId != null) {
            Novel novel = new Novel();
            novel.setAuthor(author);
            novel.setVid(Integer.parseInt(vId));
            novel.setVname(vName);
            novelMapper.insert(novel);
        }
        String novelId = resultItems.get("novelId");
        String sId = resultItems.get("sId");
        String sContent = resultItems.get("sContent");
        String sName = resultItems.get("sName");
        if (novelId != null) {
            Section section = new Section();
            section.setSid(Integer.parseInt(sId));
            section.setVid(Integer.parseInt(novelId));
            section.setScontent(sContent);
            section.setSname(sName);
            sectionMapper.insert(section);

        }

    }
}
           

因為我不會訂制Scheduler,是以抓取頁面的時候,對不同層次的頁面就放到一起處理了.

最後成功抓取有608本小說.

使用webmagic抓取小說

這是我非常喜歡的一本書,可以看到章節目錄還是挺完整的,至于為什麼留下來這麼多的空格以及回車換行<br>是因為我打算寫出來,儲存到本地,就需要将<br>替換成\r\n,這樣的話就實作了排版…另外不直接寫到本地的原因是,抓取小說的時候開啟了多線程,為了避免章節的順序錯誤,是以決定先寫到資料庫中.

使用webmagic抓取小說

主要的時間還是浪費在如何解析HTML了,這個盜版小說網站的布局特别簡單,隻能使用正則一點一點的去抽取,而且同一個層次的頁面有兩三種不同的布局,比較麻煩.

接下來的代碼任務就是将小說儲存到本地了,基本上還是沒有什麼難點的.

使用webmagic抓取小說
使用webmagic抓取小說

排版還是挺漂亮的!

使用webmagic抓取小說

碼雲位址:https://gitee.com/huazaimz/webmagic.git