使用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 506 相对名次
506. 相对名次 给出 N 名运动员的成绩,找出他们的相对名次并授予前三名对应的奖牌.前三名运动员将会被分别授予 "金牌","银牌" 和" 铜牌&q ...
- Java实现 LeetCode 398 随机数索引
398. 随机数索引 给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引. 您可以假设给定的数字一定存在于数组中. 注意: 数组大小可能非常大. 使用太多额外空间的解决方案将不会通过测试 ...
- Java实现 LeetCode 150 逆波兰表达式求值
150. 逆波兰表达式求值 根据逆波兰表示法,求表达式的值. 有效的运算符包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说明: 整数除法只保留整数部分. 给定逆波 ...
- Java实现判断单联通(强连通缩点+拓扑排序)Going from u to v or from v to u
Description In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has ...
- java实现第七届蓝桥杯交换瓶子
交换瓶子 交换瓶子 有N个瓶子,编号 1 ~ N,放在架子上. 比如有5个瓶子: 2 1 3 5 4 要求每次拿起2个瓶子,交换它们的位置. 经过若干次后,使得瓶子的序号为: 1 2 3 4 5 对于 ...
- Linux 递归acl权限和默认acl权限
递归acl权限 递归acl指给父目录设定acl时,所有的子文件和子目录都拥有相同的acl权限 setfacl -m u:boduo:rx -R /project/ 默认acl权限 默认acl权限的作用 ...
- 阿里云专有网络配置以及交换机配置+ip、子网掩码、ip网段计算原理讲解
在阿里云上购买ECS或者其他服务,如redis.polardb时,需要配置专有网络,阿里的文档写的总体上还是比较抽象的,没有一定的网络基础,会一脸懵. 所以这里我来进行专有网络和交换机的配置,以及ip ...
- CSS 简介/特点/优势/给特定浏览器提供不同样
1.CSS简介 CSS全称Cascading Style Sheet,可译为“层叠样式表”或“级联样式表”,通常称为CSS样式或者样式表.CSS是一些纯文本内容,文件格式为.css. 2.CSS特点 ...
- (二)CRLF注入
01 漏洞描述 在<HTTP | HTTP报文>一文中,我们介绍了HTTP报文的结构:状态行和首部中的每行以CRLF结束,首部与主体之间由一空行分隔.或者理解为首部最后一个字段有两个CRL ...
- C和C++中static的比较
using namespace std; class A{ private: static int a;//由static修饰的变量仅仅是一个声明,不能在此处进行初始化,需要在类的外部初始化. voi ...