本文主要介绍下爬虫架构部分。
本人渣渣,初学或者到现在有时候为了偷懒,不喜欢用框架。
初设想
单机模式
1 深度问题 通过 主页 -列表页 -详情页 -
2 多线程问题 基本只在详情页 去做线程管理
3 在想要那层做数据持久化操作
遇到问题
1 重复url 处理 通过数据库去去重 效率低。
2 线程池管理混乱异常处理。
3 没有可扩展性,比如多一层代码就要多加一层。
4 失败url 不宜重新爬取。
优点
1 代码简明
2 容易排查异常
3 适用于日常所需
框架介绍
今天我们主要探寻下一款爬虫框架webmagic
初学者很容易理解,可以想成一个循环通过中间process 去处理 downloader 返回request经过处理请求信息page对象
根据你所需要的信息进行数据持久化。
详细可以点击打开链接,请仔细阅读文档,源码解析我们会在后面进行,时间可能会隔得比较久。
实战
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashSet;
import java.util.Set;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.scheduler.PriorityScheduler;
public class Wall implements PageProcessor{
//存储过滤url
public static Set<String> set=new HashSet();
//列表页
public static final String URL_LIST = "by_sub_category\\.php\\?id=226985&name=%E4%B8%9C%E4%BA%AC%E9%A3%9F%E5%B0%B8%E9%AC%BC\\+%E5%A3%81%E7%BA%B8&lang=Chinese&page=\\d+";
//详情页
public static final String URL_POST = "https://wall\\.alphacoders\\.com/big.php\\?i=\\d{6}&lang=Chinese";
//原图
public static final String IMAGE = "https://images3\\.alphacoders\\.com/\\d{3}/\\d{6}\\.png";
private Site site = new Site().me()
.setRetryTimes(3).setTimeOut(5000000).setSleepTime(100)
.addHeader("User-Agent","Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36 Core/1.47.516.400 QQBrowser/9.4.8188.400");
@Override
public void process(Page page) {
//加入列表页
page.addTargetRequests(page.getHtml().links().regex(URL_LIST).all());
if (page.getUrl().regex(URL_LIST).match()) {
//如果是列表页 我们从页面中正则匹配详情页
page.addTargetRequests(page.getHtml().links().regex(URL_POST).all());
} else {
//如果是详情页或者主页(这边代码有问题不应该加上主页),找到对应原图url,本意是打算用image去过滤的。加到set过滤重复url
set.add(page.getHtml().xpath("//div[@style='width:100%;padding:10px;max-width:975px;margin:auto;']/div[@class='row']/div/span/@data-href").toString());
}
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) throws Exception {
Spider.create(new Wall()).addUrl("https://wall.alphacoders.com/by_sub_category.php?id=226985&name=%E4%B8%9C%E4%BA%AC%E9%A3%9F%E5%B0%B8%E9%AC%BC+%E5%A3%81%E7%BA%B8&lang=Chinese").thread(5)
.run();
FileOutputStream fos=new FileOutputStream(new File("E:/DONGJING.txt"));
OutputStreamWriter osw=new OutputStreamWriter(fos, "UTF-8");
BufferedWriter bw=new BufferedWriter(osw);
for(String string : set){
//存储方法
}
//注意关闭的先后顺序,先打开的后关闭,后打开的先关闭
bw.close();
osw.close();
fos.close();
}
}
对照官网写的demo 从wall这个图站去下东京吃货的壁纸。
我还是不习惯pipeline,这几个组件,对于一个入门菜鸟,更关心如何迅速上手。
当初比较简单,都没有问题。
讲下启动过程加入process ,开了5个线程,却使用同步启动方式,线程白写。
由于我自己测试有时候会超时,所以超时时间时间设置的比较长,每个线程做完,休息100ms,失败重试3次。
header 加个UA表示浏览器。
最后有个致命问题,为了过滤我选择加入set。如果url过多很可能内存溢出。
真不如直接直接处理掉,以后也不会这么写,可能会重复。
所以整个程序要解决的是批量过滤数据持久化。
欢迎加群313557283(刚创建),小白互相学习~