學習webmagic已經好幾天了,抓取過小紅書的視訊,拉勾網的招聘資訊,這一次抓取一些小說,做一個收尾.
經過我的考慮,我決定先爬豆瓣讀書top250的榜單,然後根據榜單進行抓取小說,這樣下載下傳下來的小說我覺得還有一點價值.
然後我把豆瓣讀書top250抓下來了
這一點代碼就不上了
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR9EMrR1T1UERNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1kzM4MzN1ETM1AzMwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
準備對網站網址進行分析,然後進行抽取,之後再比較是否為豆瓣榜單上的圖書
經過思考,決定代碼這樣寫,我直接對作者這一欄進行抽取,抽取到作者名之後,到資料庫中去查詢是否有對應的作者,如果有的話就抓取該作者下所有小說.
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本小說.
這是我非常喜歡的一本書,可以看到章節目錄還是挺完整的,至于為什麼留下來這麼多的空格以及回車換行<br>是因為我打算寫出來,儲存到本地,就需要将<br>替換成\r\n,這樣的話就實作了排版…另外不直接寫到本地的原因是,抓取小說的時候開啟了多線程,為了避免章節的順序錯誤,是以決定先寫到資料庫中.
主要的時間還是浪費在如何解析HTML了,這個盜版小說網站的布局特别簡單,隻能使用正則一點一點的去抽取,而且同一個層次的頁面有兩三種不同的布局,比較麻煩.
接下來的代碼任務就是将小說儲存到本地了,基本上還是沒有什麼難點的.