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獲取網頁的內容),

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM