使用Jsoup抓取京东图书分类页面图书信息

一、目的:

1.任务

使用 Jsoup抓取京东图书分类页面的图书信息。
抓取目标分类网址例如:https://list.jd.com/list.html?cat=1713,3259,3330
给与的某个图书页面,抓取每一页面的图书信息,此分类页多页抓取直至结束。

下面图片即为给定目标抓取页面地址
https://list.jd.com/list.html?cat=1713,3259,3330
这里写图片描述

我们获取到的应该是每一本图书里边的图书信息,类似模拟打开了网页查阅了图书信息内容。
所以我们随便打开一个item(红框圈了,暂且把分类页面的一本图书视为一个item吧),查看内容。
抓取内容是红框里这一部分:
这里写图片描述

2.工具和语言

语言:java
工具:jsoup-1.7.2.jar

二、思路

我们采取这样的思路,
1.将分类网站源码保存到本地
2.解析出分类页面所有的图书(item)拿到一个类似的item的List集合
3.根据拿到的List集合,遍历循环去解析每个页面中的图书信息,匹配到图书信息控制台打印即可。

我们把抓取京东图书抽象成一个类,这个类有保存下载源码的方法,有解析分类页面拿到List集合的方法,有解析图书页面信息的方法等。

三、解析

1.将分类网站源码保存到本地

将网站的源码下载到本地的方法,这样在本地就可以看到一个text文件, 专门存放当前网站源码的txt文件。用来解析使用的

/**
     * 将目标html保存到本地中进行解析获得 doc文本对象
     * @param htmlUrl 需要下载到本地的网址
     * @param toSavePath 需要保存到本地的电脑路径 例如E:\\jd.txt
     * @param type 编码方式 UTF-8 或者 GBK 等
     * @return
     * @throws IOException
     */
    public Document getDocFromUrl(String htmlUrl,String toSavePath,String type) throws IOException
    {
        URL url = new URL(htmlUrl) ;

        File file  = new File(toSavePath) ;
        if(file.exists())
            file.delete() ;
        file.createNewFile() ; 

        FileOutputStream fos = new FileOutputStream(file) ;

        BufferedReader br = new BufferedReader(
                new InputStreamReader(url.openStream(),type)) ;

        byte [] b = new byte[1024] ;
        String c ; 
        while(((c = br.readLine())!=null))
        {
            fos.write(c.getBytes());
        }

        System.out.println("保存分类html完毕");

        Document doc = Jsoup.parse(file,"UTF-8") ;

        return doc ;
    }

2.解析出分类页面所有的图书

这里就是解析出分类页面中的所有如图所示的item 的每个地址,将他们的地址变成一个List集合即可。这样就获得了当前某一页的所有的图书地址。为解析每个图书信息做一个铺垫。

打开浏览器的开发者模式(F12)看一下如何解析:
我们在图书信息列表中不难发现这些每一本图书都是由Li标签包裹,这些图书li标签都被使用一个class=“gl-warp”的ul的包裹着,分析到这你应该就有思路了。
这种情况我们先使用jsoup拿到ul标签的内容,再对ul标签里的li标签进行getElementsByTag(“li”); 方法,这样拿到的是每一个li标签的内容,也就是每个图书的内容。 以下两行代码获取到li的集合

    Element contentEl = doc.select("ul.gl-warp").first() ;
    Elements lis = contentEl.getElementsByTag("li");

这里写图片描述

拿到图书们的Elements元素还没完因为我们要的是这些图书的地址,换句话说要的是图书List< String > 但是如何解析出每个图书的地址呢 我们需要随便打开某个li标签进行查看。

这里写图片描述

也许你一眼就看到了一个地址,没错,就是这个标签。我们再拿到它的href属性值就行了,任性
如何做 :
Element titleEl = li.select(“div.p-name”).first() ;
Element a = titleEl.select(“a”).first() ;
String href = a.attr(“href”) ;

啰嗦了这么多上代码 看一眼:


/**
     * 解析每一个图书的页面地址
     * @param doc
     * @return
     */
    public List<String> parseItemUrl(Document doc)
    {
        //获取页面
        Element contentEl = doc.select("ul.gl-warp").first() ;
        Elements lis = contentEl.getElementsByTag("li");
        for (Element li : lis) {
              //for循环的就是每一本书拿到详情地址
            Element titleEl = li.select("div.p-name").first() ;
            Element a = titleEl.select("a").first() ;
            String  href = a.attr("href") ;
            href = "http:"+href ; 
            hrefList.add(href) ;
            }
        return hrefList  ;

    }

3.解析一本图书

解析每一本图书,根据该图书详情页的地址,下载此详情页源码,去使用jsoup匹配。可以看到图片中高亮的部分就是我们要解析的内容。同样很清晰,我们只需要解析到 一个叫class = ”parameter2 ”ul标签, 然后再对里边每个li进行解析就ok了 ,思路完全可以按照上一个解析过程来。 这里我是直接当成一个text文本全部输出出来了,没有循环遍历具体到每一个li标签, 大家可以完全按照上一个来做。

这里写图片描述

    /**
     * 解析书本的信息
     * @param doc
     */
    public void parseContent(Document doc)
    {
        Element contentEl = doc.getElementById("parameter2") ;
        if(contentEl==null)
            return ; 

        Elements lis = contentEl.getElementsByTag("li");

        if(lis==null)
            return ; 

        for (Element li : lis) {
              String text = li.text() ;
              System.out.println("--"+text);
            }
    }   

解析当前分类页的下一页的内容

我们需要的就是匹配到当前页面的下一页的按钮的规则,获取下一页的url即可。
这里写图片描述

解析下一页的按钮也不难发现 我们要找到 p-num 的span标签, 然后在此标签内找到pn-next的 a标签。 该a标签的href属性值就是我们要找到的地址。
这里我们就直接通过代码来拿到他。

这里写图片描述

    /**
     * 解析下一页
     * @param doc
     * @return
     */
    public String parseNext(Document doc)
    {   String nextPageHref="";

        Element el = doc.select("span.p-num").first() ;
        Elements as = el.getElementsByTag("a") ;
        for(Element a :as)
        {

            if(a.attr("class").endsWith("pn-next"))
            {
                String  pageHref = a.attr("href") ;
                nextPageHref = htmlUrl.substring(0,htmlUrl.lastIndexOf("/"))+pageHref;
                System.out.println("下一页地址:"+nextPageHref);
        }
        }
            return nextPageHref;
    }

四、代码:

封装的解析类HtmlParser .java:

package com.jd.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
/**
 * html网址解析器
 * @author shaoduo
 *
 */
public class HtmlParser {

    String htmlUrl = "" ; 
    String nextPageUrl = "" ; 
    String charSet = "" ; 


    List<String> hrefList = new ArrayList<String>() ;


    public HtmlParser(String htmlUrl)
    {
        this.htmlUrl  = htmlUrl ; 
    }

/*  public List<String> getHrefList ()
    {
        try {

            parser() ;

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return hrefList ; 
    }*/


    public String getNextPageHrefList()
    {

        return this.nextPageUrl ;
    }


    /**
     * 解析过程
     * @param htmlUrl
     * @throws IOException
     */
    public  void parser(String htmlUrl) throws IOException {

        Document doc = getDocFromUrl(htmlUrl, "D:\\cat.txt","utf-8") ;
        hrefList = parseItemUrl(doc) ;
        for (String string : hrefList) {
            Document conDoc = getDocFromUrl(string, "D:\\content.txt","gbk") ;
            parseContent(conDoc);
            }

        nextPageUrl =  parseNext(doc) ;
        if(nextPageUrl!="")
        {
            System.out.println("解析下一页------------");
            parser(nextPageUrl) ;
        }

    }



    /**
     * 将目标html保存到本地中进行解析获得 doc文本对象
     * @param htmlUrl
     * @param toSavePath
     * @param type
     * @return
     * @throws IOException
     */
    public Document getDocFromUrl(String htmlUrl,String toSavePath,String type) throws IOException
    {
        URL url = new URL(htmlUrl) ;

        File file  = new File(toSavePath) ;
        if(file.exists())
            file.delete() ;
        file.createNewFile() ; 

        FileOutputStream fos = new FileOutputStream(file) ;

        BufferedReader br = new BufferedReader(
                new InputStreamReader(url.openStream(),type)) ;

        byte [] b = new byte[1024] ;
        String c ; 
        while(((c = br.readLine())!=null))
        {
            fos.write(c.getBytes());
        }

        System.out.println("保存分类html完毕");

        Document doc = Jsoup.parse(file,"UTF-8") ;

        return doc ;
    }


    /**
     * 解析每一个图书的页面地址
     * @param doc
     * @return
     */
    public List<String> parseItemUrl(Document doc)
    {
        //获取页面
        Element contentEl = doc.select("ul.gl-warp").first() ;
        Elements lis = contentEl.getElementsByTag("li");
        for (Element li : lis) {

            Element titleEl = li.select("div.p-name").first() ;
            Element a = titleEl.select("a").first() ;
            String  href = a.attr("href") ;
            href = "http:"+href ; 
            hrefList.add(href) ;
            }
        return hrefList  ;

    }

    /**
     * 解析书本的信息
     * @param doc
     */
    public void parseContent(Document doc)
    {
        Element contentEl = doc.getElementById("parameter2") ;
        if(contentEl==null)
            return ; 

        Elements lis = contentEl.getElementsByTag("li");

        if(lis==null)
            return ; 

        for (Element li : lis) {
              String text = li.text() ;
              System.out.println("--"+text);
            }
    }   

    /**
     * 解析下一页
     * @param doc
     * @return
     */
    public String parseNext(Document doc)
    {   String nextPageHref="";

        Element el = doc.select("span.p-num").first() ;
        Elements as = el.getElementsByTag("a") ;
        for(Element a :as)
        {

            if(a.attr("class").endsWith("pn-next"))
            {
                String  pageHref = a.attr("href") ;
                nextPageHref = htmlUrl.substring(0,htmlUrl.lastIndexOf("/"))+pageHref;
                System.out.println("下一页地址:"+nextPageHref);
        }
        }
            return nextPageHref;
    }




}

测试类程序主入口:

package com.jd.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
 * 京东图书分类html网址解析主入口
 * @author shaoduo
 *
 */
public class JD {


    static List<String> hrefList = new ArrayList<String>() ;
    static String nextPageUrl = "" ;


    public static void main(String arg[])
    {

            String startCatUrl  = "https://list.jd.com/list.html?cat=1713,3279,3646";

            HtmlParser hp = new HtmlParser(startCatUrl) ;
            try {

                hp.parser(startCatUrl);

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    }

}

五、源代码下载

https://github.com/shaoduo123/JD_CAT_JOUP_DEMO


版权声明
author :shaoduo
原文来自:http://blog.csdn.net/shaoduo/article/details/78247664
其他出处均为转载,原创作品,欢迎读者批评指正。

猜你喜欢

转载自blog.csdn.net/shaoduo/article/details/78247664