zoukankan      html  css  js  c++  java
  • SOCKET简单爬虫实现代码和使用方法

    抓取一个网页内容非常容易,常见的方式有curl、file_get_contents、socket以及文件操作函数file、fopen等。

    下面使用SOCKET下的fsockopen()函数访问Web服务器最常用的80端口,通过获取80端口的数据,并进行分析,来模拟网络爬虫的工作方法。

    1、实现SOCKET模拟网络爬虫主要包括以下几个部分:

    • 使用SOCKET获取指定页的内容。
    • 使用get_meta_tags()函数分析网页的META、TITLE等标签内容。
    • 解析TITLE、链接或网页内容,可以使用正则表达式来取得需要的内容。

    SOCKET爬虫实现代码,完整代码如下:

    简单爬虫实现代码和使用方法

    
    class Spider
    {
        private $_url = "";//定义用于保存URL的变量
        private $_sites = "";//定义用于保存网站相关内容的变量
    
        /**
         * 构造函数,用于初始化变量
         * @param $url
         */
        public function __construct($url)
        {
            $this->_url = $url;
        }
    
        /**
         * 开始爬页面
         */
        public function start()
        {
            $content = $this->socketOpen($this->_url);//使用socketOpen()方法链接指定的服务器
            $this->_sites["meta"] = $this->getMeta($content);//使用getMeta()方法获取meta信息
            $this->_sites["title"] = $this->getTitle($content);//使用getTitle()方法获取title信息
            $this->_sites["detail"] = $this->getDetail($content);//使用getDetail()方法获取内容信息
            $this->_sites["links"] = $this->getLinks($content);//使用getLinks()方法获取内容链接信息
        }
    
        /**
         * 获取网页meta
         * @param $content
         * @return array
         */
        protected function getMeta($content)
        {
            $file = "metaCache";//向于保存缓存文件的名称
            file_put_contents($file, $content);//将缓存保存到缓存文件中
            $meta = get_meta_tags($file);//使用get_meta_tags()取得内容的meta信息
            return $meta;//返回meta信息
        }
    
        /**
         * 获取body内容
         * @param $contents
         * @return string
         */
        protected function getDetail($contents)
        {
            preg_match('/<body(.*?)>(.+)</body>/s', $contents, $matches);//使用正则表达式处理内容
            //var_dump($matches);die;
            $body = $this->StripHTML($matches[2]);//去掉特殊HTML字符
            $body = strip_tags($body);//清除内容中的特殊标签
            return mb_substr($body, 0, 400);//返回内容的前400个字符
        }
    
        /**
         * 获取网页标题
         * @param $contents
         * @return mixed
         */
        protected function getTitle($contents)
        {
            preg_match('/<title>(.+)</title>/s', $contents, $matches);//使用正则表达式处理内容
    
            return $matches[1];//返回处理结果中的标题部分
        }
    
        /**
         * 获取页面超链接
         * @param $content
         * @return mixed
         */
        protected function getLinks($content)
        {
            $pat = '/<a(.*?)href="(.*?)"(.*?)>(.*?)</a>/i';//处理链接的正则表达式
            preg_match_all($pat, $content, $m);//使用正则表达式处理链接
            return $m;
        }
    
        /**
         * 抓取页面内容
         * @param $url
         * @return bool|string
         */
        protected function socketOpen($url)
        {
            $fp = fsockopen($url, 80, $errno, $errstr, 30);//使用fsockopen()建立SOCKET链接
            if($fp === false){
                echo "连接远程服务器失败:$errstr($errno)<br/>
    ";
                return false;
            }else{
                $out = "GET / HTTP/1.1
    ";//创建要发送的头文件信息
                $out .= "Host: ".$url."
    ";//指定头文件信息中的主机内容
                $out .= "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36
    ";
                $out .= "Connection: keep-alive
    
    ";
                fwrite($fp, $out);//使用fwrite()函数发送请求
                $contents = "";
                while(!feof($fp)){//使用while循环读取返回的数据
                    $contents .= fgets($fp, 1024);
                }
                fclose($fp);//关闭句柄
                return $contents;//返回获取的内容
            }
        }
    
        /**
         * 去掉HTML中不相关的代码
         * @param $string
         * @return mixed
         */
        protected function StripHTML($string)
        {
            $pattern=array(
                "'<script[^>]*?>.*?</script>'si",
                "'<style[^>]*?>.*?</style>'si"
            );//建立正则表达式
            $replace=array(
                "",
                ""
            );//建立替换字符数组
            return preg_replace($pattern, $replace, $string);//替换内容中HTML并返回替换后的内容
        }
    
        /**
         * 打印出抓取到的数据
         */
        public function show()
        {
            echo "<pre>";
            print_r($this->_sites);//显示保存到$_sites公共变量中的内容
            echo "</pre>";
        }
    
        /**
         * 过滤分析数据中的超链接
         */
        public function filterLinks()
        {
            $realLinks = "";
            $links = $this->_sites["links"][2];//获取保存链接的数组元素
            //遍历数组,清除不规范链接
            foreach($links as $v){//遍历链接数据
                //只保存链接
                if(preg_match('/^http:///', $v) || preg_match('/^https:///', $v)){
                    $realLinks[] = $v;
                }
            }
    		//去除重复的链接
            $realLinks = array_unique($realLinks);
    
            echo "<pre>";
            print_r($realLinks);//显示过滤后的链接
            echo "</pre>";
        }
    }
    
    //域名
    $domainName = 'www.163.com';
    //使用Web爬虫的方法
    $spider = new Spider($domainName);//实例化spider类,并设置需要抓取的网站
    $spider->start();//开始抓取数据
    //$spider->show();//显示抓取的内容
    $spider->filterLinks();
    

    2、执行后结果

    3、执行完成,在文件所在目录下会有个metaCache文件,用文本编辑器打开如下

    • 在获取超链接以后,就可以再使用Web爬虫类对这些链接进行下一步的数据抓取。具体的实现代码可以使用无限循环来实现。

    4、注意

    • 上述例子暂时不能爬去https的网站,这个待去探索
    • 上述例子如需要爬取像http://news.163.com/17/1225/14/D6GQU683000189FH.html这样的链接,还需要着手扩展下上述代码中socketOpen函数(设置下请求头信息,详细情况见另一篇博文使用SOCKET获取网页的内容),

    参考资料

  • 相关阅读:
    (1)前言——(10)jquery项目的历史(History of the jQuery project)
    JavaScript编程:使用DOM操作样式表
    机房收费系统总结之4——VB.NET 轻松解决判断文本框、组合框为空问题
    协同过滤及大数据处理
    Storm工作流程 vs. Spark Stream
    《大数据技术原理与应用》学习
    gdb的follow-fork-mode使用以及多线程操作
    回上海咯!继续学习计算广告
    美团技术博客
    这里面有一些关于依图工作的内容
  • 原文地址:https://www.cnblogs.com/renzhicai/p/8110460.html
Copyright © 2011-2022 走看看