满天星
Fork me on GitHub

天亮爬虫学习笔记01

05实时新闻采集

天亮爬虫篇--初级篇

五大门户:新浪新闻,网易,腾讯,搜狐,凤凰

中国青年网是国内用户群体最广泛,体量最大,权威度最高,集新闻编撰,发布,传播为一体的新闻数据中心。

http://news.youth.cn/gn/
采集要求:
    数据字段要求
        新闻标题,发布时间,数据插入数据库的时间
    首次采集
        因为新闻数据量巨大,机器和带宽有限,故只采集前5页即可,并存储到mysql数据库中
    增量采集
        当首次采集的5页完成后,定时周期性每隔1分钟增量采集一次,将新出现的新闻条目采集下去,并存储到mysql数据库即可
    采集日志输出要求
        日志当中,要能一直输出当前共采集多少条新闻,当天共采集多少条新闻

主要思路:
    通过javase+maven+httpclient数据集组件+正则+mysql综合实现
    数据采集器的开发流程:主要包括提交任务的用户接口层,任务调度层,网络爬取层,数据解析层,数据持久化层,共5个主要层,再循环至任务调度层的过程
    模块间解耦设计,模块间通过类或方法来衔接串联,最终形成完整的系统。

    //任务调度层:解决先后采集等策略问题
    //递归采集分深度优先和广度优先
主要考点:
    项目分析与开发过程熟悉
    javase程序设计基础
    面向对象程序设计
    maven项目构建和开发
    httpclient api学习和使用
    正则
    mysql操作

爬虫相关博文链接:
    https://blog.csdn.net/erliang20088/article/details/45790263?locationNum=7&fps=1    
    https://blog.csdn.net/erliang20088/article/details/45790201
    https://blog.csdn.net/erliang20088/article/details/45790103
    https://blog.csdn.net/erliang20088/article/details/45790253

    简单页面:是指没有异步请求的页面。


nlp:
    句法分析
    itp   哈工大

    数据挖掘:
    基于nlp基础

    HttpURLConnection底层是socket
    HttpClient底层是httpURLConnection


SimpleYouthNewsSpider
<!-- 首先配置仓库的服务器位置,首选阿里云,也可以配置镜像方式 -->
<repositories>
    <repository>
        <id>nexus-aliyun</id>
        <name>Nexus iliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/xxxx</url>
    </repository>
</repositories>
<dependencies>
    <!-- 引入hadoop-cli-2.7.4依赖 -->
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>2.7.4</version>
        <scope>provided</scope>
    </dependency>
    hive
    ...
</dependencies>
<build>打包的</build>

package一般是5层
com.tl.spider.ui
    UIManager();
com.tl.spider.schedule
com.tl.spider.download
com.tl.spider.parser
com.tl.spider.utils
resources
    seeds.txt

/*
    负责爬虫系统对外开放接口的设计
*/
public class UIManager{
    //拿到系统运行的种子
    public static String getSeedUrl(){
        return "http://news.youth.cn/gn/";
    }
    //拿到系统运行的种子通过文件加载的方式
    public static List<String> getSeedUrlFromFile(){
        String seedFilePath = "seeds.txt";
        List<String> seedUrlList=FileOperatorUtil.getList();
    }
    public static String readFromFile(String filePath,String charset){
        File fileObj = new File(filePath);
        FileInputStream fis = new FileInputStream(fileObj);
        InputStreamReader isr = new InputStreamReader(fis);
        BufferedReader br = new BufferedReader(isr);
        StringBuilder stringBuilder = new StringBuilder();
        String temp = null;
        int lineCounter=0;// StringBuilder会多一行
        while(temp=br.readLine()!=null){
            if(lineCounter > 0){
                stringBuilder.append("\n");
            }
            lineCounter ++;
            stringBuilder.append(temp);
        }
        br.close();
        return stringBuilder.toString();
    }
    public static List<String> readFromFile(String filePath,String charset) throws Exception{
        File fileObj = new File(filePath);
        FileInputStream fis = new FileInputStream(fileObj);
        InputStreamReader isr = new InputStreamReader(fis);
        BufferedReader br = new BufferedReader(isr);
        StringBuilder stringBuilder = new StringBuilder();
        String temp = null;
        List<String> lineList = new ArrayList<String>();
        while(temp=br.readLine()!=null){
            temp = temp.trim();
            if(temp.length() > 0){
                lineList.add(temp);
            }
        }
        br.close();
        return stringBuilder.toString();
    }

    psvm(){

    }

}

//seeds.txt
http://news.youth.cn/gn/

URL.  里面有个.openStream()。 返回InputStream

.....

拿到html后

//负责接收外部传过来的url任务,通过一定的分发策略,将相应的url任务分发到采集任务中
public class ScheduleManager{
    public static List<UrlTaskPojo> todoTaskList = new LinkedList<>();
    //
    public static List<UrlTaskPojo> xxx(xxx){
        //将种子url加入到待采集队列
        return null;
    }
}


去重:
添加种子的时候要去重
remove的时候也要去重
public static Set<String> todoTaskUrl = new HashSet<String>();

if(todoTaskUrl.contains(seedUrl)){
    return false;
}
todoTaskUrlSet.remove(url);


mysql插入数据

maven依赖:
mysql-connector-java   5.1.40

批量插入数据:
PreparedStatement ps = conn.prepareStatement(sql);
ps.addBatch();
for(xxx:xxx){
    ps.set...
    ps.addBatch();
}
ps.executeBatch();




//25  前5页采集     周期采集

一次采集步骤:
1.拿种子
2.交给任务调度层,用于后续的下载分发
3.下载拿到的url,没有则返回空
4.解析下载下来的htmlsource
5.对解析出来的对象进行持久化

3.
String htmlSource = DownLoadManager.download();
while(htmlSource != null){
    4.
    5.
    3.    
}

while(true){
    12345.
    Thread.sleep(10*1000);
}
将定时循环次数放在配置文件里面


增量采集:

//用于保存已采集过的url的任务集合donwTaskSet
public static Set<String> doneTaskSet = new HashSet<String>();

在持久化的时候
//filed:01 (不建议)
for(xxx:xxx){
    //加入到已采集任务集合当中
}
//filed:02 (这种方式更符合业务逻辑)
//在5.步的时候
DataPersistenceManager.persist(resultEntityList);
//将已入库完成的entity数据,加入到已采集数据的set当中,用于判断是否已采集过数据,最终实现增量采集
ScheduleManager.addUrlToDoneTaskSet(resultEntityList);
htmlSource = DownLoadManager.download();

public static void addUrlToDoneTaskSet(List<ParserResultEntity> resultEntityList){
    for(ParserResultEntity entity:resultEntityList){
        addUrlToDoneTaskSet(entity.getSourceUrl());
    }
}


//在4.步到5.步时判断是否需要添加重复的数据持久化
3种方法判断  在4上,在5上,在4~5之间判断(优)
4.
//加入增量采集的判断
boolean isFindRepeatData = false;
List<ParserResultEntity> resultEntityListFinal = new ArrayList<ParserResultEntity>();
for(ParserResultEntity entity:resultEntityList){
        if(ScheduleManager.isHaveDone(entity.getSourceUrl)){
            isFindRepeatData = true;
            break;
        }
        ParserResultEntityFinal.add(entity);
}
//scheduleManager.java
public static boolean isHaveDone(String url){
    return doneTaskSet.contains(url);
}
5.
DataPersistenceManager.persist(resultEntityListFinal);
ScheduleManager.addUrlToDoneTaskSet(resultEntityList);
//循环下载,直到不存在待采集任务
if(isFindRepeatData){
    ScheduleManager.clearToDoTaskList();
    sout("发现重复");
    break;
}
htmlSource = DownLoadManager.download();

//ScheduleManager.java
public static void clearToDoTaskList(){
    todoTaskUrlSet.clear();
    todoTaskUrlList.clear();
}


log4j

reg:介绍
https://www.cnblogs.com/franson-2016/p/5640427.html


log4j maven

修改log4j.properties.    一般maven文件都放在resources下
要自己新建    UTF-8

log4j.rootLogger = DEBUG,stdout,file    
//这里不写info,表示DEBUG级以上的信息全部显示出来

.File = 路径
.MaxFileSize = 5MB   每隔多少M写一个新的文件

TestLog4j{
    public static Logger logger = Logger.getLogger(TestLog4j.class);
    psvm(){
        logger.info("123"); 
    }
}

将其放入爬虫:
manager
    StatisticManager();

public class StaticManager{
    public static Logger logger=Logger.getLogger(StatisticManager.class);
    public static void logStatistic(){
        logger.info(SchedulaManager.xxxx);
    }
}
-------------本文结束期待您的评论-------------