荆轲刺秦王

因业务需求,需要做一个网页的信息采集功能。这个网页就是安居客的新房的列表页。

第一步:一开始,我用最基本的采集,采集一点很基本的内容,就是网页 html 的的<title>标签的内容,采集出来的是乱码

问过同事后才明白:原来有些网站为了优化,会使用 gzip 压缩,这样就导致我们采集的信息一直是乱码。

如何检测网页是否使用了 gzip 压缩?

1.谷歌浏览器  F12打开页面

2.右键点击 Waterfall  > Response Headers > Content-Encoding

3. 如何开启了 gzip 则会显示 gzip 没有则为空

解决办法:使用下面的函数:

function https_request($url='',$gz=false){$curl=curl_init();if($gz){curl_setopt($curl,CURLOPT_ENCODING,'gzip');}//加入gzip解析curl_setopt($curl,CURLOPT_URL,$url);curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,FALSE);curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,FALSE);curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);$data=curl_exec($curl);if(curl_errno($curl)){return 'ERROR'.curl_error($curl);}curl_close($curl);return $data;}

第一个参数传入需要抓取页面的 url 第二个参数设为 true

然后,我将抓取页面信息的函数封装成一个方法,如果同学需要抓取其他页面,需要修改其中的正则表达式!

//this is collect functionpublic function getCollectContent($url){$content = $this->https_request($url,true);//echo $content;exit();$title_preg='#<h3><span class="items-name">(.*)</span></h3>#i';preg_match_all($title_preg,$content,$titles);//print_r($res[1]);exit;$newarray = array();foreach($titles[1] as $k=>$v){$newarray[$k] = array('ktitle' => $v,);}//print_r($newarray);//this  is  address and area collect$address_preg='#<span class="list-map" target="_blank">(.*)</span>#i';preg_match_all($address_preg,$content,$address);//print_r($address[1]);exit();foreach($address[1] as $k=>$v){foreach($newarray as $key=>$value){if($k == $key){$newarray[$key]['address']=substr(str_replace('&nbsp;','',$v),strpos(str_replace('&nbsp;','',$v),']')+1);$newarray[$key]['area']=substr(str_replace('&nbsp;','',$v),1,(strpos(str_replace('&nbsp;','',$v), ']') -1));}}}//this is  sole status$sale_preg='#<i class="status-icon .*s.*">(.*)</i>#i';preg_match_all($sale_preg,$content,$sales);//print_r($sales[1]);exit;foreach($sales[1] as $k=>$v){foreach($newarray as $key=>$value){if($k == $key){$newarray[$key]['isflag']=$v;}}}//this is web_id$web_info_preg = '/<div class="item-mod " data-link="(.*?)" data-soj="(.*?)"  rel="nofollow">/';preg_match_all($web_info_preg,$content,$web_infos);//print_r($web_infos[1]);exit;foreach($web_infos[1] as $k=>$v){foreach($newarray as $key=>$value){if($k == $key){$array = explode('/', $v);$newarray[$key]['web_id'] = substr($array[2],0,strpos($array[2], '.'));$newarray[$key]['web_domain'] = substr($array[4],0,strpos($array[4], '.'));$newarray[$key]['web_fenqi'] = '';$newarray[$key]['fromweb'] = 2;$newarray[$key]['fromurl'] = $v;$newarray[$key]['city_id'] = $this->city_id;$newarray[$key]['user_id'] = UID;$newarray[$key]['addtime'] = date("Y-m-d H:i",time());$newarray[$key]['uptime'] = 0;$newarray[$key]['deltime'] = 0;$newarray[$key]['state'] = 1;$newarray[$key]['cai_id'] = null;}}}return $newarray;}

其实我想重点讲解一下这个采集的方法,或者说是函数!

里面在采集 address 的时候,使用的字符串截取和去除 &nbsp; 是写到一块了,所以千万别被迷惑了。

主要内容就是将:[&nbsp;汤阴&nbsp;汤阴&nbsp;]&nbsp;乾坤大道与德贤路交汇处  处理为:汤阴汤阴  和  乾坤大道与德贤路交汇处  将网页中的内容截分为两个数据库的字段。

上面在采集具体某一个楼盘链接的时候,我顺带将需要插入数据库的所有字段都做了补充,方便后面直接使用 TP5 的 insertAll

方法一次性全部插入。不过就这个项目而言这个思路被我废弃了。不管怎样,你只需要知道 我写的这个方法返回的是一个二维数组就可以了!

然后,考虑到列表页肯定不止一页数据,而且城市不一样 楼盘数量肯定也不一样,我专门做了一个 getPage 方法,这个方法也很简单,就是先使用采集获取到一共有多少条数据,

这个 getPage 的思路也很简单,就是获取这个所有的楼盘数量,然后除以每页显示的数量,然后再向上取整 :

//this is for get page functionpublic function getPage(){$domain = $this->getCityDomain();//echo $domain;exit();$url = "https://".$domain.".fang.anjuke.com/loupan/?from=navigation";//echo $url;exit();$content = $this->https_request($url,true);//echo $content;exit();$em_preg='#<span class="result">.*<em>(.*)</em>#isU';preg_match_all($em_preg,$content,$result);//print_r($result);exit;$res = $result[1][0];$allPage = ceil($res/60);return $allPage;}

这个 getPage 函数主要也是为了获取第二页,第三页等等的链接地址的。

for($i=1;$i<=$this->getPage(); $i++) {sleep($wait_sec);$url = "https://".$domain.".fang.anjuke.com/loupan/all/p$i/";$res = $this->getCollectContent($url);//print_r($res);exit();$this->checkData($res);}

可以看到,我每次采集都会先使程序 sleep 几秒,我写这个是因为项目需要,一般情况是可以省略的。

然后使用 foreach 循环获取第一页,第二页,第三页等等的内容。

最后我还写了一个 checkData  解释一下这个函数:这个是为了解决:客户第一次采集完数据之后,如果再次采集,重复的数据作为更新,不重复的数据将作为新增数据,新增到数据库。

代码:

//this is for check data is existspublic function checkData($obj_array){//$data = Db::table('tb_house_cai')->select();//print_r($obj_array);foreach($obj_array as $k=>$v){$result = Db::table('tb_house_cai')->where('ktitle',$v['ktitle'])->select();if(empty($result)){Db::table('tb_house_cai')->insert($v);}else{$res = Db::table('tb_house_cai')->where('ktitle',$v['ktitle'])->find();$v['cai_id'] = $res['cai_id'];Db::table('tb_house_cai')->update($v);}}}

注意!

这里 个人认为非常不理想,我一开始的思路是这样的:

public function checkDta($obj_array){$data = Db::table('tb_house_cai')->select();//print_r($obj_array);foreach($data as $k=>$v){foreach($obj_array as $key=>$value){if($v['ktitle'] == $value['ktitle']){$obj_array[$key]['cai_id'] = $data[$k]['cai_id'];Db::table('tb_house_cai')->update($v);}else{Db::table('tb_house_cai')->insert($v);}}}}

我认为不好的地方也很明显,就是连接数据库的次数太多,我一开始的思路按照上面的代码操作,但是结果并不理想,或者说结果与我预期的效果不符合。我最后没办法,只能放弃这种思路,如果有同学可以帮我指出问题,可以在评论区里讨论。

最后,上整个控制器的代码:

这里面有个别地方需要借鉴的同学修改!

<?php
namespace app\web\admin;use app\admin\controller\Admin;
use app\common\builder\ZBuilder;//引入Zbuilder;
use app\sys\model\City as CityModel;
use think\Db;//引入Bb类/**
* 楼盘信息采集管理
*/
class Collect extends Admin
{private $city_id;public function index(){if ($this->request->isPost()) {// 接收表单数据$data = $this->request->post();if($data['city_id'] == null)$this->error('城市不能为空');$wait_sec = $data['wait_sec'];//echo $wait_sec;exit();if($data['city_id'] == null){$city_id = 1;}else{$city_id = $data['city_id'];}$this->city_id = $city_id;$domain = $this->getCityDomain();//https://zz.fang.anjuke.com/loupan/all/p1///echo $this->getPage();exit();for($i=1;$i<=$this->getPage(); $i++) {sleep($wait_sec);$url = "https://".$domain.".fang.anjuke.com/loupan/all/p$i/";$res = $this->getCollectContent($url);//print_r($res);exit();$this->checkData($res);}$this->success('采集完成');}$city_list = CityModel::getCityList();$wait_list = array('3'=>'三秒','5'=>'五秒','10'=>'十秒','15'=>'十五秒','20'=>'二十秒','25'=>'二十五秒','30'=>'三十秒','45'=>'四十五秒','60'=>'一分钟','120'=>'两分钟',);return ZBuilder::make('form')->setPageTitle('采集链接')->addFormItem('select', 'city_id', '请选择城市', '', $city_list)->addFormItem('select', 'wait_sec', '请选择采集等待时间', '', $wait_list)//->addFormItem('text', 'url', '请输入需要采集的链接')->fetch();}function https_request($url='',$gz=false){$curl=curl_init();if($gz){curl_setopt($curl,CURLOPT_ENCODING,'gzip');}//加入gzip解析curl_setopt($curl,CURLOPT_URL,$url);curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,FALSE);curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,FALSE);curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);$data=curl_exec($curl);if(curl_errno($curl)){return 'ERROR'.curl_error($curl);}curl_close($curl);return $data;}function DeleteHtml($str){$str = trim($str); //清除字符串两边的空格$str = preg_replace("/\t/","",$str); //使用正则表达式替换内容,如:空格,换行,并将替换为空。$str = preg_replace("/\r\n/","",$str);$str = preg_replace("/\r/","",$str);$str = preg_replace("/\n/","",$str);$str = preg_replace("/ /","",$str);$str = preg_replace("/  /","",$str);  //匹配html中的空格return trim($str); //返回字符串}function SubStr($tinfo=NULL,$ks=NULL,$js=NULL,$s=1,$e=0) {if(empty($tinfo)){return '';}if(strpos($tinfo, $ks) == FALSE) {return '';}if(!empty($ks)){$arry_tinfo=explode($ks,$tinfo);if(!empty($arry_tinfo)){$tinfo=$arry_tinfo[$s];}}if(!empty($js)){$arry_tinfo=explode($js,$tinfo);if(!empty($arry_tinfo)){$tinfo=$arry_tinfo[$e];}}return $tinfo;}public function getCityDomain(){$array = array('1'=>'zz','2'=>'kf','3'=>'ly','4'=>'pds','5'=>'ay','6'=>'jz','7'=>'hb','8'=>'xx','9'=>'py','10'=>'xc','11'=>'lh','12'=>'smx','13'=>'ny','14'=>'sq','15'=>'zk','16'=>'xy','17'=>'zmd','18'=>'jy','19'=>'zm');return $array[$this->city_id];}//this is collect functionpublic function getCollectContent($url){$content = $this->https_request($url,true);//echo $content;exit();$title_preg='#<h3><span class="items-name">(.*)</span></h3>#i';preg_match_all($title_preg,$content,$titles);//print_r($res[1]);exit;$newarray = array();foreach($titles[1] as $k=>$v){$newarray[$k] = array('ktitle' => $v,);}//print_r($newarray);//this  is  address and area collect$address_preg='#<span class="list-map" target="_blank">(.*)</span>#i';preg_match_all($address_preg,$content,$address);//print_r($address[1]);exit();foreach($address[1] as $k=>$v){foreach($newarray as $key=>$value){if($k == $key){$newarray[$key]['address']=substr(str_replace('&nbsp;','',$v),strpos(str_replace('&nbsp;','',$v),']')+1);$newarray[$key]['area']=substr(str_replace('&nbsp;','',$v),1,(strpos(str_replace('&nbsp;','',$v), ']') -1));}}}//this is  sole status$sale_preg='#<i class="status-icon .*s.*">(.*)</i>#i';preg_match_all($sale_preg,$content,$sales);//print_r($sales[1]);exit;foreach($sales[1] as $k=>$v){foreach($newarray as $key=>$value){if($k == $key){$newarray[$key]['isflag']=$v;}}}//this is web_id$web_info_preg = '/<div class="item-mod " data-link="(.*?)" data-soj="(.*?)"  rel="nofollow">/';preg_match_all($web_info_preg,$content,$web_infos);//print_r($web_infos[1]);exit;foreach($web_infos[1] as $k=>$v){foreach($newarray as $key=>$value){if($k == $key){$array = explode('/', $v);$newarray[$key]['web_id'] = substr($array[2],0,strpos($array[2], '.'));$newarray[$key]['web_domain'] = substr($array[4],0,strpos($array[4], '.'));$newarray[$key]['web_fenqi'] = '';$newarray[$key]['fromweb'] = 2;$newarray[$key]['fromurl'] = $v;$newarray[$key]['city_id'] = $this->city_id;$newarray[$key]['user_id'] = UID;$newarray[$key]['addtime'] = date("Y-m-d H:i",time());$newarray[$key]['uptime'] = 0;$newarray[$key]['deltime'] = 0;$newarray[$key]['state'] = 1;$newarray[$key]['cai_id'] = null;}}}return $newarray;}//this is for get page functionpublic function getPage(){$domain = $this->getCityDomain();//echo $domain;exit();$url = "https://".$domain.".fang.anjuke.com/loupan/?from=navigation";//echo $url;exit();$content = $this->https_request($url,true);//echo $content;exit();$em_preg='#<span class="result">.*<em>(.*)</em>#isU';preg_match_all($em_preg,$content,$result);//print_r($result);exit;$res = $result[1][0];$allPage = ceil($res/60);return $allPage;}//this is for check data is existspublic function checkData($obj_array){//$data = Db::table('tb_house_cai')->select();//print_r($obj_array);foreach($obj_array as $k=>$v){$result = Db::table('tb_house_cai')->where('ktitle',$v['ktitle'])->select();if(empty($result)){Db::table('tb_house_cai')->insert($v);}else{$res = Db::table('tb_house_cai')->where('ktitle',$v['ktitle'])->find();$v['cai_id'] = $res['cai_id'];Db::table('tb_house_cai')->update($v);}}}public function checkDta($obj_array){$data = Db::table('tb_house_cai')->select();//print_r($obj_array);foreach($data as $k=>$v){foreach($obj_array as $key=>$value){if($v['ktitle'] == $value['ktitle']){$obj_array[$key]['cai_id'] = $data[$k]['cai_id'];Db::table('tb_house_cai')->update($v);}else{Db::table('tb_house_cai')->insert($v);}}}}}

关于采集:

有兴趣的同学可以学习使用一下: phpQuery

不过这个 phpQuery v3 版本的用着没有 v4 版本的好用,但是 v4 版本的需要 php 7.0以上,所以我放弃了,但是如果条件允许,phpQuery 将是个非常好用的采集插件!

ThinkPHP5 采集网页的指定内容相关推荐

  1. window.print()打印网页中指定内容的实现方法

    一般直接使用window.print();是直接打印了整个页面,但只打印其中的一部分时就需要一些方法了 1.在页面的代码头部处加入JavaScript: <script language=jav ...

  2. vc采集网页内指定frame框架下所有元素-再升级版

    再升级版说明:通过frame的get_location属性,指定frame来获取其元素,减少递归和循环,减少循环和递归,基于效能提升门户生产地址获取主叫,可从6s压缩到1s,耗时在于指定frame所有 ...

  3. window.print()打印网页中指定内容

    <!DOCTYPE html> <html><head><meta charset=" utf-8"><meta name=& ...

  4. php抓取html元素内容 采集网页

    网页抓取就像搜索引擎一个可以去自动抓取其它服务器上的内容了,下面我整理的几个php常用做法,大家一起来看看. 抓取某一个网页中的内容,需要对DOM树进行解析,找到指定节点后,再抓取我们需要的内容,过程 ...

  5. python爬虫搜特定内容的论文_python基于BeautifulSoup实现抓取网页指定内容的方法...

    python基于BeautifulSoup实现抓取网页指定内容的方法 更新时间:2015年07月09日 10:12:50 作者:光索与诺 这篇文章主要介绍了python基于BeautifulSoup实 ...

  6. vb.net提取html网址,如何提取网页代码中指定内容

    怎么提取网页代码中指定内容? 某数据库网页结构如下: html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http ...

  7. python搜索网页特定区域内容_Python爬取练习:指定百度搜索的内容并提取网页的标题内容...

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 以下文章源于白菜学python ,作者小白菜 刚接触Python的新手.小白,可以复制下面的链接去 ...

  8. python 打开网页开发者工具_Python获取网页指定内容(BeautifulSoup工具的使用方法)...

    page = urllib2.urlopen(url) contents = page.read() #获得了整个网页的内容也就是源代码 print(contents) url代表网址,content ...

  9. autojs屏蔽网页指定内容

    autojs屏蔽网页指定内容 *@更多基础加autojs交流群553908361喽; 一键加群:点击加群 在交流群里看到个很有意思的代码.我们一起来解析下 屏蔽线程 = threads.start(f ...

最新文章

  1. pyqt怎么给字体加粗_微信拍一拍可设置后缀?怎么用?还有更多新功能!
  2. Pytorch之GPU加速计算问题以及model=model.to(device)
  3. css之命名规范 BEM
  4. RxJava系列4(过滤操作符)
  5. eclipse 模版的使用
  6. C(++) Websocket实现扫码二维码登录---GoEasy
  7. 3、electron打包生成exe文件
  8. ASP.NET中登录功能的简单逻辑设计
  9. matlab三维三角网格,有限元分析利用matlab的gplot函数实现三维划分网格的方法
  10. windowsxp系统怎么装iis服务器,XP系统如何安装IIS?IIS安装教程
  11. Python 批量更改文件名、更改文件格式
  12. HTML中哪些标记能放在首部,HTML基本结构与常用标记
  13. CPU使用率和负载区别及分析
  14. php 计算函数 相加,比较,相除,相减,求余,相乘
  15. windows cmd字典
  16. weka中文使用(一)
  17. 拉结尔派遣任务辅助介绍 拉结尔快速升级脚本挂机工具
  18. R语言)不依赖求导的寻根方法:Nelder-Mead方法
  19. php输出扶墙而立的三角形,扶墙而立的成长历程——涉县五中刘嘉巍
  20. easyui filebox 上传图片预览

热门文章

  1. 边缘计算与云计算协同白皮书2018
  2. Win10 启用照片查看器
  3. 洛古P2392-kkksc03考前临时抱佛脚
  4. Auvidea J120 TX2开发板 Jetpack刷机与驱动安装
  5. Go语言的学习【2】基础语法
  6. 详细介绍:如何用Vue完成喵喵电影项目?
  7. 手撸一个一起看电影应用-5-项目打包
  8. Python中的id函数到底是什么?
  9. 快速设置指南/FeistyFawn
  10. 蓝桥杯python每日一题——圆的面积