博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java爬虫案例学习
阅读量:5043 次
发布时间:2019-06-12

本文共 14142 字,大约阅读时间需要 47 分钟。

最近几天很无聊,学习了一下java的爬虫,写一些自己在做这个案例的过程中遇到的问题和一些体会

1.学习目标
         练习爬取京东的数据,图片+价格+标题等等

2.学习过程

      1·开发工具

           JDK1.8
           IntelliJ IDEA
           IDEA自带的Maven

       2.使用技术

           Spring Boot+Spring Data JPA
       3.数据库准备

CREATE TABLE `jd_item` (  `id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '主键id',  `spu` bigint(15) DEFAULT NULL COMMENT '商品集合id',  `sku` bigint(15) DEFAULT NULL COMMENT '商品最小品类单元id',  `title` varchar(100) DEFAULT NULL COMMENT '商品标题',  `price` bigint(10) DEFAULT NULL COMMENT '商品价格',  `pic` varchar(200) DEFAULT NULL COMMENT '商品图片',  `url` varchar(200) DEFAULT NULL COMMENT '商品详情地址',  `created` datetime DEFAULT NULL COMMENT '创建时间',  `updated` datetime DEFAULT NULL COMMENT '更新时间',  PRIMARY KEY (`id`),  KEY `sku` (`sku`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='京东商品表';

        4.添加依赖

4.0.0
org.springframework.boot
spring-boot-starter-parent
2.0.2.RELEASE
cn.itcast.crawler
itcast-crawler-jd
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
org.apache.httpcomponents
httpclient
org.jsoup
jsoup
1.10.3
org.apache.commons
commons-lang3

   5.添加配置文件

#DB Configuration:spring.datasource.driverClassName=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://127.0.0.1:3306/crawlerspring.datasource.username=rootspring.datasource.password=root#JPA Configuration:spring.jpa.database=MySQLspring.jpa.show-sql=true

  6.代码实现

1.pojo

@Entity@Table(name = "jd_item")public class Item {    //主键    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long id;    //标准产品单位(商品集合)    private Long spu;    //库存量单位(最小品类单元)    private Long sku;    //商品标题    private String title;    //商品价格    private Double price;    //商品图片    private String pic;    //商品详情地址    private String url;    //创建时间    private Date created;    //更新时间    private Date updated; set/get}

2.编写dao

public interface ItemDao extends JpaRepository
{ }

3.编写service接口

public interface ItemService {    //根据条件查询数据    public List
findAll(Item item); //保存数据 public void save(Item item);}

4.ItemServiceImpl实现类

@Servicepublic class ItemServiceImpl implements ItemService {    @Autowired    private ItemDao itemDao;    @Override    public List
findAll(Item item) { Example example = Example.of(item); List list = this.itemDao.findAll(example); return list; } @Override @Transactional public void save(Item item) { this.itemDao.save(item); }}

5.编写引导类

@SpringBootApplication//设置开启定时任务@EnableSchedulingpublic class Application {    public static void main(String[] args) {        SpringApplication.run(Application.class, args);    }}

6. 封装HttpClient

@Componentpublic class HttpUtils {    private PoolingHttpClientConnectionManager cm;    public HttpUtils() {        this.cm = new PoolingHttpClientConnectionManager();        //    设置最大连接数        cm.setMaxTotal(200);        //    设置每个主机的并发数        cm.setDefaultMaxPerRoute(20);    }    //获取内容    public String getHtml(String url) {        // 获取HttpClient对象        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();        // 声明httpGet请求对象        HttpGet httpGet = new HttpGet(url);        // 设置请求参数RequestConfig        httpGet.setConfig(this.getConfig());        CloseableHttpResponse response = null;        try {            // 使用HttpClient发起请求,返回response            response = httpClient.execute(httpGet);            // 解析response返回数据            if (response.getStatusLine().getStatusCode() == 200) {                String html = "";                // 如果response。getEntity获取的结果是空,在执行EntityUtils.toString会报错                // 需要对Entity进行非空的判断                if (response.getEntity() != null) {                    html = EntityUtils.toString(response.getEntity(), "UTF-8");                }                return html;            }        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                if (response != null) {                    // 关闭连接                    response.close();                }                // 不能关闭,现在使用的是连接管理器                // httpClient.close();            } catch (Exception e) {                e.printStackTrace();            }        }        return null;    }    //获取图片    public String getImage(String url) {        // 获取HttpClient对象        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();        // 声明httpGet请求对象        HttpGet httpGet = new HttpGet(url);        // 设置请求参数RequestConfig        httpGet.setConfig(this.getConfig());        CloseableHttpResponse response = null;        try {            // 使用HttpClient发起请求,返回response            response = httpClient.execute(httpGet);            // 解析response下载图片            if (response.getStatusLine().getStatusCode() == 200) {                // 获取文件类型                String extName = url.substring(url.lastIndexOf("."));                // 使用uuid生成图片名                String imageName = UUID.randomUUID().toString() + extName;                // 声明输出的文件                OutputStream outstream = new FileOutputStream(new File("D:/images/" + imageName));                // 使用响应体输出文件                response.getEntity().writeTo(outstream);                // 返回生成的图片名                return imageName;            }        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                if (response != null) {                    // 关闭连接                    response.close();                }                // 不能关闭,现在使用的是连接管理器                // httpClient.close();            } catch (Exception e) {                e.printStackTrace();            }        }        return null;    }    //获取请求参数对象    private RequestConfig getConfig() {        RequestConfig config = RequestConfig.custom().setConnectTimeout(1000)// 设置创建连接的超时时间                .setConnectionRequestTimeout(500) // 设置获取连接的超时时间                .setSocketTimeout(10000) // 设置连接的超时时间                .build();        return config;    }}

7. 实现数据抓取

@Componentpublic class ItemTask {    @Autowired    private HttpUtils httpUtils;    @Autowired    private ItemService itemService;    public static final ObjectMapper MAPPER = new ObjectMapper();    //设置定时任务执行完成后,再间隔100秒执行一次    @Scheduled(fixedDelay = 1000 * 100)    public void process() throws Exception {        //分析页面发现访问的地址,页码page从1开始,下一页oage加2        String url = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&cid2=653&cid3=655&s=5760&click=0&page=";        //遍历执行,获取所有的数据        for (int i = 1; i < 10; i = i + 2) {            //发起请求进行访问,获取页面数据,先访问第一页            String html = this.httpUtils.getHtml(url + i);            //解析页面数据,保存数据到数据库中            this.parseHtml(html);        }        System.out.println("执行完成");    }    //解析页面,并把数据保存到数据库中    private void parseHtml(String html) throws Exception {        //使用jsoup解析页面        Document document = Jsoup.parse(html);        //获取商品数据        Elements spus = document.select("div#J_goodsList > ul > li");        //遍历商品spu数据        for (Element spuEle : spus) {            //获取商品spu            Long spuId = Long.parseLong(spuEle.attr("data-spu"));            //获取商品sku数据            Elements skus = spuEle.select("li.ps-item img");            for (Element skuEle : skus) {                //获取商品sku                Long skuId = Long.parseLong(skuEle.attr("data-sku"));                //判断商品是否被抓取过,可以根据sku判断                Item param = new Item();                param.setSku(skuId);                List
list = this.itemService.findAll(param); //判断是否查询到结果 if (list.size() > 0) { //如果有结果,表示商品已下载,进行下一次遍历 continue; } //保存商品数据,声明商品对象 Item item = new Item(); //商品spu item.setSpu(spuId); //商品sku item.setSku(skuId); //商品url地址 item.setUrl("https://item.jd.com/" + skuId + ".html"); //创建时间 item.setCreated(new Date()); //修改时间 item.setUpdated(item.getCreated()); //获取商品标题 String itemHtml = this.httpUtils.getHtml(item.getUrl()); String title = Jsoup.parse(itemHtml).select("div.sku-name").text(); item.setTitle(title); //获取商品价格 String priceUrl = "https://p.3.cn/prices/mgets?skuIds=J_"+skuId; String priceJson = this.httpUtils.getHtml(priceUrl); //解析json数据获取商品价格 double price = MAPPER.readTree(priceJson).get(0).get("p").asDouble(); item.setPrice(price); //获取图片地址 String pic = "https:" + skuEle.attr("data-lazy-img").replace("/n9/","/n1/"); System.out.println(pic); //下载图片 String picName = this.httpUtils.getImage(pic); item.setPic(picName); //保存商品数据 this.itemService.save(item); } } }}

3.结果

4.总结全文

在写代码代码的时候遇到一下的错误,首先打开了京东的要抓取的页面url="xxxxxx",但是在抓取的时候总是抓取不到数据 循环里面的spus总是为0,经过我多方查找信息,把上面的数据修改为一下代码,就成功了

package cn.itboxue.jd.task;import cn.itboxue.jd.pojo.Item;import cn.itboxue.jd.serivce.ItemService;import cn.itboxue.jd.util.HttpUtils;import com.fasterxml.jackson.databind.ObjectMapper;import org.jsoup.Jsoup;import org.jsoup.nodes.Document;import org.jsoup.nodes.Element;import org.jsoup.select.Elements;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.util.Date;import java.util.List;@Componentpublic class ItemTask {    @Autowired    private HttpUtils httpUtils;    @Autowired    private ItemService itemService;    private static final ObjectMapper MAPPER =  new ObjectMapper();    //当下载任务完成后,间隔多长时间进行下一次的任务。    @Scheduled(fixedDelay = 100 * 1000)    public void itemTask() throws Exception {        //声明需要解析的初始地址/*        https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq%22%20+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22=%E6%89%8B%E6%9C%BA&cid2=653&cid3=655&s=113&click=0&page=*/        String url = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq%22%20+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22=%E6%89%8B%E6%9C%BA&cid2=653&cid3=655&s=113&click=0&page=";        //按照页面对手机的搜索结果进行遍历解析        for (int i = 1; i < 100; i = i + 2) {            Document doc = Jsoup.connect(url+i).maxBodySize(0).get();            //doc获取整个页面的所有数据            Elements ulList = doc.select("ul[class='gl-warp clearfix']");            Elements liList = ulList.select("li[class='gl-item']");            this.parse(liList);        }        System.out.println("手机数据抓取完成!");    }    //解析页面,获取商品数据并存储    private void parse( Elements liList) throws Exception {        //解析html获取Document       // Document doc = Jsoup.parse(html);        //System.out.print(doc);        //获取spu信息        //Elements elements = doc.select("div#J_goodsList > ul > li");        //System.out.println(elements+"是否有数据");        for (Element spuEle : liList) {            //获取spu            long spu = Long.parseLong(spuEle.attr("data-spu"));            //获取sku信息            Elements skuEles = spuEle.select("li.ps-item");            for (Element skuEle : skuEles) {                //获取sku                long sku = Long.parseLong(skuEle.select("[data-sku]").attr("data-sku"));                //根据sku查询商品数据                Item item = new Item();                item.setSku(sku);                List
list = this.itemService.findAll(item); if(list.size()>0) { //如果商品存在,就进行下一个循环,该商品不保存,因为已存在 continue; } //设置商品的spu item.setSpu(spu); //获取商品的详情的url String itemUrl = "https://item.jd.com/" + sku + ".html"; item.setUrl(itemUrl); //获取商品的图片 String picUrl ="https:"+ skuEle.select("img[data-sku]").first().attr("data-lazy-img"); picUrl = picUrl.replace("/n9/","/n1/"); String picName = this.httpUtils.doGetImage(picUrl); item.setPic(picName); //获取商品的价格 String priceJson = this.httpUtils.doGetHtml("https://p.3.cn/prices/mgets?skuIds=J_" + sku); double price = MAPPER.readTree(priceJson).get(0).get("p").asDouble(); item.setPrice(price); //获取商品的标题 String itemInfo = this.httpUtils.doGetHtml(item.getUrl()); String title = Jsoup.parse(itemInfo).select("div.sku-name").text(); item.setTitle(title); item.setCreated(new Date()); item.setUpdated(item.getCreated()); //保存商品数据到数据库中 this.itemService.save(item); } } }}

今天的笔记就做到这里吧,希望以后的想学习java爬虫的爱好者少走弯路,谢谢。。。。。。。

2019-04-1921:07:56

作者:何秀好

转载于:https://www.cnblogs.com/itboxue/p/10738810.html

你可能感兴趣的文章
百度编辑器图片在线流量返回url改动
查看>>
我对你的期望有点过了
查看>>
微信小程序wx:key以及wx:key=" *this"详解:
查看>>
下拉框比较符
查看>>
2.2.5 因子的使用
查看>>
css选择器
查看>>
photoplus
查看>>
Python 拓展之推导式
查看>>
[Leetcode] DP-- 474. Ones and Zeroes
查看>>
80X86寄存器详解<转载>
查看>>
c# aop讲解
查看>>
iterable与iterator
查看>>
返回顶部(动画)
查看>>
webpack+react+antd 单页面应用实例
查看>>
Confluence 6 SQL Server 数据库驱动修改
查看>>
Confluence 6 通过 SSL 或 HTTPS 运行 - 备注和问题解决
查看>>
【47.76%】【Round #380B】Spotlights
查看>>
Git(使用码云)
查看>>
分享Java web 开发必游之路
查看>>
IIS初始化(预加载),解决第一次访问慢,程序池被回收问题(转载)
查看>>