一、目的:
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
其他出处均为转载,原创作品,欢迎读者批评指正。