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/>\n";
            return false;
        }else{
            $out = "GET / HTTP/1.1\r\n";//创建要发送的头文件信息
            $out .= "Host: ".$url."\r\n";//指定头文件信息中的主机内容
            $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\r\n";
            $out .= "Connection: keep-alive\r\n\r\n";
            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获取网页的内容),

参考资料

posted @ 2017-12-25 17:47  才鱼  阅读(2020)  评论(0编辑  收藏  举报