• PHP如何采集网站数据


    需求:

      对于刚搭建的网站,数据比较单一,那么如何采集点数据呢。

    前言:

      这里我们可以用PHP写的一个框架QueryList,官网文档:http://www.querylist.cc/docs/guide/v4/overview;

    说明:

      如果你之前没有做过数据采集,希望快速的理解,和入门。那么下面的文字可以给你带来帮助。

    什么是数据采集:

      数据采集就是通过代码,模拟浏览器请求,将第三方网站上资源(图片资源,文字资源),采集到本地。简而言之,比如有一个线上的博客网站,你自己也搭建了一个网站,但是没有博客怎么办。一般你可以通过复制粘贴,搬运到自己的网站上。所谓的数据采集,就是通过代码实现刚才的操作流程。

    核心处理点:

      这里使用代码操作,主要就是两块:

        一个是,如何按规则选中我们要采集的网站字段;这个主要是用 DOM内容选择:CSS选择器

        一个是,如何将选中的数据采集下来;这个就是通过 HTTP客户端:GuzzleHTTP

      简而言之,代码主要是用css选择器按规则,选中需要采集的数据,然后用模拟HTTP客户端请求,采集数据。

    我们要做什么:

      现在,我们要将一个第三方网站的数据,采集下来,然后写入到自己数据库中。

    我们大致怎么做:

      步骤一,按官方文档,在自己项目(这边项目是用tp6.0搭建的项目)中安装QueryList扩展;

      步骤二,采集博客列表,然后循环列表,采集列表详情,而后将详情里面的图片下载到本地,最后对数据进行处理,自己需要哪些字段就存取哪些字段;

      步骤三,对上面的数据进行格式化后,写入到自己数据库中;

    上代码:

      1、在ThinkPHP6.0项目中通过Composer安装QueryList扩展

    composer require jaeger/querylist

      2、DataCj.php控制器中引入 use QL\QueryList类,按步骤处理,用redis做数据中转,最后拿到具体格式数据。对于选择器的使用具体见QueryList文档。

    <?php
    /*
     * @Fun: 数据采集
     * @User: JessieK
     * @Date: 2021-11-03 15:50:22
     */
    
    namespace app\v1\controller;
    
    use think\Request;
    use QL\QueryList;
    use think\facade\Cache;
    use think\facade\Db;
    use lib\XFace;
    use think\Model;
    class DataCj
    {
        protected $api_url;//接口域名
    
        public function __construct()
        {
            $host = 1;//环境切换 1:test环境;2:prod环境
            if($host == 1){
                $this->api_url = 'https://a.cn';
            }else{
                $this->api_url = 'https://b.cn';
            }
        }
    
        /**
         * @name: 采集寻找朋友数据 列表
         * @param {Request} $request
         * @return {*}
         */    
        public function xunrenla_xunzhaopengyou(Request $request)
        {
            $page = $request->param('page', 1);
            $renewal = $request->param('renewal', 0);
            //放入缓存
            $redis = Cache::store('redis');
            $key = $request->action() .'_'. $page;
            $data_list = $redis->get($key);
            if(!$data_list || $renewal){
                //采集网址
                $url = 'http://www.xunrenla.com/xunzhaopengyou/list_6_'. $page .'.html';
                //元素采集规则
                $rules = [
                    //姓名
                    'name' => ['.siteContent a', 'title'],
                    //详情地址
                    'url' => ['.siteContent a', 'href'],
                    //图片地址
                    'img' => ['.siteImg img', 'src'],
                ];
                //切片选择器,选择列表范围
                $range = '.layui-col-md8 .layui-card-body>div';
                //开始采集
                $rt = QueryList::get($url)->rules($rules)->range($range)->queryData();
                $rt_key = count($rt) - 1;
                unset($rt[$rt_key]);
                // d($rt);
                $res = $redis->set($key, $rt, 2592000);
                echo '开始写入缓存'.$res;
                exit('写入缓存,数量值='.$rt_key);
            }else{
                exit('已有缓存,数量值='. count($data_list));
            }
        }
    
        /**
         * @name: 采集寻找朋友数据 下载图片到本地
         * @param {Request} $request
         * @return {*}
         */    
        public function xunrenla_xr(Request $request)
        {
            $page = $request->param('page', 1);
            $key = 'xunrenla_xunzhaopengyou_'. $page;
            //取的缓存里面的数据
            $redis = Cache::store('redis');
            $xr_list = $redis->get($key);
            if($xr_list){
                lg('已取出,开始处理图片='. count($xr_list));
                //定义图片存放路径
                $img_path = runtime_path() . 'xrl_img/';
                $time = time();
                foreach($xr_list as $key => $value){
                    //判断图片地址是否存在
                    if(strstr($value['img'], 'http')){
                        $img_string = file_get_contents($value['img']);
                        lg('准备下载会员='.$value['name']);
                        //保存图片
                        $name = md5($value['name'] . $time . $key).'.jpg';
                        $img_name = $img_path . $name;
                        $put_res = file_put_contents($img_name, $img_string);
                        lg('下载结果='.$put_res);
                        //追加路径
                        $xr_list[$key]['img_path'] = $img_name;
                    }else{
                        //删除图片不存在的
                        unset($xr_list[$key]);
                        lg('当前图片路径不存在,跳过');
                    }
                }
                lg('准备写入缓存,实际下载数量='.count($xr_list));
                $res = $redis->set($request->action() . '_'. $page, $xr_list, 2592000);
                exit('处理完成res='.$res);
            }else{
                exit('暂无数据');
            }
        }
        
        /**
         * @name: 图片上传 test服务器
         * @param {Request} $request
         * @return {*}
         */    
        public function xunrenla_upd_img(Request $request)
        {
            $page = $request->param('page', 1);
            $key = 'xunrenla_xr_'. $page;
            //取的缓存里面的数据
            $redis = Cache::store('redis');
            $xr_list = $redis->get($key);
            if(!$xr_list){
                exit('暂无数据');
            }
            $upd_key = $request->action() . '_'. $page;
            $upd_value = $redis->get($upd_key);
            if($upd_value){
                exit('已处理'.count($upd_value));
            }
            lg('开始处理图片,待处理数='.count($xr_list));
            foreach($xr_list as $key => $value){
                //获取图片base64字符
                $base_sting = imgToBase64($value['img_path']);
                if($base_sting){
                    lg('获取图片base64字符成功name'.$value['name']);
                    lg('准备上传test服务器');
                    $https_res = httpCurl($this->api_url . '/index/baseStringApi', ['chars' => $base_sting, 'filename' => md5($value['name'])], 1);
                    if($https_res && $https_res['code'] == 200){
                        lg('上传成功path='.$https_res['data']['path']);
                        $xr_list[$key]['test_img_path'] = $https_res['data']['path'];//追加到新元素
                    }else{
                        unset($xr_list[$key]);
                        lg('上传失败https_res='.$https_res['msg']);
                    }
                }else{
                    unset($xr_list[$key]);
                    lg('获取图片base64失败');
                }
            }
            lg('准备写入缓存,实际上传数='.count($xr_list));
            $res = $redis->set($upd_key, $xr_list, 2592000);
            exit('处理完成res='.$res);
        }
    
        /**
         * @name: 采集寻人朋友 列表详情
         * @param {Request} $request
         * @return {*}
         */    
        public function xunrenla_details(Request $request)
        {
            $page = $request->param('page', 1);
            $key = 'xunrenla_upd_img_'. $page;
            //取的缓存里面的数据
            $redis = Cache::store('redis');
            $xr_list = $redis->get($key);
            if(!$xr_list){
                exit('暂无数据');
            }
    
            foreach($xr_list as $key => $value){
                $ql = QueryList::get($value['url']);
                lg('开始采集详情='.$value['name']);
                $rt = [];
                $rt['name'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(1)')->text(), ':');
                $rt['sex'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(2)')->text(), ':');
                $rt['age'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(3)')->text(), ':');
                $rt['lost_time'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(4)')->text(), ':');
                $rt['jg'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(5)')->text(), ':');
                $rt['szdd'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(6)')->text(), ':');
                $rt['sg'] = jq_zq(jq_zh($ql->find('.layui-col-md9 li:nth-child(7)')->text(), ':'), 'C');
                $rt['lxr'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(9)')->text(), ':');
                $rt['ph'] = jq_zq(jq_zh($ql->find('.layui-col-md9 li:nth-child(10)')->text(), ':'), '提');
    
                $rt['fp'] = jq_zh($ql->find('.layui-col-md8 .layui-hide-xs')->text(), ':');
                
                $rt['ms'] = jq_zh($ql->find('.article-content div:nth-child(1) p')->text(), ':');
                //数组详情追加
                $xr_list[$key]['detaile'] = $rt;
            }
    
            lg('采集完成,准备写入缓存');
            $res = $redis->set($request->action() . '_'. $page, $xr_list, 2592000);
            exit('处理完成res='.$res);
        }
    
        /**
         * @name: 对采集数据进行清洗,格式化经纬度
         * @param {Request} $request
         * @return {*}
         */    
        public function xunrenla_data_up(Request $request)
        {
            $page = $request->param('page', 1);
            $key = 'xunrenla_details_'. $page;
            //取的缓存里面的数据
            $redis = Cache::store('redis');
            $xr_list = $redis->get($key);
            if(!$xr_list){
                exit('暂无数据');
            }
            $upd_key = $request->action() . '_'. $page;
            $upd_value = $redis->get($upd_key);
            // d($upd_value);
            if($upd_value){
                exit('已处理'.count($upd_value));
            }
            // d($xr_list);
            lg('开始处理数据,待处理数='.count($xr_list));
            $data_list = [];
            foreach($xr_list as $key => $value){
                //解析地址
                lg('准备解析地址');
                $dzz = str_replace(' ', '', $value['detaile']['jg']);
                $addres_res = XFace::showLocation($dzz);
                if($addres_res['status']){
                    lg('地址解析失败,res='.$addres_res['msg']);
                    unset($xr_list[$key]);
                }else{
                    lg('解析成功,res='.$addres_res['msg']);
                    $data_list[$key]['member_id'] = 8;//会员uid
                    $data_list[$key]['member_name'] = '人人寻客服-小寻';//会员昵称
                    $data_list[$key]['member_headr'] = 'https://thirdwx.qlogo.cn/mmopen/vi_32/IxNUxicGvfiaibrSkUd9wMYibhOicua4icbwNUr8VQKKePQTnpUxxUL9kYTRBakq2Nsg9QxJVx4gpM5FHbibrOFloJwKQ/132';//会员头像
                    $data_list[$key]['lost_type'] = 1;//寻人类型,0找亲人,1帮忙找',
                    // $data_list[$key]['title'] = $value['name'];//寻人标题
                    $data_list[$key]['name'] = $value['name'];//姓名
                    if($value['detaile']['sex'] == '男'){//性别(1男,2女
                        $data_list[$key]['sex'] = 1;
                    }else{
                        $data_list[$key]['sex'] = 2;
                    }
                    $data_list[$key]['age'] = getAge(strtotime($value['detaile']['age']));//年龄
                    $data_list[$key]['height'] = $value['detaile']['sg'];//身高
                    $data_list[$key]['face_img'] = $value['test_img_path'];//图片
                    // $data_list[$key]['phone'] = '';//手机号id
                    // $data_list[$key]['lost_trait'] = $value['detaile']['ms'];//外貌特征
                    $data_list[$key]['lost_time'] = strtotime($value['detaile']['lost_time'] . '14:35');//走失时间
    
                    $data_list[$key]['lost_lon'] = $addres_res['data']['lon'];//走失地点(经度',
                    $data_list[$key]['lost_lat'] = $addres_res['data']['lat'];//走失地点(纬度'
    
                    // $data_list[$key]['address'] = $value['detaile']['szdd'];//具体位置(通过经纬度解析)
                    // $data_list[$key]['province_id'] = 1;//省id',
                    // $data_list[$key]['city_id'] = 1;//市id',
                    // $data_list[$key]['district_id'] = 1;//区id',
    
                    $data_list[$key]['address_detail'] =$dzz;//详细地址(预留字段',
                    $data_list[$key]['describe'] = str_replace(' ', '', $value['detaile']['ms']);//走失描述
                    $data_list[$key]['insert_time'] = strtotime($value['detaile']['fp']);//创建时间
                    $data_list[$key]['make_type'] = 2;//创建类型(1会员发布,2采集发布,默认为1',
                    $data_list[$key]['m_phone'] = $value['detaile']['ph'];//采集发布,手机号',
                    $data_list[$key]['laiyuan'] = '寻人啦www.xunrenla.com';//来源
                }
            }
            lg('采集完成,准备写入缓存,实际写入数='.count($data_list));
            $res = $redis->set($upd_key, $data_list, 2592000);
            exit('处理完成res='.$res);
        }
    
        /**
         * @name: 将采集数据 写入test数据库
         * @param {Request} $request
         * @return {*}
         */    
        public function xunrenla_data_insert(Request $request)
        {
            $page = $request->param('page', 1);
            $key = 'xunrenla_data_up_'. $page;
            //取的缓存里面的数据
            $redis = Cache::store('redis');
            $xr_list = $redis->get($key);
            // d($xr_list);die;
            if(!$xr_list){
                exit('暂无数据');
            }
            $debug = $request->param('debug', 0);
            if($debug != 99){
                d($xr_list);
                die;
            }
            lg('开始组装数据');
            $inser_data = [];
            foreach($xr_list as $key => $value){
                //组装数据
                $time = time();
                $pj_data = [
                    'name' => $value['name'],
                    'sex' => $value['sex'],
                    'age' => $value['age'],
                    'height' => $value['height'],
                    'face_img' => $value['face_img'],
                    // 'phone' => $data['phone'],
    
                    'member_id' => $value['member_id'],
                    'member_name' => $value['member_name'],
                    'member_headr' => $value['member_headr'],
    
                    'lost_type' => $value['lost_type'],
                    // 'title' => $data['title'],
                    // 'lost_trait' => $value['describe'],//外貌特征
                    'lost_time' => $value['lost_time'],
                    'lost_lon' => $value['lost_lon'],//经度
                    'lost_lat' => $value['lost_lat'],//纬度
                    'address_detail' => $value['address_detail'],//详细位置
                    // 'address' => $adres_res['data']['formatted_address'],//具体地址(经纬度解析
    
                    // 'province_id' => $adres_res['data']['province_id'],
                    // 'city_id' => $adres_res['data']['city_id'],
                    // 'district_id' => $adres_res['data']['district_id'],
                    
                    'describe' => $value['describe'],//走失描述
                    'insert_time' => $time,
                    // 'update_time' => $time,
                    'make_type' => $value['make_type'],
                    'm_phone' => $value['m_phone'],
                    'laiyuan' => $value['laiyuan'],
                ];
                $inser_data[$key] = $pj_data;
                // lg('准备写入数据库name='.$value['name']);
                // $tset_data = Db::table('t_lost_person')->insert($insert_data);
                // lg('写入完成tset_data='.$tset_data);
                // die;
            }
            lg('组装完成,总计inser_data='.count($inser_data));
            lg('准备批量写入数据库');
            $tset_data = Db::table('t_lost_person')->insertAll($inser_data);
            exit('批量写入完成tset_data='.$tset_data);
            // d($inser_data);
        }
    }

    说明:

      以上请在采集的时候,注意网站版权问题,如上代码,仅做学习使用,请勿用作商业用途。


    -----END

    影子是一个会撒谎的精灵,它在虚空中流浪和等待被发现之间;在存在与不存在之间....
  • 相关阅读:
    个人总结11
    进度条4,5
    对vivo自带输入法的评价
    个人总结10
    hdu5589Tree
    HDU5213 Lucky
    2018icpcShenYangE
    bzoj3683: Falsita
    cf396C. On Changing Tree
    cf600E. Lomsat gelral
  • 原文地址:https://www.cnblogs.com/camg/p/15516741.html
Copyright © 2020-2023  润新知