phpspider在列表页生成内容采集url.(又名:如何通过搜狗搜索关键词,爬取新浪新闻)

原创
2020/04/02 17:52
阅读数 4.7K

需要采集一些电台相关的新闻,百度搜索了一下,本来思路是进去网易,或者搜狐啥的大型新闻平台进行搜索后,进行关键词爬取.

结果发现网易新闻没有搜索新闻的入口,然后搜狐搜索出来的新闻很多是视频筛选比较困难,也有点难搞..

后来发现搜狗他爬取收录了各种平台的新闻内容页,这真的就是:可恨年年压金线,为他人作嫁衣裳...刚好便宜了我,嘿嘿

于是决定爬取搜狗的搜索页,

1.先提取url

https://news.sogou.com/news?query=site%3Asina.com.cn+%B5%E7%CC%A8&_ast=1585809152&_asf=news.sogou.com&time=0&w=03009900&sort=0&mode=2&manual=true&dp=1

2.然后获取他列表页的规则

进入 http://tool.chinaz.com/regex/  这个网站,可以快速写个正则匹配就行了,其实就是找到分页的page参数字段,然后把值改成正则的数字,替换一下就完事儿了..简简单单,把规律找到

3.详情页的匹配规则,

因为详情页都是以.sina.com.cn结尾的url,所以,他的正则也很好写

((https|http)?:\/\/)[^\s]{1,6}.sina.com.cn/[a-z]{1,10}/.*.shtml

4.下面讲一些自己踩的坑

4.1:在搜狗搜索页下面,获取不到内容详情页的url

原因:因为domains主域名需要你把你采集的内容页和详情页的开头的域名都给填上,不填就是不会采集的..所以我的domains下面填写了一大串新浪的二级域名

4.2:采集到不该采集的文章详情去了,我只想要搜索的文章结果的url

分析:phpspider一般情况是根据你config中的content_url_regexes来正则匹配列表页中的url,然后提起出来,作为详情页采集..这样它就会采集到一些不属于搜索内容的url.

做法:重写spider的on_list_page方法,直接把列表页里面的html,通过selector把需要的url元素提取出来,然后插入内容页,并且返回false,不再插入其他获得的内容url

//采集列表页
$spider->on_list_page = function($page, $content, $phpspider)
{
    // 在列表页中通过XPath提取到内容页URL 这里获取的是数组,所以下面要进行循环
    $content_url = \phpspider\core\selector::select($content,"//h3[@class='vrTitle']/a/@href");

    if(!empty($content_url)){
        foreach ($content_url as $k=>$v){
            $phpspider->add_url($v);
        }
    }

    return false;
};

4.3如何匹配多个规则,比如有些文章的内容div的id是article,有的又是article_content

分析:使用xpath里面的一个叫或者的东西,使用如下,就把不同的规则通过一个"|"分割开了,一开始没注意到,后来感觉非常好用

'selector' => "//div[@id='article_content']//p|//div[@id='article']//p|//div[@class='img_wrapper']",

4.4获取的内容可能是数组,怎么办?

在设置里面设置repeat为true,使用方法可以搜索文档具体查看

我的用法是,获取文章内容里面的P标签,和图片标签,因为里面还有啥嵌入的广告,这样那样的东西,一个个去排除太麻烦了,我TM干脆直接获取里面的p和图片,就完事儿了,然后我自己拼接成字符串儿..

config配置:

[
            'name' => "content",//网站内容
            'selector' => "//div[@id='article_content']//p|//div[@id='article']//p|//div[@class='img_wrapper']",
            'required'=>false,
            'repeated' => true,
        ],

采集到的结果后,进行处理的on_extract_field函数,直接给它判断,有图片,就用div拼接图片,否则,就拼接个p标签,给串成字符串儿..然后用转json,压缩成字符串,转base64,存数据库(占用的空间少)

//详情页=>提取字段=>处理字段
$spider->on_extract_field = function($fieldname, $data, $page)
{
    if($fieldname=='content'){
        $data_str='';
        if(!empty($data)){
            //循环拼接成字符串
            foreach ($data as $k=>$v){
                if(strstr($v,"img")!==false){
                    $data_str.="<div class='img_wrapper'>".$v."</div>";
                }else{
                    $data_str.="<p>".$v."</p>";
                }
            }
            $content=json_encode($data_str,JSON_UNESCAPED_UNICODE);//转成json
            $content_gz=gzcompress($content);//压缩字符串
            $data=base64_encode($content_gz);//组成base64
        }else{
            $data='';
        }

        return $data;
    }

    return $data;
};

 

5.上俺的代码

注意:这里的phpspider引用路劲,需要按照自己的实际路由引用..然后我把数据库配置单独写了一个config.php作为所有采集文件公共的引入文件

<?php

require_once __DIR__.'/../vendor/owner888/phpspider/autoloader.php';
require __DIR__.'/config.php';
use phpspider\core\phpspider;
use phpspider\core\db;


//随机IP
function Rand_IP(){

    $ip2id= round(rand(600000, 2550000) / 10000); //第一种方法,直接生成
    $ip3id= round(rand(600000, 2550000) / 10000);
    $ip4id= round(rand(600000, 2550000) / 10000);
    //下面是第二种方法,在以下数据中随机抽取
    $arr_1 = array("218","218","66","66","218","218","60","60","202","204","66","66","66","59","61","60","222","221","66","59","60","60","66","218","218","62","63","64","66","66","122","211");
    $randarr= mt_rand(0,count($arr_1)-1);
    $ip1id = $arr_1[$randarr];
    return $ip1id.".".$ip2id.".".$ip3id.".".$ip4id;
}

//下面这个注释删了就跑不起来.....
/* Do NOT delete this comment */
/* 不要删除这段注释 */




$configs = array(
    'name' => 'sina',
    'log_show' => true,
    'tasknum' => 3,//爬虫任务数
    //主域名
    'domains' =>[
        'news.sogou.com',
        'news.sina.com.cn',
        'mil.news.sina.com.cn',
        'mobile.sina.com.cn',
        'sports.sina.com.cn',
        'tech.sina.com.cn',
        'games.sina.com.cn',
        'ent.sina.com.cn',
        'finance.sina.com.cn',
    ],
    //入口地址
    'scan_urls' => [
        'https://news.sogou.com/news?query=site%3Asina.com.cn+%B5%E7%CC%A8&_ast=1585812480&_asf=news.sogou.com&time=0&w=01029901&sort=0&mode=2&manual=true&dp=1&sut=942&sst0=1585814645811&lkt=0%2C0%2C0',
    ],
    //列表url 匹配规则
    'list_url_regexes' => [
        "https://news.sogou.com/news\?mode=2&manual=true&query=site\%3Asina.com.cn\+\%B5%E7%CC%A8&sort=0&page=\d+.*",
    ],
    //详情页url 匹配规则
    'content_url_regexes' =>[
        "((https|http)?:\/\/)[^\s]{1,6}.sina.com.cn/[a-z]{1,10}/.*.shtml",
    ],
    'db_config' => $db_config,
    'fields' => [
        [
            'name' => "title",//标题
            'selector' => "//h1/text()",
            'required' => true,
        ],
        [
            'name' => "keywords",//关键词
            'selector' => "//meta[@name='keywords']/@content",
            'required'=>false,
        ],
        [
            'name' => "description",//描述
            'selector' => "//meta[@property='og:description']/@content",
            'required'=>false,
        ],
        [
            'name' => "create_time",//创建时间
            'selector' => "//meta[@property='article:published_time']/@content",
            'required'=>false,
        ],
        [
            'name' => "thumb",//缩略图
            'selector' => "//meta[@property='og:image']/@content",
            'required'=>false,
        ],
        [
            'name' => "oldurl",//网站链接
            'selector' => "//meta[@property='og:url']/@content",
            'required'=>false,
        ],
        [
            'name' => "content",//网站内容
            'selector' => "//div[@id='article_content']//p|//div[@id='article']//p|//div[@class='img_wrapper']",
            'required'=>false,
            'repeated' => true,
        ],

    ],

);


//实例化蜘蛛
$spider=new phpspider($configs);

//采集初始=>数据库初始化
$spider->on_start = function($phpspider)
{

    // 生成列表页URL入队列
    for ($i = 1; $i <= 24; $i++)
    {
        $url = "https://news.sogou.com/news?mode=2&manual=true&query=site%3Asina.com.cn+%B5%E7%CC%A8&sort=0&page={$i}&p=42230302&dp=1";
        $phpspider->add_url($url);
    }

    \phpspider\core\requests::set_header("CURLOPT_HTTPHEADER", array('X-FORWARDED-FOR:'.Rand_IP(), 'CLIENT-IP:'.Rand_IP()));

    $db_config = $phpspider->get_config("db_config");
    // 数据库连接
    db::set_connect('default', $db_config);
    db::_init();
};

//详情页=>提取字段=>处理字段
$spider->on_extract_field = function($fieldname, $data, $page)
{
    if($fieldname=='content'){
        $data_str='';
        if(!empty($data)){
            //循环拼接成字符串
            foreach ($data as $k=>$v){
                if(strstr($v,"img")!==false){
                    $data_str.="<div class='img_wrapper'>".$v."</div>";
                }else{
                    $data_str.="<p>".$v."</p>";
                }
            }
            $content=json_encode($data_str,JSON_UNESCAPED_UNICODE);//转成json
            $content_gz=gzcompress($content);//压缩字符串
            $data=base64_encode($content_gz);//组成base64
        }else{
            $data='';
        }

        return $data;
    }

    return $data;
};

//详情页=>提取最终的数据=>入库
$spider->on_extract_page = function($page, $data)
{
    $savedata = $data;
    $savedata['cate_name']='电台';//栏目:电台新闻
    $savedata['title']=strip_tags($data['title']);
    $savedata['status'] = 1;//状态
    $savedata['site']='sina';//来源网站:新浪

    //时间戳
    $savedata['create_time_timestamp']=strlen($data['create_time'])>2?strtotime($data['create_time']):0;

    //如果采集的数据content字段不为空,直接插入数据库
    if($savedata['content']!==''){
        $sql = "SELECT id from yx_news WHERE title='".$savedata['title']."';";
        $row = db::get_one($sql);
        if(empty($row)){

            db::insert("yx_news", $savedata);
            echo '数据库已保存!';
        }else{
            echo '数据重复,已跳过...';
        }

    }
    return $data;
};

//采集列表页
$spider->on_list_page = function($page, $content, $phpspider)
{
    // 在列表页中通过XPath提取到内容页URL 这里获取的是数组,所以下面要进行循环
    $content_url = \phpspider\core\selector::select($content,"//h3[@class='vrTitle']/a/@href");

    if(!empty($content_url)){
        foreach ($content_url as $k=>$v){
            $phpspider->add_url($v);
        }
    }

    return false;
};

$spider->on_content_page=function ($page,$content,$Phpspider){
    return false;
};

$spider->start();



config.php

<?php
$db_config=[
    'host'  => '127.0.0.1',
    'port'  => 3306,
    'name'=>'fm_news',
    'user'=>'root',
    'pass'=>'root'
];

 

展开阅读全文
加载中

作者的其它热门文章

打赏
2
1 收藏
分享
打赏
0 评论
1 收藏
2
分享
返回顶部
顶部