京东等电商爬虫问题与总结(二)

京东等电商爬虫问题与总结(二)

  • 京东
    这一段时间比较忙,更新也不及时。。。下面将总结一下在写京东爬虫的时候,遇到的一些问题。
    京东的页面,列表页的数据基本包含了所有的信息了,详情页里面也没有什么有价值的信息了。所以我的数据都是取自于列表页。并且京东的数据经过我多次测试(主要是公司很多运营同学在使用。。。),他是不反爬的。
    这样听起来是不是觉得很简单?但是这里面还是有一个坑的,京东列表页数据,如果你什么操作都不做,单纯http请求数据,那么只能拿到一半的数据(京东列表页有60条商品数据,只能拿到30条商品数据),因为他是动态加载的,需要模拟人的滑动操作,滚动到页面底端。这里我使用的是phantomjs来模拟人的滚动操作。还有一点需要注意的是,使用phantomjs滚到到底端获取到数据之后,他获取到的是为滑动前30条商品数据+滑动后60条数据,共90条数据,我们需要的是后60条数据,所以这个在页面解析的时候需要注意一下。
    因为我使用的是webmagic这个框架,所以页面下载、解析这些继承的他的类,进一步做的处理。
private void processListPage(Page page, String spiderUrl) {
        List<GoodsInfo> goodsInfoList = new ArrayList<>();

        // 下一页
        Integer totalPage = Integer.valueOf(page.getHtml().$(JD_TOTAL_PAGE, "text").toString());
        if ((pageNum++) < totalPage) {
            Integer currentPage = Integer.valueOf(page.getHtml().$(JD_CURRENT_PAGE, "text").toString());
            String[] urls = spiderUrl.split("&page=");
            String nextPageUrl = urls[0] + "&page=" + (currentPage * 2 + 1);
            page.addTargetRequest(nextPageUrl);
            logger.info("nextpage is ==>{}", nextPageUrl);
        }

        // 列表详情
        Document document = Jsoup.parse(page.getHtml().get());
        Elements elements = document.select("#J_goodsList > ul");
        if (elements.size() > 0) {
            Elements element = elements.get(elements.size() - 1).select("li");
            logger.info("element size is ==>{}", element.size());
            element.forEach(element1 -> getParsedPageInfo(goodsInfoList, element1));
            logger.info("the goodsCount is ==>{}", goodsCount);
            page.putField("goodsInfo", goodsInfoList);
        }
    }

下面是具体的页面解析。

private void getParsedPageInfo(List<GoodsInfo> goodsInfoList, Element element1) {
        try {
            String goodsId = element1.select("li").attr("data-sku");
            String goodsTitle = null;

            try{
                goodsTitle = element1.select("div").get(4).select("em").get(0).text();
            }catch (Exception e){
                goodsTitle = element1.select("div.gl-i-wrap > div").select("em").text().replaceAll("¥","");
            }
            String goodsLink = "http://item.jd.com/" + goodsId + ".html";
            String goodsPrice = element1.select("strong").text();
            String imgLink = element1.select("a > img").get(0).attr("src");

            String storeName = element1.select("span.J_im_icon").text();
            String storeLink = element1.select("span.J_im_icon > a").get(0).attr("href");

            GoodsInfo goodsInfo = new GoodsInfo();
            goodsInfo.setGoodsId(goodsId);

            if (StringUtils.isBlank(imgLink)) {
                imgLink = element1.select("a > img").get(0).attr("data-lazy-img");
            }
            if (StringUtils.isNotBlank(goodsLink)&&!goodsLink.startsWith("http")) {
                goodsLink = "http:" + goodsLink;
            }
            if (StringUtils.isNotBlank(imgLink)&&!imgLink.startsWith("http")) {
                imgLink = "http:" + imgLink;
            }
            if (StringUtils.isNotBlank(storeLink)&&!storeLink.startsWith("http")) {
                storeLink = "http:" + storeLink;
            }
            goodsInfo.setGoodsLink(goodsLink);
            goodsPrice = goodsPrice.split(" ")[0].replace("¥", "");
            goodsInfo.setGoodsCurrentPrice(goodsPrice);
            goodsInfo.setGoodsCalcPrice(Double.parseDouble(goodsPrice));
            goodsInfo.setGoodsTitle(goodsTitle);
            goodsInfo.setShopName(storeName);
            goodsInfo.setShopKeeper(storeName);
            goodsInfo.setGoodsImages(imgLink);

            goodsInfo.setShopLink(storeLink);
            String shopId = storeLink.replace("http://mall.jd.com/index-", "").replace(".html", "").trim();

            //店铺名称 商品id 店铺链接 商品标题 商品链接 商品图片链接 商品列表价格 平台id 平台名称 总页数 搜索关键词
            logger.info("\n商品id==>{}\n商品链接==>{}\n商品列表价格==>{}\n商品名称==>{}\n图片链接==>{}\n店铺ID==>{}\n店铺名称==>{}\n店铺链接==>{}\n任务ID==>{}\n",
                    goodsId, goodsLink, goodsPrice, goodsTitle, imgLink, shopId, storeName, storeLink, crawlerRule.getTaskNo());

            goodsInfo.setShopId(shopId);
            goodsInfo.setPlatformId(crawlerRule.getSpiderPlatformId());
            goodsInfo.setTaskNo(crawlerRule.getTaskNo());
            goodsInfo.setRuleNo(crawlerRule.getRuleNo());
            goodsInfo.setCrawlerTaskId(crawlerRule.getCrawlerTaskId());
            goodsInfo.setCrawlerRuleId(crawlerRule.getId());
            goodsInfo.setCreateBy(crawlerRule.getCreateBy());
            goodsInfo.setCreateDate(crawlerRule.getCreateDate());

            Date date = new Date();
            DateFormat format = new SimpleDateFormat("yyyyMMdd");
            String crawlerVersion = format.format(date);
            goodsInfo.setCrawlerVersion(Integer.parseInt(crawlerVersion));
            goodsInfoList.add(goodsInfo);

        } catch (Exception e) {
            logger.info("parse failed ==>{}", e);
        }
    }

下载器呢,使用的是webmagic自带的PhantomjsDownloader,源代码里面,写了可以调用js来达到滑动的效果,并且源代码也给出了一个例子,我基于这个例子,修改了那段js,达到了我需要的效果(如果要使用,要记得安装phantomjs呀),下面是这段js:

var system = require('system');
var url = system.args[1];

var page = require('webpage').create();
page.settings.loadImages = false;
page.settings.resourceTimeout = 5000;
var vWidth = 1080;
var vHeight = 1920;
page.viewportSize = {
    width: vWidth ,
    height: vHeight
};
page.open(url, function (status) {
    if (status != 'success') {
        console.log("HTTP request failed!");
        phantom.exit();
    } else {
        console.log(page.content);
         setTimeout((function() {
            page.evaluate(function() {
                var pos, scroll;
                pos = 0;
                scroll = function() {
                    pos += 250;

                    window.document.body.scrollTop = pos;
                    return setTimeout(scroll, 100);
                };
                return scroll();
            });
            return setTimeout((function() {
                console.log(page.content);
                return phantom.exit();
            }), 5000);
        }), 1000);
    }

});

PhantomjsDownloader调用的源代码我也列一下,其实完全可以自己编写


    /**
     * 新增构造函数,支持crawl.js路径自定义,因为当其他项目依赖此jar包时,runtime.exec()执行phantomjs命令时无使用法jar包中的crawl.js
     * <pre>
     * crawl.js start --
     * 
     *   var system = require('system');
     *   var url = system.args[1];
     *   
     *   var page = require('webpage').create();
     *   page.settings.loadImages = false;
     *   page.settings.resourceTimeout = 5000;
     *   
     *   page.open(url, function (status) {
     *       if (status != 'success') {
     *           console.log("HTTP request failed!");
     *       } else {
     *           console.log(page.content);
     *       }
     *   
     *       page.close();
     *       phantom.exit();
     *   });
     *   
     * -- crawl.js end
     * </pre>
     * 具体项目时可以将以上js代码复制下来使用
     *   
     * example:
     *    new PhantomJSDownloader("/your/path/phantomjs", "/your/path/crawl.js");
     * 
     * @param phantomJsCommand phantomJsCommand
     * @param crawlJsPath crawlJsPath
     */
    public PhantomJSDownloader(String phantomJsCommand, String crawlJsPath) {
      PhantomJSDownloader.phantomJsCommand = phantomJsCommand;
      PhantomJSDownloader.crawlJsPath = crawlJsPath;
    }

    /** 中间还有一些框架自带的方法我省略了。。。。大家看一下最主要的方法,这段没有注释,我      解释一下
     *  这个Request类是对URL地址的一层封装,可从中取出下载的url
     *  phantomJsCommand 这个phantomjs安装的路径
     *  crawlJsPath js文件的路径
     */
protected String getPage(Request request) {
        try {
            String url = request.getUrl();
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec(phantomJsCommand + " " + crawlJsPath + " " + url);
            InputStream is = process.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            StringBuffer stringBuffer = new StringBuffer();
            String line;
            while ((line = br.readLine()) != null) {
                stringBuffer.append(line).append("\n");
            }
            return stringBuffer.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值