PHP_京东数据采集

作者: php飞扬 | 来源:发表于2016-12-15 12:11 被阅读195次

为什么要做数据采集??

我是一个做网站开发的程序员,做一个网站想要我的网站好看,网站内容 充 实,让网站更加漂亮。如果是我们
自己去录入数据,我们可能要去找 很多资料,还需要美工做很多的图片,这样的成本就会很高。
而且现在京东和淘宝商品数据非常的丰富,我们可以直接写一套数据采集器,直接把数据采集到本网站来使用。

下面直接上代码说明如何做采集

采集时要的参数

1.采集的地址。

这里是采集的jd的列表页,最好是列表页的最后一级分类如:http://list.jd.com/list.html?cat=12218,12222,12243
2.采集的数量。
采集的数量要小于翻页的数量,不然多了没有。

采集方法
/**
 * 京东数据的采集
 */
public function jd(){
    //采集的数量
    $number=10;
    //采集的地址
    $url='http://list.jd.com/list.html?cat=12218,12222,12243';
    //实例化采集的类
    $jd= new jd_collect($number);
    //检查url是否有效
    $is_url=$jd->checkListUrl($url);
    if($is_url){
        //给类赋值采集的地址
        $jd->readListPage($url);
        //获取列表页商品的详情页url
        $list=$jd->pickGoodsLinkFromList();
        //采集到的数据数组
        $data=$jd->collect();
        //分类的父级赋值
        $parent_id=0;
        //分类id赋值
        $cate_id=[0,0];
        //判断分类是否存在,添加
        foreach ($data['cat'] as $k=>$v){
            $cate_id[$k]=GoodsCategory::getName(['name'=>$v]);
            if(!$cate_id[$k]){
                $parent_id=GoodsCategory::add([
                    'name'=>$v,
                ]);
                $cate_id[$k]=&$parent_id;
            }
        }
        //对商品进行添加
        foreach($data['item'] as $v){
           $id = Goods::add([
                'name'=>$v['name'],
                'memo'=>$v['name'],
                'sell_price'=>$v['sell_price'],
                'cost_price'=>$v['cost_price'],
                'market_price'=>$v['market_price'],
                'sort'=>50,
                'img'=>$v['img'][0],
                'list_img'=>$v['img'][0],
                'small_img'=>$v['img'][0],
                'store_num'=>100,
                'cate_id'=>$cate_id[0],
                'cate_two_id'=>$cate_id[1],
                'start_time'=>time(),
                'end_time'=>time()+100*24*60*60,
            ]);
           //对商品的图片进行添加
           foreach ($v['img'] as $img){
               GoodsImg::add([
                   'goods_id'=>$id,
                   'image'=>$img,
                   'list_img'=>$img,
                   'small_img'=>$img,
               ]);
           }
        }
    }
}
京东数据采集的操作类
<?php
namespace App\Helpers\JD;
use App\Helpers\JD\collect;
use Psy\Util\Json;
/**
 * @brief 京东商品列表采集器,适用于普通类,不可再分类的列表
 * @author nswe
 * @date 2013/12/25 13:52:19
 */
class jd_collect extends collect
{
    //属性数据
    private $cacheAttrData = array();

    //采集数量
    private $number = 20;
    /**
     * @brief 构造函数
     */
    public function __construct($number=0)
    {
        if($number){
           $this->number=$number;
        }
    }

    /**
     * @brief 检查列表url
     */
    public function checkListUrl($url)
    {
        return strpos($url,'http://list.jd.com/list.html?cat=') === false ? false : true;
    }

    /**
     * @brief 检查详情url
     */
    public function checkShowUrl($url)
    {
        return strpos($url,'http://item.jd.com') === false ? false : true;
    }

    /**
     * @brief 挑选分类
     * @return array 根据层次返回分类
     */
    public function pickCatFromList()
    {
        $catExp = '@<div class="trigger">(.+?)</div>@';
        preg_match_all($catExp,$this->listPageHtml,$match);
        
        if(!isset($match[0]))
        {
            throw new Exception('页面缺少商品分类');
        }
        foreach ($match[1] as $v){
            $data[]=strip_tags($v);
        }
        return $data;
    }

    /**
     * @brief 挑选属性
     * @return array 属性数据
     */
    public function pickAttributeFromList()
    {
        $keyExp   = '@<div class="a-key">(.+?)</div>@';
        $valueExp = '@<ul class="f-list">(.+?)</ul>@';

        preg_match_all($keyExp,$this->listPageHtml,$matchKey);
        preg_match_all($valueExp,$this->listPageHtml,$matchValue);

        if(!isset($matchKey[1]))
        {
            throw new Exception('页面缺少商品属性名称');
        }

        if(!isset($matchValue[1]))
        {
            throw new Exception('页面缺少商品属性数值');
        }

        //过滤无用的数据
        array_shift($matchKey[1]);//移除品牌
        array_shift($matchKey[1]);//移除价格
        array_shift($matchValue[1]);//移除价格

        $attrData = array();
        foreach($matchKey[1] as $key => $val)
        {
            $attrData[trim($val,':')] = trim(strip_tags(strtr($matchValue[1][$key],array('</li>' => '</li>,'))),',');
        }
        return $attrData;
    }

    /**
     * @brief 挑选列表页面的商品连接
     * @return array 商品详情的url
     */
    public function pickGoodsLinkFromList()
    {
        $linkExp ='<a target="_blank" href="//item.jd.com/(.*?).html".*?>';
        preg_match_all($linkExp,$this->listPageHtml,$match);
        if(!isset($match[1]))
        {
            throw new Exception('页面缺少商品详情连接');
        }
        return $match[1];
    }

    /**
     * @brief 获取商品名称从详情页面
     * @return string 商品名字
     */
    public function pickGoodsNameFromShow()
    {
        $exp = '/<h1>([^<>]*)<\/h1>/';
        preg_match($exp,$this->showPageHtml,$match);

        if(!isset($match[0]))
        {
            throw new Exception('没有找到商品名称');
        }
        return strip_tags($match[0]);
    }
    
    /**
     * @brief 获取商品名称从详情页面
     * @return string 商品描述
     */
    public function pickGoodsMemoFromShow()
    {
        $exp = "/<div id=\"p-ad\".*?>.*?<\/div>/ism";
        preg_match($exp,$this->showPageHtml,$match);
        if(!isset($match[0]))
        {
            throw new Exception('没有找到商品名称');
        }
        return strip_tags($match[0]);
    }

    /**
     * @brief 获取商品价格从API
     * @param $idArray string 商品id数组,如:J_970602
     * @return string 商品价格json
     */
    public function getGoodsPriceFromAPI($idString)
    {
//      $apiUrl = 'http://p.3.cn/prices/mgets?skuIds='.trim($idString,',');
        $apiUrl='http://p.3.cn/prices/get?type=1&area=1_72_4137&pdtk=HxOK%2F%2B%2Fwpjlr75zX3szVoe%2BWRMfuWsRCxWZRS2x7B84nzLc1bJwTzqlQm2fSRjIk&pduid=844111226&pdpin=&pdbp=0&skuid='.trim($idString,',');
        $result = file_get_contents($apiUrl);
        $result = strtr($result,array('J_' => ''));
        return json_decode($result,true);
    }

    /**
     * @brief 获取商品属性从详情页面
     * @return string 商品某属性
     */
    public function pickGoodsAttributeFromShow()
    {
        $exp = '@<ul class="detail-list">(.+?)</ul>@s';
        preg_match($exp,$this->showPageHtml,$match);
        return $this->cacheAttrData=[];
        if(!isset($match[1]))
        {
            throw new Exception('没有找到商品属性');
        }

        $match[1] = trim(strip_tags(strtr($match[1],array('<li>' => '</li>,'))));
        $tempArray = explode(',',$match[1]);

        $attrArray = array();
        $tmp = array();
        foreach($tempArray as $key => $val)
        {
            $tmp = explode(':',$val);
            $attrArray[$tmp[0]] = trim($tmp[1]);
        }
        return $this->cacheAttrData = $attrArray;
    }

    /**
     * @brief 获取商品图片从详情页面
     * @return array 商品的图片url
     */
    public function pickGoodsImageFromShow()
    {
        $exp='<img.+data-url=\'(.*?)\'.+>';
        preg_match_all($exp,$this->showPageHtml,$match);
        if(!isset($match[1]) || !is_array($match[1]))
        {
            throw new Exception('没有找到商品图片');
        }

        $jdImageServerPre = 'http://img13.360buyimg.com/n0/';
        foreach($match[1] as $key => $val)
        {
            $match[1][$key] = $jdImageServerPre.$val;
        }
        return $match[1];
    }

    /**
     * @brief 获取商品规格从详情页面
     * @return array 商品的规格 array(规格名称=>规格值)
     */
    public function pickGoodsSpecFromShow()
    {
        $exp = '@<li id="choose-(?:version|color)".*?>.*?</li>@s';
        preg_match_all($exp,$this->showPageHtml,$match);

        $result = array();
        if(isset($match[0]) && $match[0])
        {
            foreach($match[0] as $key => $val)
            {
                $val = trim(strip_tags(strtr($val,array('</a>' => '</a>,'))),',');
                $temp = explode(':',$val);

                if(isset($temp[1]))
                {
                    $result[$temp[0]] = $temp[1];
                }
            }
        }
        return $result;
    }

    /**
     * @brief 获取商品详情从详情页面
     * @return string 商品的详情数据
     */
    public function pickGoodsContentFromShow()
    {
        $exp = '@<div class="detail-content">.*<!--product-detail end-->@s';
        preg_match($exp,$this->showPageHtml,$match);
        if(!isset($match[0]))
        {
            throw new Exception('没有找到商品详情');
        }
        return strtr($match[0],array('data-lazyload' => 'src'));
    }

    /**
     * @brief 获取商品重量
     * @return string 商品重量
     */
    public function pickGoodsWeightFromShow()
    {
        if(!$this->cacheAttrData)
        {
            $this->pickGoodsAttributeFromShow();
        }
        preg_match('@[\d\.]+@',$this->cacheAttrData['商品毛重'],$matchAttr);
        return isset($matchAttr[0]) ? $matchAttr[0] : 0;
    }

    /**
     * @brief 获取商品计量单位
     * @return string 计量单位
     */
    public function pickGoodsUnitFromShow()
    {
        if(!$this->cacheAttrData)
        {
            $this->pickGoodsAttributeFromShow();
        }
        preg_match('@[\d\.]+(.*)$@',$this->cacheAttrData['商品毛重'],$matchAttr);
        return isset($matchAttr[1]) ? $matchAttr[1] : '千克';
    }

    /**
     * @brief 开始采集商品
     * @return array('cat' => '商品分类','attr' => '属性','item' => array(
     * 'goods_no' => '商品编号','up_time' => '上架时间','weight' => '重量','unit' => '计量单位','name' => '商品名字','price' => '商品价格','img' => array(商品图片),'content' => '商品详情','spec' => '商品规格','attr' => '商品属性'
     * ))
     */
    public function collect()
    {
        $result = array(
            'cat' => $this->pickCatFromList(),
//          'attr'=> $this->pickAttributeFromList(),
            'item'=> array()
        );
        $goodsUrl = $this->pickGoodsLinkFromList();
        //取列表页商品的数量
        $goodsUrl=array_slice($goodsUrl,0,$this->number);
        foreach($goodsUrl as $key => $val)
        {
            $showurl='http://item.jd.com/'.$val.'.html';
            $this->readShowPage($showurl);
            preg_match('@\d+@',$val,$match);
            $priceObj = $this->getGoodsPriceFromAPI('J_'.$match[0]);
//          $attrData = $this->pickGoodsAttributeFromShow();
            $result['item'][] = array(
//              'goods_no' => $attrData['商品编号'],
//              'up_time'  => $attrData['上架时间'],
//              'weight' => $this->pickGoodsWeightFromShow(),
//              'unit'   => $this->pickGoodsUnitFromShow(),
                'name'   => $this->pickGoodsNameFromShow(),
                'sell_price'  => $priceObj[0]['p'],
                'market_price'  => $priceObj[0]['m'],
                'cost_price'  => $priceObj[0]['op'],
                'img'    => $this->pickGoodsImageFromShow(),
//              'content'=> $this->pickGoodsContentFromShow(),
//              'spec'   => $this->pickGoodsSpecFromShow(),
//              'attr'   => $attrData
            );
        }
        
        return $result;
    }
}
采集器抽象类
<?php
namespace App\Helpers\JD;
/**
 * @brief 采集器抽象类
 * @date 2014/1/1 20:21:11
 * @author chendeshan
 */
abstract class collect
{
    //已经采集到的列表页面html代码
    protected $listPageHtml = '';

    //已经采集到的详情页面html代码
    protected $showPageHtml = '';

    /**
     * @brief 获取列表页面的html代码
     * @param $url string 列表页面url地址
     */
    public function readListPage($url)
    {
        if($this->checkListUrl($url) == false)
        {
            throw new Exception('URL不符合规范');
            exit;
        }

        if(!$content = file_get_contents($url))
        {
            throw new Exception('没有采集到列表页面的html代码');
        }

        //转码GBK转换UTF-8
        $this->listPageHtml = $this->converContent($content);
    }

    /**
     * @brief 获取商品详情页面数据
     * @param $url string 详情页面url
     */
    public function readShowPage($url)
    {
        if($this->checkShowUrl($url) == false)
        {
            throw new Exception('URL不符合规范');
            exit;
        }

        $content = file_get_contents($url);

        //转码GBK转换UTF-8
        $this->showPageHtml = $this->converContent($content);
    }

    /**
     * @brief 字符串转码
     * @param $content string 要转换的字符串
     * @return string
     */
    public function converContent($content)
    {
        if($this->isUTF8($content) == false)
        {
            return iconv('GBK','UTF-8//IGNORE',$content);
        }
        return $content;
    }
    public function isUTF8($string)
    {
        $e=mb_detect_encoding($string, array('UTF-8', 'GBK'));
        switch($e){
            case 'UTF-8' : //如果是utf8编码
                return true;
                break;
            case 'GBK': //如果是gbk编码
                break;
        }
    } 
    /**
     * @brief 检查商品列表url的合法性
     * @param $url string
     * @return boolean
     */
    abstract public function checkListUrl($url);

    /**
     * @brief 检查商品详情url的合法性
     * @param $url string
     * @return boolean
     */
    abstract public function checkShowUrl($url);

    /**
     * @brief 采集商品信息
     * @return array
     */
    abstract public function collect();
}

我在本次采集的操作过程中遇到几个问题给总结下。

  • 注意采集来数据的页面的编码格式,要主相应的判断和转换

  • 注意正则的匹配。采集页面有可能调整对应的正则就需要重新。

  • 注意找出那一部分是页面加载的数据,那一部分是ajax加载过来的数据,要分清楚,不如是得不到数据的

这里我们可以用火狐浏览器的firebug来查看,那些数据是可以用正则来匹配的


图片.png
  • 不能用正则匹配的就需要用ajax的请求获得数据如商品详情页商品的价格

这里获取数据的时间我们要注意下,我在做这里的时间第一次直接用http://p.3.cn/prices/mgets?skuIds= 就可以获取数据,但是后面京东需要验证菜返回数据所以我们可以复制firebug中的连接,进行请求就会有数据了。

图片.png
  • 这里我做的商品页的商品详情数据没有找到获取的方法,如果有知道的请分享给我。

相关文章

  • PHP_京东数据采集

    为什么要做数据采集?? 我是一个做网站开发的程序员,做一个网站想要我的网站好看,网站内容 充 实,让网站更加漂亮。...

  • 采集案例二:采集京东商品详情

    采集系列文章 爬虫软件的介绍及案例说明(文章链接) 案例一:采集京东商品列表页数据(文章链接) ▶案例二:采集京东...

  • 爬虫软件的介绍及案例说明

    采集系列文章 ▶爬虫软件的介绍及案例说明(本文) 案例一:采集京东商品列表页数据(文章链接) 案例二:采集京东商品...

  • 采集案例一:采集京东商品列表页数据

    采集系列文章 爬虫软件的介绍及案例说明(文章链接) ▶案例一:采集京东商品列表页数据(本文) 案例二:采集京东商品...

  • 采集案例三:采集京东商品评论

    采集系列文章 爬虫软件的介绍及案例说明(文章链接) 案例一:采集京东商品列表页数据(文章链接) 案例二:采集京东商...

  • 京东数据采集整理标准化流程介绍

    用电商数据采集软件采集过数据的朋友就应该很清楚,我们输入指令通过采集软件将我们需要的淘宝、天猫、京东等平台数据采集...

  • 数据分析京东笔记本电脑

    注:数据来源使用八爪鱼采集器采集京东商城中笔记本的数据,共采集12030条,去除重复、无用数据后剩余5968条,本...

  • 如何采集京东数据

    这里我们浅谈一下如何采集京东数据,我个人比较喜欢是使用安托数据监测系统(pm.antuodata),简单,方便,易...

  • 数据采集:京东阅读

    京东读书 入口(爬取所有的类别链接)选择以jd读书中的在线读书的分类为入口,解析页面获取每个分类的url 爬取每个...

  • Python学习笔记(4)翻页采集列表

    **一、操作步骤。京东的列表网页有很多页,爬虫能不能自动翻页,采集每一页的数据?当然可以,做好翻页采集规则,爬虫就...

网友评论

  • f3276d10c214:我也写过获取商品详情的,不过不太会正则,用了phpquery:smile:
    php飞扬:@f3276d10c214 http://dx.3.cn/desc/商品id?cdn=2 谢谢找到了,有时间我在加进去
    php飞扬:@f3276d10c214 代码的类库我已是在网上找的,中间的一些正则和实现是一边测试一边做了修改
    f3276d10c214:商品详情在源代码匹配desc:后面的链接就是了,好奇一下,你代码的日期是怎么是2014

本文标题:PHP_京东数据采集

本文链接:https://www.haomeiwen.com/subject/kogwmttx.html