使用php采集网页数据一般有多种方法,有时候东西以采集
优采云 发布时间: 2021-08-15 23:12使用php采集网页数据一般有多种方法,有时候东西以采集
php采集网页数据的使用方式一般有很多种。有时我们使用正则去采集页面,但是当我们需要采集有一个很大很大的页面时,就会严重浪费我们的CPU。到时候我们可以用phpQuer来做采集。如果你不了解 phpQuery,你可以去看看这是什么。
以采集此网站为例
假设我们需要采集commodity category Name Price Item No Shelf Time Product Picture Detail Picture
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 != 200) {
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[1];
//商品参数
$prame_check = pq("#summary1 .dd");
$prame = [];
foreach ($prame_check as $li) {
$prame[] = pq($li)->text();
}
$sn = $prame[0];//货号
$brank = $prame[1];//品牌
$time = $prame[2];//上架时间
// 商品图片
$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[1],
'category2' => $category[2],
'category3' => $category[3],
'price' => $price,
'sn' => $sn,
'brank' => $brank,
'time' => $time,
'photo' => $photo,
'info_photo' =>$info_photo,
];
}
echo "";
print_r($data);
//检测url是否合法
function getHeaders($url,$data=FALSE){
$_headers = get_headers($url,1);
if( !$data ){return $_headers;}
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$url);//获取内容url
curl_setopt($curl,CURLOPT_HEADER,1);//获取http头信息
curl_setopt($curl,CURLOPT_NOBODY,1);//不返回html的body信息
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);//返回数据流,不直接输出
curl_setopt($curl,CURLOPT_TIMEOUT,30); //超时时长,单位秒
curl_exec($curl);
$rtn= curl_getinfo($curl,CURLINFO_HTTP_CODE);
curl_close($curl);
return $rtn;
}
这种情况下,可以采集到这个页面的数据,但是如果我们需要更多的采集数据页面,比如几万条数据,这种方式会很慢
多页采集
如果我们直接循环获取页面,这样每个页面都需要访问一次,并且爬取数据,费时费力,这就是我们可以有多种方案来优化速度。
一个。使用curl模拟多线程,一次性抓取所有网页,保存在本地给采集,避免重复请求带来的开销
B.使用 swoole 创建多个线程来执行采集。比如我们去采集10个页面,需要10秒。这时候我们创建了多个线程,同事请求分发。网址,你可以提高我们的速度
c.当然,如果我们对数据要求不高,可以使用第三方软件,比如优采云、优采云,这些工具可以采集更快的拿到需要的数据
笔者这里用的是第一种方法,因为是windows环境,如果swoole的话,windows安装有点麻烦
我使用 ajax 轮询,一次 10 个。比如我们从产品id为1采集
的数据开始
phpcj.php
php
//获取开始采集的id
$start_id = $_POST['start_id'];
$end_id = $start_id+10; //每次加10条
if(empty($start_id) || empty($end_id)){
exit(json_encode(['status'=>0,'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 != 200){
//如果不合法,返回结束id,重新开始执行
exit(json_encode(['status'=>1,'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 ,0);
curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT,60);
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'=>0,'msg'=>'本次采集未成功..','start_id'=>$start_id]));
}else{
//采集成功,将最后一条数据返回,用作下此次执行的开始id
exit(json_encode(['status'=>1,'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[1];
//参数
$prame_check = pq("#summary1 .dd");
$prame = [];
foreach ($prame_check as $li) {
$prame[] = pq($li)->text();
}
$sn = $prame[0];//货号
if(count($prame) > 2){
$brank = $prame[1];//品牌
$time = $prame[2];//上架时间
}else{
$brank = '无';
$time = $prame[1];//上架时间
}
// 商品图片
$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) < 3){
$category[3] = '';
}
$data = [
'title' => $title,
'category1' => $category[1],
'category2' => $category[2],
'category3' => $category[3],
'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,1);
if( !$data ){return $_headers;}
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$url);//获取内容url
curl_setopt($curl,CURLOPT_HEADER,1);//获取http头信息
curl_setopt($curl,CURLOPT_NOBODY,1);//不返回html的body信息
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);//返回数据流,不直接输出
curl_setopt($curl,CURLOPT_TIMEOUT,30); //超时时长,单位秒
curl_exec($curl);
$rtn= curl_getinfo($curl,CURLINFO_HTTP_CODE);
curl_close($curl);
return $rtn;
}
这样我们就完成了页面采集的循环
前台代码,使用ajax循环请求(如果使用服务器定时任务,需要注意,对于采集不成功的判断,本节我手动重新填id,因为采集因素不可控,可能是对方页面错了,对方数据库错了,但是我们还是可以正常访问的,所以需要把采集失败或者把采集保留在某个id上,需要加上时效判断。超过多久,默认是当前数据采集不成功,那么下一轮采集就会开始,可以是当前id+1,或者其他规则,反正跳过这个id)
"en">
"UTF-8">
Document
"text" name="start_id" id="start_id" placeholder="采集开始id">
"button" id="btn" value="开始采集">
"zhi">
"text" id="ids" placeholder="采集返回成功条数">