使用phpQuery进行采集数据,模拟curl提升访问速度
使用php采集网页数据一般有多种方法,有时候会使用正则去采集页面,但是当我们需要采集的页面大并且多的话,会严重的浪费我们的cpu,这时候我们可以使用phpQuer来进行采集,不知道phpQuery的童鞋可以去看看这是东西
以采集 http://www.rsq111.com/goods.php?id=15663 这个网站为例
假设我们需要采集商品的 分类 名称 价格 货号 上架时间 商品图片 详情图片
1.首先下载phpQuery类 phpQuery.php
2.接下里我们可以新建一个cj.php类
单页面采集
<?php
header("Content-Type: text/html; charset=UTF-8");
require("phpQuery.php"); //引入类
//检测当前链接是否合法
$url = 'http://www.rsq111.com/goods.php?id=15663';
$header_info=getHeaders($url,true);
if ($header_info != ) {
die;
}
phpQuery::newDocumentFile($url); //获取网页对象内容
//pq() == $(this)
// 商品分类
$arr_check = pq(".breadcrumb");
foreach ($arr_check as $li) {
$cat = pq($li)->text();
}
$category = explode('>', $cat);
//商品标题
$h1_check = pq("#name");
$title = pq($h1_check)->text();
//商品价格
$price_check = pq(".rmbPrice");
$shop_price = [];
foreach ($price_check as $li) {
$shop_price[] = pq($li)->text();
}
$shop_price = array_pop($shop_price);
$shop_price = explode(':', $shop_price);
$price = $shop_price[];
//商品参数
$prame_check = pq("#summary1 .dd");
$prame = [];
foreach ($prame_check as $li) {
$prame[] = pq($li)->text();
}
$sn = $prame[];//货号
$brank = $prame[];//品牌
$time = $prame[];//上架时间
// 商品图片
$prame_photo_check = pq("#goods_gallery a");
$photo = [];
foreach ($prame_photo_check as $li) {
$src = 'http://www.rsq111.com/'.pq($li)->attr('href');//图片路径
//注释代码为保存图片路劲,下载图片到本地
$localSrc = 'w/'.md5($src).'.jpg';
// $stream = file_get_contents($src);
// file_put_contents($localSrc,$stream);
// pq($li)->attr('src',$localSrc);
$photo[] = $localSrc;
}
//商品详情图片
$info_photo_check = pq(".detail-content img");
$info_photo = [];
foreach ($info_photo_check as $li) {
$src = 'http://www.rsq111.com/'.pq($li)->attr('src');
$localSrc = 'w/'.md5($src).'.jpg';
// $stream = file_get_contents($src);
// file_put_contents($localSrc,$stream);
// pq($li)->attr('src',$localSrc);
$info_photo[] = $localSrc;
}
$data= [
'title' => $title,
'category1' => $category[],
'category2' => $category[],
'category3' => $category[],
'price' => $price,
'sn' => $sn,
'brank' => $brank,
'time' => $time,
'photo' => $photo,
'info_photo' =>$info_photo,
];
}
echo "<pre>";
print_r($data);
//检测url是否合法
function getHeaders($url,$data=FALSE){
$_headers = get_headers($url,);
if( !$data ){return $_headers;}
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$url);//获取内容url
curl_setopt($curl,CURLOPT_HEADER,);//获取http头信息
curl_setopt($curl,CURLOPT_NOBODY,);//不返回html的body信息
curl_setopt($curl,CURLOPT_RETURNTRANSFER,);//返回数据流,不直接输出
curl_setopt($curl,CURLOPT_TIMEOUT,); //超时时长,单位秒
curl_exec($curl);
$rtn= curl_getinfo($curl,CURLINFO_HTTP_CODE);
curl_close($curl);
return $rtn;
}
这样的话就可以采集到这页面的数据了,但是如果我们需要采集的数据页面比较多,比如上万条数据的话,我们用这种方式速度会很慢
多页面采集
如果我们直接循环去获取页面的,这样每个页面都需要访问一次,并且抓取数据,耗时耗性能,这是我们可以有多种方案来优化提升速度
a.使用curl模拟多线程,将网页一次性全部抓取回来,保存到本地进行采集,避免了重复请求,造成的开销
b.使用swoole,创建多个线程,来进行采集,比如当我们去采集10个页面的时候,耗时10秒,这时候我们创建多个线程,同事去请求分配出去的url,则可以提升我们的速度
c.当然,如果我们对数据要求性低,我们可以借助第三方软件,比如八爪鱼,火车,这些工具,可以更加快速的采集到需要的数据
笔者在这里采用的是第一种方法,因为是windows环境,swoole的话,windows安装有点麻烦
我采用的是ajax轮询,每次10条,比如我们从商品id为1的数据开始采集
phpcj.php
<?php
//获取开始采集的id
$start_id = $_POST['start_id'];
$end_id = $start_id+; //每次加10条 if(empty($start_id) || empty($end_id)){
exit(json_encode(['status'=>,'msg'=>'参数不正确']));
}
$pdo = new PDO('mysql:host=数据库地址;dbname=数据库名','用户','密码',array(PDO::ATTR_PERSISTENT)); header("Content-Type: text/html; charset=UTF-8");
require("phpQuery.php");
//将要采集的地址全部循环出来
for ($i=$start_id; $i < $end_id; $i++) {
$urls[$i] = 'http://www.rsq111.com/goods.php?id='.$i;
}
//判断当前url是否合法,这里我判断的是第一条
$code = getHeaders(array_shift($urls),true);
if($code != ){
//如果不合法,返回结束id,重新开始执行
exit(json_encode(['status'=>,'msg'=>'当前id无商品','end_id'=>$end_id]));
}
$save_to='test.txt'; // 把抓取的代码写入该文件
$st = fopen($save_to,'w+'); $mh = curl_multi_init();
foreach ($urls as $i => $url) {
$conn[$i] = curl_init($url);
curl_setopt($conn[$i], CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)");
curl_setopt($conn[$i], CURLOPT_HEADER ,);
curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT,);
curl_setopt($conn[$i],CURLOPT_RETURNTRANSFER,true); // 设置不将爬取代码写到浏览器,而是转化为字符串
curl_multi_add_handle ($mh,$conn[$i]);
} do {
curl_multi_exec($mh,$active);
} while ($active); foreach ($urls as $i => $url) {
file_put_contents($save_to, '');
$data = curl_multi_getcontent($conn[$i]); // 获得爬取的代码字符串
file_put_contents($save_to, $data); //将抓取到的野蛮写入到文件中
$data = cj($i);
if ($data) {
$add[$i] = $data;
}
}
foreach ($urls as $i => $url) {
curl_multi_remove_handle($mh,$conn[$i]);
curl_close($conn[$i]);
} curl_multi_close($mh);
fclose($st); //将采集成功的数据存入数据库
$sql = '';
if(!empty($add))
{
foreach ($add as $key => $value) {
$title = str_replace("'","",$value['title']);
$category1 = $value['category1'];
$category2 = $value['category2'];
$category3 = $value['category3'];
$price = $value['price'];
$sn = $value['sn'];
$brank = $value['brank'];
$time = $value['time'];
$photo = $value['photo'];
$info_photo = $value['info_photo'];
$cj_id = $end_id; $sql[] = "('$title','$category1','$category2','$category3','$price','$sn','$brank','$time','$photo','$info_photo','$cj_id')"; }
$sqls =implode(',', $sql);
$add_sql = "INSERT into phpcj (title,category1,category2,category3,price,sn,brank,time,photo,info_photo,cj_id) VALUES ".$sqls;
$res = $pdo->exec($add_sql);
if(!$res) {
//采集未成功,返回id,重新开始采集
exit(json_encode(['status'=>,'msg'=>'本次采集未成功..','start_id'=>$start_id]));
}else{
//采集成功,将最后一条数据返回,用作下此次执行的开始id
exit(json_encode(['status'=>,'msg'=>'采集成功,正在进行循环采集..','end_id'=>$end_id]));
}
} //采集方法
function cj($i)
{
$url = 'http://www.***.com/test.txt'; //页面存取的文本路劲
phpQuery::newDocumentFile($url);
// 分类
$arr_check = pq(".breadcrumb");
foreach ($arr_check as $li) {
$cat = pq($li)->text();
}
if(empty($cat)){
return;
}
$category = explode('>', $cat); //标题
$h1_check = pq("#name");
$title = pq($h1_check)->text(); //价格
$price_check = pq(".rmbPrice");
$shop_price = [];
foreach ($price_check as $li) {
$shop_price[] = pq($li)->text();
}
$shop_price = array_pop($shop_price);
$shop_price = explode(':', $shop_price);
$price = $shop_price[]; //参数
$prame_check = pq("#summary1 .dd");
$prame = [];
foreach ($prame_check as $li) {
$prame[] = pq($li)->text();
} $sn = $prame[];//货号
if(count($prame) > ){
$brank = $prame[];//品牌
$time = $prame[];//上架时间
}else{
$brank = '无';
$time = $prame[];//上架时间
} // 商品图片
$prame_photo_check = pq("#goods_gallery a");
$photo = [];
foreach ($prame_photo_check as $li) {
$src = 'http://www.rsq111.com/'.pq($li)->attr('href');
// $localSrc = 'w/'.md5($src).'.jpg';
// $stream = file_get_contents($src);
// file_put_contents($localSrc,$stream);
// pq($li)->attr('src',$localSrc);
// $photo[] = $localSrc;
$photo[] = $src;
}
$photo =json_encode($photo); //商品详情图片
$info_photo_check = pq(".detail-content img");
$info_photo = [];
foreach ($info_photo_check as $li) {
$src = 'http://www.rsq111.com/'.pq($li)->attr('src');
// $localSrc = 'w/'.md5($src).'.jpg';
// $stream = file_get_contents($src);
// file_put_contents($localSrc,$stream);
// pq($li)->attr('src',$localSrc);
// $info_photo[] = $localSrc;
$info_photo[] = $src;
}
$info_photo = json_encode($info_photo);
//如果商品没有三级分类,给他赋值为空
if(count($category) < ){
$category[] = '';
}
$data = [
'title' => $title,
'category1' => $category[],
'category2' => $category[],
'category3' => $category[],
'price' => $price,
'sn' => $sn,
'brank' => $brank,
'time' => $time,
'photo' => $photo,
'info_photo' =>$info_photo,
'cj_id' => $end_id,
];
return $data; } //判断url是否合法
function getHeaders($url,$data=FALSE){
$_headers = get_headers($url,);
if( !$data ){return $_headers;}
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$url);//获取内容url
curl_setopt($curl,CURLOPT_HEADER,);//获取http头信息
curl_setopt($curl,CURLOPT_NOBODY,);//不返回html的body信息
curl_setopt($curl,CURLOPT_RETURNTRANSFER,);//返回数据流,不直接输出
curl_setopt($curl,CURLOPT_TIMEOUT,); //超时时长,单位秒
curl_exec($curl);
$rtn= curl_getinfo($curl,CURLINFO_HTTP_CODE);
curl_close($curl);
return $rtn;
}
这样我们完成了对页面的循环采集
前台代码,使用ajax循环请求(如果,使用服务器定时任务的话,需要注意,对采集不成功的判断,这块我是手动重新填写id,因为采集的因素不可控,也许对方页面错误,对方的数据库出错,但是我们依旧可以正常访问到,所以需要对采集不成功,或者对某个id一直进行采集时,我们要加时效性判断。如果超过多长时间,默认为当前数据采集不成功,则开始下一轮的采集,可以是当前id+1,或者其他规则,总之跳过这个id就可以)
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="text" name="start_id" id="start_id" placeholder="采集开始id">
<!-- <input type="text" name="end_id" id="end_id" placeholder="采集结束id"> -->
<input type="button" id="btn" value="开始采集">
<h5 id="zhi"></h5>
<input type="text" id="ids" placeholder="采集返回成功条数">
</body>
</html>
<script type="text/javascript" src="./jquery.min.js"></script>
<script>
$('#btn').click(function(){
var startid = $('#start_id').val();
cj(startid)
}) function cj(startid)
{
var ids = $('#ids').val();
if (ids) {
startid = ids;
} $('#zhi').html('采集中...');
var urls = "http://wlkx.oeob.net/phpcj.php"
$.ajax({
type: "post",
url: urls,
dataType:'json',
data: {"start_id":startid},
success : function(res){
console.log(res)
$('#zhi').html('');
if(res.status == ){
$('#zhi').html(res.msg);
$('#ids').val(res.start_id);
}else{
$('#zhi').html(res.msg);
$('#ids').val(res.end_id);
setTimeout(cj,*);
} } });
} </script>
使用phpQuery进行采集数据,模拟curl提升访问速度的更多相关文章
- js优化提升访问速度
一.给JS文件减肥. 有的人为了给网站增加炫目效果,往往会使用一些JS效果代码,这在上个世纪似乎还很流行,对于现在来说,最好在用户体验确实需要的情况下,使用这些东西.至于希望给自己的JS文件减肥的童鞋 ...
- 使用Gzip压缩数据,加快页面访问速度
在返回的json数据量大时,启用Gzip压缩,可以提高传输效率.下面为Gzip压缩对json字符串压缩并输出到页面的代码. 一.代码 /** 向浏览器输出字符串响应数据,启用 ...
- [技巧篇]00.TrimFilter去掉jsp页面空白,提升访问速度
最近感觉项目访问的速度有点慢,我就在网络中一顿搜索,发下了一个好东东,忍不住跟大家分享,希望大家可以试一试,确实有提升的空间啊!要求去除空白区.提取公用代码.减小页面. 胖先生乱搜之下,找到了Trim ...
- php中CURL实现模拟登录并采集数据
在php中采集我们用的是简单的采集方式(例如file_get_contents)就无法做到了,但是如果想模拟登录用户并采集利用它就没办法了,我们可利用CURL函数来实现模拟登录并采集数据 这里要说一些 ...
- [PHP自动化-进阶]001.CURL模拟登录并采集数据
引言:PHP可以通过libcurl实现模拟登录,提交数据,违法乱纪,烧杀抢虐等等事项. 简单说明一下"libcurl",补一下脑: libcurl目前支持http.https.ft ...
- php curl采集数据问题汇总
1. 使用curl获取网页数据提示: "curl: (6) Could not resolve host: xxx.xxx.com ; Name or service not known&q ...
- php 模拟登陆(不带验证码)采集数据
这里模拟表单登陆窗口 提交代码部分 1,生成session_id保存到 cookie $login_url = 'http://www.96net.com.cn/Login.php';$cookie_ ...
- OCM_第十三天课程:Section6 —》数据库性能调优 _结果缓存 /多列数据信息采集统计/采集数据信息保持游标有效
注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...
- asp.net 模拟CURL调用微信公共平台API 上传下载多媒体文
近公司项目上在开发微信服务号的接口,需要给用户回复图片或语音或视频,这个时候就需要用到 上传下载多媒体文件接口,微信在这方面推荐采用的是开源函数库curl实现的,CURL项目包括很多版本,我主要测试的 ...
随机推荐
- Java实现 LeetCode 232 用栈实现队列
232. 用栈实现队列 使用栈实现队列的下列操作: push(x) – 将一个元素放入队列的尾部. pop() – 从队列首部移除元素. peek() – 返回队列首部的元素. empty() – 返 ...
- java实现SPFA算法
1 问题描述 何为spfa(Shortest Path Faster Algorithm)算法? spfa算法功能:给定一个加权连通图,选取一个顶点,称为起点,求取起点到其它所有顶点之间的最短距离,其 ...
- java实现 猜数字游戏
猜数字游戏 猜数字 很多人都玩过这个游戏:甲在心中想好一个数字,乙来猜.每猜一个数字,甲必须告诉他是猜大了,猜小了,还是刚好猜中了.下列的代码模拟了这个过程.其中用户充当甲的角色,计算机充当乙的角色. ...
- MyBatis整合双数据源
有时候在项目中会遇到需要连接两个数据库的情况.本文就结合Spring和Mybatis来讲下怎么使用双数据源(或者是多数据源). 背景知识介绍 本文中实现多数据源的关键是Spring提供的Abstrac ...
- Linux磁盘空间容量不够-通过新增磁盘-挂载原磁盘
首先上一张图 -------1)首先fdisk 一块磁盘并格式化 mkfs.ext4 /dev/sda15 --------2)将此磁盘挂载在mnt目录下,并将磁盘容量不够的磁盘所有文件进行复制到mn ...
- 手把手教你用redis实现一个简单的mq消息队列(java)
众所周知,消息队列是应用系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有 ActiveMQ,RabbitMQ,Zero ...
- grafana 如何对数据进行切分
也就是如何增加筛选,根据想要的条件筛选不同的内容,数据源是prometheus 效果 设置variable 正则表达式 匹配url中IP和端口 切片进阶 根据前一个切片 再过滤 含义说明 instan ...
- Ray射线检测和Recources.Load
记录射线检测常用的方法,以及Rocources.Load的常用用法 使用代码实现鼠标点击在鼠标点击处生成制定gameObject RayCastHit hit; void Update() { Ray ...
- 一个非侵入的Go事务管理库——如何使用
在文章"清晰架构(Clean Architecture)的Go微服务: 事物管理"中,我谈到了如何在清晰架构中实现非侵入的事务管理. 它允许你把事务代码与业务逻辑代码分开,并且让你 ...
- 黎活明8天快速掌握android视频教程--27_网络通信之通过GET和POST方式提交参数给web应用
1该项目主要实现Android客户端以get的方式或者post的方式向java web服务器提交参数 Android客户端通过get方式或者post方式将参数提交给后台服务器,后台服务器对收到的参数进 ...