源码地址:https://github.com/LeeToug/NewsGather
最近公司需要做一个信息发布网站,任务分配下来之后确定我来主导这个项目。由于之前做小说采集网站的时候多用的是CMS自带的采集系统,但是本人实在不怎么感冒cms,所以在网上查看了一些资料,很神奇的找到了Querylist这个东西,今天就将我昨晚这次项目的里程分享一下。
首先,querylist官网(http://www.querylist.cc),直接点击文档走起。
大概看了一下,可以满足我的需求。okay,thinkphp5框架搭起来,使用composer安装querylist,安装之后本地出现gaegar文件夹,进去之后就会看到querylist了。至此,完成了安装的步骤啦,就是这么简单!!!
接下来就是使用Querylist类啦,一步一步来走:
首先引入类
use QL\QueryList;
然后重点
$html = "http://www.***.com";
//选择大的区域
$selector = "body";
//获取当前所选区域html
$content=QueryList::get($html)->find($selector)->html();
//最外层规则筛选
$rules = array(
'plist' => ['dt','html']
);
//获取分类数据、处理/采集数据
$data = $this->dealData($content,$rules);
$html是你要采集的目标站点,$content是获取到的html页面源码,$rules是即将要用的筛选规则。主要看一下处理数据的方法dealData();
public function dealData($content,$rules){
$data = QueryList::html($content)->rules($rules)->range('')->queryData(function ($item){
$item = QueryList::html($item)->rules(array(
'title' => array('a','text'),
'original_link' =>array('a','href')
))->range('')->queryData();
return $item;
});
return $data;
}
该方法中由于我要采集的目标站需要两层进去,所以又写了一次内部回调。将之前获取到的页面源码$content放入html()方法中去,使用rules()方法匹配dt标签中的html源码,range()方法是分片的,我这里没有用到,就留空,但是这个方法一定要写在这儿。在回调中,将之前获取到的html源码定在在$item中,然后进行二次rule规则筛选,将原站中的标题与链接采集到,此时的$item中就已经保存了我们想要的数据了,然后我们就可以将数据存库或是做其他处理了。
至此,一次简单的采集就完成了。
后附多线程采集的源码,原理与上面一样,需要注意的是,多线程采集时,需要引入对应的类,看下,如果大家有需要的话,我会再写一篇关于querylist多线程采集的文章。
use QL\QueryList;
use QL\Ext\CurlMulti;
use think\Db;
class Gather extends Admin
{
/**
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* 采集文章信息
* @author lyf
* @date 2019-5-10
*/
public function index(){
$param=$this->request->get();
$ql = QueryList::getInstance();
$ql->use(CurlMulti::class);
$htmls = array();
$map['status'] = 0;
$html = Db::name('city_cate_url')
->where($map)
->order("id","ASC")
->limit("0","10")
->select();
foreach ($html as $item){
$url = explode('/',$item['url']);
$link = explode('.',$url[3]);
$htmls[] = $url[0].'//'.$url[2].'/'.$link[0].'P'.$item['page'].'.'.$link[1];
}
$data = $this->gather($htmls,$ql);
$ids=array_column($html,"id");
$res_list=db("city_cate_url")
->where("id","in",$ids)
->where('status','-1')
->select();
$k=0;
if($htmls){
$k++;
if($res_list){
$this->success("正在采集第{$k}次","gather/index","",60);
}else{
$this->success("正在采集第{$k}次","gather/index","",30);
}
}else{
$this->success("采集成功");
}
}
/**
* @param $html
* @param $city_name
* @param $cate_name
* @param $num
* @return string
* 采集列表信息
* @author lyf
* @date 2019-5-8
*/
public function gather($html,$ql){
$ql->curlMulti($html)->success(function (QueryList $ql,CurlMulti $curl,$r){
// echo $r['info']['url'];echo "
";
//初始化
$content1 = '';
$content2 = '';
//获取城市ID
$city = explode('/',$r['info']['url']);
$cityId = $this->getCityId($city[0].'//'.$city[2].'/');
$msg = '';
$selector1 = "#main";
$selector2 = "tbody";
try{
$content1=$ql->get($r['info']['url'])->find($selector1)->html();
$content2=$ql->get($r['info']['url'])->find($selector2)->html();
}catch(\Exception $e) {
}
$rules = [
'title' => ['.t>div>a','title'],
'original_link' => ['.t>div>a','href'],
'img' => ['.i>a>img','src'],
'brief' => ['.t>div','html','-#wrapv1'],
'price' => ['.p','text'],
'date' => ['.u','text']
];
if($content1&&$content2){
//处理数据信息
$data = $this->dealData($content2,$rules,$ql,$cityId,$r['info']['url']);
//数据入库
if($data){
$res = $this->saveData($data,$r['info']['url']);
}
}
else if($content1&&!$content2){
$this->endNow($r['info']['url'],$status='1');
}else{
$this->endNow($r['info']['url'],$staus='-1');
}
$ql->destruct();
})->start([
// 最大并发数,这个值可以运行中动态改变。
'maxThread' => 10,
// 触发curl错误或用户错误之前最大重试次数,超过次数$error指定的回调会被调用。
'maxTry' => 3,
// 全局CURLOPT_*
'opt' => [
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 1,
CURLOPT_RETURNTRANSFER => true
]
]);
}
源码地址:git:https://github.com/LeeToug/NewsGather
第一次在这边发博客,大家有什么不满意的地方,可以随时指正,也希望大家多多包涵。有问题随时可以私我,看到的话一定会回复哒