在这个地方我们将对spider来进行一点源码的查看!
spider 因为呢,不想其他的几个部件一样,这个部件拥有很高的利用率,因为他才是整个爬虫的内部核心管理器,他拥有这其他几个部件不可替代的作痛,所以他是一个单独的类,在core核心jar包中,放再了根目录下面!
在这里呢,因为内部东西比较多且杂,所以呢,我就只挑一些,关键的地方 做一下解释!
protected Downloaderdownloader; //download
protected List pipelines =new ArrayList(); //业务需求不同数据出口也是不同的,有的呢,所以用list来装也是很合理的
protected PageProcessorpage Processor;//页面解析,一个爬虫只能拥有一个页面解析的
protected List startRequests;//当页面开始的时候,我们存放进去的url或者request
protected Site site;//负责整个请求的Site,里面会放一些head的 host 啊,userAagent啊
protected String uuid; // 整个爬虫的编码
protected Scheduler scheduler =new QueueScheduler(); //url 管理器
protected Logger logger = LoggerFactory.getLogger(getClass());//日志打印点
protected CountableThreadPoolthreadPool;//线程池
protected ExecutorService executorService;//逻辑池
protected int threadNum =1;//当不写是默认为1 的线程爬虫线程设计处
protected AtomicInteger stat =new AtomicInteger(STAT_INIT);
protected boolean exitWhenComplete =true;//爬虫是否结束,也就是说url是否完成
protected final static int STAT_INIT =0;//爬虫运行状态 未运行
protected final static int STAT_RUNNING =1;//爬虫运行状态 正在运行
protected final static int STAT_STOPPED =2;// 爬虫运行状态 停止运行
protected boolean spawnUrl =true;//是否生成网址
protected boolean destroyWhenExit =true;//爬虫进行悬挂,默认是否,
private ReentrantLock newUrlLock =new ReentrantLock();//重入锁(一种递归无阻塞同步机制)
private Condition newUrlCondition =new UrlLock.newCondition();//条件
private List spiderListeners;//爬虫监听器,因为我们放置的是多个url,每个监听器监听一个url,很合理
private final AtomicLong pageCount =new AtomicLong(0);//初始化提供原子操作
private Date startTime;//开始时间
private int emptySleepTime =30000;//空闲时,睡眠时间,当爬虫进行悬挂之后,这个时间便是你检查有没有url 的依据
以上呢,就是spider 里面额一些参数的详细解释了。 另外一些我太不清楚的地方,希望能给我留言。
接下来呢,我们就查看spider 里面额一些重要的方法,在这里呢,我记不复制源码图片了,只写方法名称。
public static Spidercreate(PageProcessor pageProcessor) {
return new Spider(pageProcessor);
}//进行页面解析类的添加
//还有一种办法就是 构造方法添加,也是可以的
public SpidersetUUID(String uuid) {
this.uuid = uuid;
return this;
}// 传入爬虫的uuid 也就是他的唯一标识
public SpideraddPipeline(Pipeline pipeline) {
checkIfRunning();
this.pipelines.add(pipeline);
return this;
} //这里呢,就是数据管道的添加设置了,当然了,是可以设置多个,你一边把数据存成文件,一遍把数据扔进数据库,这都是阔以的! 也支持 list 大规模传入 用的是 setpipeline方法
public Spiderdownloader(Downloader downloader) {
return setDownloader(downloader);
}//download 的传入方法
private void addRequest(Request request) {
if (site.getDomain() ==null && request !=null && request.getUrl() !=null) {
site.setDomain(UrlUtils.getDomain(request.getUrl()));
}
scheduler.push(request, this);
}//每个url 都会被spider 封装成request的,当然也支持直接传入request了,这里就是了
public Spider addUrl(String... urls) {
for (String url : urls) {
addRequest(new Request(url));
}
signalNewUrl(); return this;
}// 当然传入url也是不会出错的
比较重要的方法说完了,接下来就是重头戏了啊,请看大屏幕
在webmagic 中呢,启动爬虫的方法一共有2个,一个叫做run,一个叫做start,不过呢,rstart方法,启动的是runAsync 方法,所以呢,我们就不对runAsync 方法做更多的解释了!
@Override
public void run() {
checkRunningStat();
initComponent();
logger.info("Spider {} started!",getUUID());
while (!Thread.currentThread().isInterrupted() &&stat.get() ==STAT_RUNNING) {
final Request request =scheduler.poll(this);
if (request ==null) {
if (threadPool.getThreadAlive() ==0 &&exitWhenComplete) {
break;
}
// wait until new url added
waitNewUrl();
}else {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
processRequest(request);
onSuccess(request);
}catch (Exception e) {
onError(request);
logger.error("process request " +request +" error", e);
}finally {
pageCount.incrementAndGet();
signalNewUrl();
}
}
});
}
}
stat.set(STAT_STOPPED);
// release some resources
if (destroyWhenExit) {
close();
}
logger.info("Spider {} closed! {} pages downloaded.", getUUID(), pageCount.get());
}
不用说了,是不是啊,run方法呢,跟start方法,最根本的区别就在于,一个是阻塞式启动,一个是非阻塞式启动了!
具体情况呢,就是run 是阻塞式启动,start 是非阻塞是穷了!
具体情况呢,就是run 是阻塞式启动,start 是非阻塞是穷了!
具体情况呢,就是run 是阻塞式启动,start 是非阻塞是穷了!
重要的话说三遍!
如果有什么疑问,请直接咨询我!
https://blog.csdn.net/qq_36783371 一个大佬写的博客,欢迎去砸鸡蛋!