需要采集一些电台相关的新闻,百度搜索了一下,本来思路是进去网易,或者搜狐啥的大型新闻平台进行搜索后,进行关键词爬取.
结果发现网易新闻没有搜索新闻的入口,然后搜狐搜索出来的新闻很多是视频筛选比较困难,也有点难搞..
后来发现搜狗他爬取收录了各种平台的新闻内容页,这真的就是:可恨年年压金线,为他人作嫁衣裳...刚好便宜了我,嘿嘿
于是决定爬取搜狗的搜索页,
1.先提取url
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'
];
来源:oschina
链接:https://my.oschina.net/laobia/blog/3217571