练习使用WebMagic爬取唯美图片

57 阅读3分钟

前言

周末闲着没事,准备练习一下爬虫技术,同时也拓展一下视野(欣赏一下美好的东西),练习使用WebMagic爬取美女图片实战。 废话不多说,直接进入主题。

第一步 分析网站数据结构

以妹子网为例:

  1. 进入首页可以看到分成了几个栏目;
  2. 进入栏目页面后是美女列表;
  3. 点击列表中美女图片后进入单个美女的相册页面,页面中显示单张图片,同时带有分页信息;
  4. 最后两个栏目里是直接分页显示美女图片;

根据上面的分析,基本了解了该网站的基本结构,接下来就可以写爬虫程序了。

第二步 代码实现

1.Maven仓库配置

代码如下:

<properties>
        <httpclient.version>4.5.13</httpclient.version>
        <webmagic.version>0.7.4</webmagic.version>
        <hutool.version>5.6.4</hutool.version>
</properties>


    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>${httpclient.version}</version>
        </dependency>
  <dependency>
            <groupId>us.codecraft</groupId>
            <artifactId>webmagic-core</artifactId>
            <version>${webmagic.version}</version>
        </dependency>
        <dependency>
            <groupId>us.codecraft</groupId>
            <artifactId>webmagic-extension</artifactId>
            <version>${webmagic.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-classic</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
     </dependencies>

2.PageProcessor代码

代码如下:

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.http.HttpUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;

import java.io.File;
import java.net.InetAddress;

public class MzituPageProcessor implements PageProcessor {
    /**
     * 定义域名
     */
    private static final String HOST = "https://www.mzitu.com/";
    /**
     * 图片保证路径
     */
    private final String basePath;
    private final Site site = Site.me().setRetryTimes(5).setTimeOut(5000).setSleepTime(200)
            .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0");

    public MzituPageProcessor(String basePath) {
        this.basePath = basePath;
    }

    @Override
    public void process(Page page) {
        String url = page.getUrl().get();
        Document document = Jsoup.parse(page.getHtml().get());
        if (url.contains("/page/")) {
            // xinggan japan mm 列表页
            // 获取列表 #pins > li:nth-child(1) > a
            Elements listElements = document.select("#pins > li > a");
            listElements.forEach(element -> {
                System.out.println("list Element =" + element.attr("href"));
                // 进入二级页面
                page.addTargetRequest(element.attr("href"));
            });
            // 获取下一页
            Elements pageElements = document.select("div.pagination > div > a.next");
            if (null != pageElements) {
                System.out.println("下一页 =" + pageElements.get(0).attr("href"));
                // 进入下一页
                page.addTargetRequest(pageElements.get(0).attr("href"));
            }
        } else if (url.contains("/#comments")) {
            // zipai jiepai 列表页
            String relativePath = document.select("div.currentpath").text().replace("当前位置: 妹子图 » ", "");
            // #comments > ul > li > div > p > img
            Elements imgElements = document.select("#comments > ul > li > div > p > img");
            imgElements.forEach(element -> {
                String imgName = element.attr("data-original").substring(element.attr("data-original").lastIndexOf("/") + 1);
                // 下载图片
                HttpUtil.downloadFile(element.attr("data-original"), String.format("%s%s\\%s", basePath, relativePath, imgName));
            });
            // 获取下一页
            Elements pageElements = document.select("#comments > div > a.prev.page-numbers");
            if (null != pageElements) {
                // 进入下一页
                page.addTargetRequest(pageElements.get(0).attr("href"));
            }
        } else if (page.getUrl().regex("[a-zA-z]+://www.mzitu.com/\\d{1,8}$").match()) {
            // 详情页
            // 获取文件名
            String relativePath = document.select("div.currentpath").text().replace("当前位置: 妹子图 » ", "").replace(" » ", "-").replaceAll("[.,,。?“”]", "-");
            String imgUrl = document.select("div.main-image > p > a > img").attr("src");
            String imgName = String.format("%s%s", url.replace(HOST, "").replace("/", "-"), imgUrl.substring(imgUrl.lastIndexOf(".")));
            // 下载图片
            HttpUtil.downloadFile(imgUrl, String.format("%s%s\\%s", basePath, relativePath, imgName));
            // 获取分页信息
            Elements pageElements = document.select("div.pagenavi > a");
            int maxPage = 1, startPage = 2;
            for (int i = 0; i < pageElements.size(); i++) {
                Element pageElement = pageElements.get(i);
                if (i > 1 && NumberUtil.isNumber(pageElement.attr("href").substring(pageElement.attr("href").lastIndexOf("/") + 1))) {
                    int nowPage = Integer.parseInt(pageElement.attr("href").substring(pageElement.attr("href").lastIndexOf("/") + 1));
                    if (nowPage > maxPage) {
                        maxPage = nowPage;
                    }
                }
            }
            // 检查是否已经下载了,检查文件夹是否存,检查文件夹中图片数量
            String imgPath = String.format("%s%s", basePath, relativePath);
            if (FileUtil.exist(imgPath)) {
                // 文件夹已存在
                startPage = 1 + new File(imgPath).listFiles().length;
            } else {
                // 文件夹不存在
                startPage = 2;
            }
            for (int i = startPage; i <= maxPage; i++) {
                System.out.println("详情页 下一页 =" + url + "/" + i);
                page.addTargetRequest(url + "/" + i);
            }
        } else {
            // 详情页
            // 获取文件名
            String relativePath = document.select("div.currentpath").text().replace("当前位置: 妹子图 » ", "").replace(" » ", "-").replaceAll("[.,,。?“”]", "-");
            String imgUrl = document.select("div.main-image > p > a > img").attr("src");
            String imgName = String.format("%s%s", url.replace(HOST, "").replace("/", "-"), imgUrl.substring(imgUrl.lastIndexOf(".")));
            // 下载图片
            HttpUtil.downloadFile(imgUrl, String.format("%s%s\\%s", basePath, relativePath, imgName));
        }
    }

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


3.主程序

代码如下:

  @SneakyThrows
    public static void main(String[] args) {
        Spider.create(new MzituPageProcessor("D:\\mzitu\\", localAddress)).addUrl(
                "https://www.mzitu.com/xinggan/page/1",
                "https://www.mzitu.com/japan/page/1",
                "https://www.mzitu.com/mm/page/1",
                "https://www.mzitu.com/zipai/#comments",
                "https://www.mzitu.com/jiepai/#comments"
        )
                .thread(3)
                .run();
    }


第三步 打完收工

接下来就尽情欣赏吧!当然要考虑人家网站的承受能力,大家在满足自己的诉求时也要考虑人家网站的承受能力,下载时候不要太快,保障其他人也能够正常使用,独乐乐不如众乐乐是吧! 码觉客微信公众号